2002-03-06 21:10:08 +00:00
|
|
|
/*
|
|
|
|
* Hamlib CI-V backend - OptoScan extensions
|
2004-09-26 08:35:05 +00:00
|
|
|
* Copyright (c) 2000-2004 by Stephane Fillod
|
2002-03-06 21:10:08 +00:00
|
|
|
*
|
2004-10-02 20:18:16 +00:00
|
|
|
* $Id: optoscan.c,v 1.12 2004-10-02 20:18:16 fillods Exp $
|
2002-03-06 21:10:08 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Library General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2003-10-01 19:40:15 +00:00
|
|
|
#include <stdio.h>
|
2002-03-06 21:10:08 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h> /* String function definitions */
|
|
|
|
#include <unistd.h> /* UNIX standard function definitions */
|
|
|
|
#include <math.h>
|
2003-08-17 22:39:07 +00:00
|
|
|
#include <sys/time.h>
|
2002-03-06 21:10:08 +00:00
|
|
|
|
2003-04-07 22:42:11 +00:00
|
|
|
#include "hamlib/rig.h"
|
|
|
|
#include "serial.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "cal.h"
|
|
|
|
#include "token.h"
|
2002-03-06 21:10:08 +00:00
|
|
|
|
|
|
|
#include "icom.h"
|
|
|
|
#include "icom_defs.h"
|
|
|
|
#include "frame.h"
|
2003-05-19 06:57:44 +00:00
|
|
|
#include "optoscan.h"
|
2002-03-06 21:10:08 +00:00
|
|
|
|
|
|
|
|
2003-05-19 06:57:44 +00:00
|
|
|
const struct confparams opto_ext_parms[] = {
|
|
|
|
{ TOK_TAPECNTL, "tapecntl", "Toggle Tape Switch", "Toggles built in tape switch", 0, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_5KHZWIN, "5khzwin", "Toggle 5kHz Search Window", "Toggles 5kHz search window", 0, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_SPEAKER, "speaker", "Toggle speaker audio", "Toggles speaker audio", 0, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_AUDIO, "audio", "Audio present", "Audio present", NULL, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_DTMFPEND, "dtmfpend", "DTMF Digit Pending", "DTMF Digit Pending", NULL, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_DTMFOVRR, "dtmfovrr", "DTMF Buffer Overflow", "DTMF Buffer Overflow", NULL, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_CTCSSACT, "ctcssact", "CTCSS Tone Active", "CTCSS Tone Active", NULL, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ TOK_DCSACT, "dcsact", "DCS Code Active", "DCS Code Active", NULL, RIG_CONF_CHECKBUTTON, {} },
|
|
|
|
{ RIG_CONF_END, NULL, }
|
|
|
|
};
|
|
|
|
|
|
|
|
static int optoscan_get_status_block(RIG *rig, struct optostat *status_block);
|
2003-08-17 22:39:07 +00:00
|
|
|
static int optoscan_send_freq(RIG *rig,pltstate_t *state);
|
|
|
|
static int optoscan_RTS_toggle(RIG *rig);
|
|
|
|
static int optoscan_start_timer(RIG *rig, pltstate_t *state);
|
|
|
|
static int optoscan_wait_timer(RIG *rig, pltstate_t *state);
|
2003-05-19 06:57:44 +00:00
|
|
|
|
2002-03-06 21:10:08 +00:00
|
|
|
/*
|
|
|
|
* optoscan_open
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_open(RIG *rig)
|
|
|
|
{
|
|
|
|
struct icom_priv_data *priv;
|
|
|
|
struct rig_state *rs;
|
2003-08-17 22:39:07 +00:00
|
|
|
pltstate_t *pltstate;
|
2002-03-06 21:10:08 +00:00
|
|
|
unsigned char ackbuf[16];
|
|
|
|
int ack_len, retval;
|
|
|
|
|
|
|
|
rs = &rig->state;
|
|
|
|
priv = (struct icom_priv_data*)rs->priv;
|
|
|
|
|
2003-08-17 22:39:07 +00:00
|
|
|
pltstate = malloc(sizeof(pltstate_t));
|
|
|
|
if (!pltstate) {
|
|
|
|
return -RIG_ENOMEM;
|
|
|
|
}
|
|
|
|
memset(pltstate, 0, sizeof(pltstate_t));
|
|
|
|
priv->pltstate = pltstate;
|
|
|
|
|
2002-03-06 21:10:08 +00:00
|
|
|
/* select REMOTE control */
|
|
|
|
retval = icom_transaction (rig, C_CTL_MISC, S_OPTO_REMOTE,
|
|
|
|
NULL, 0, ackbuf, &ack_len);
|
2003-08-17 22:39:07 +00:00
|
|
|
if (retval != RIG_OK) {
|
|
|
|
free(pltstate);
|
|
|
|
return retval;
|
|
|
|
}
|
2002-03-06 21:10:08 +00:00
|
|
|
|
|
|
|
if (ack_len != 1 || ackbuf[0] != ACK) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_open: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", ackbuf[0], ack_len);
|
2003-08-17 22:39:07 +00:00
|
|
|
free(pltstate);
|
2002-03-06 21:10:08 +00:00
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* optoscan_close
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_close(RIG *rig)
|
|
|
|
{
|
|
|
|
struct icom_priv_data *priv;
|
|
|
|
struct rig_state *rs;
|
|
|
|
unsigned char ackbuf[16];
|
|
|
|
int ack_len, retval;
|
|
|
|
|
|
|
|
rs = &rig->state;
|
|
|
|
priv = (struct icom_priv_data*)rs->priv;
|
|
|
|
|
|
|
|
/* select LOCAL control */
|
|
|
|
retval = icom_transaction (rig, C_CTL_MISC, S_OPTO_LOCAL,
|
|
|
|
NULL, 0, ackbuf, &ack_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (ack_len != 1 || ackbuf[0] != ACK) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_close: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", ackbuf[0], ack_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
2003-08-17 22:39:07 +00:00
|
|
|
free(priv->pltstate);
|
|
|
|
|
2002-03-06 21:10:08 +00:00
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* optoscan_get_info
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
const char* optoscan_get_info(RIG *rig)
|
|
|
|
{
|
|
|
|
struct icom_priv_data *priv;
|
|
|
|
struct rig_state *rs;
|
|
|
|
unsigned char ackbuf[16];
|
|
|
|
int ack_len, retval;
|
|
|
|
static char info[64];
|
|
|
|
|
|
|
|
rs = &rig->state;
|
|
|
|
priv = (struct icom_priv_data*)rs->priv;
|
|
|
|
|
|
|
|
/* select LOCAL control */
|
|
|
|
retval = icom_transaction (rig, C_CTL_MISC, S_OPTO_RDID,
|
|
|
|
NULL, 0, ackbuf, &ack_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ack_len != 7) {
|
2002-03-07 22:58:47 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_info: ack NG (%#.2x), "
|
2002-03-06 21:10:08 +00:00
|
|
|
"len=%d\n", ackbuf[0], ack_len);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(info, "OptoScan%c%c%c, software version %d.%d, "
|
|
|
|
"interface version %d.%d\n",
|
|
|
|
ackbuf[2], ackbuf[3], ackbuf[4],
|
|
|
|
ackbuf[5] >> 4, ackbuf[5] & 0xf,
|
|
|
|
ackbuf[6] >> 4, ackbuf[6] & 0xf);
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2003-04-09 06:37:37 +00:00
|
|
|
/*
|
|
|
|
* optoscan_get_ctcss_tone
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_get_ctcss_tone(RIG *rig, vfo_t vfo, tone_t *tone)
|
|
|
|
{
|
|
|
|
const struct rig_caps *caps;
|
|
|
|
unsigned char tonebuf[MAXFRAMELEN];
|
|
|
|
int tone_len, retval;
|
|
|
|
|
|
|
|
caps = rig->caps;
|
|
|
|
|
|
|
|
retval = icom_transaction(rig, C_CTL_MISC, S_OPTO_RDCTCSS, NULL, 0,
|
|
|
|
tonebuf, &tone_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (tone_len != 4) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_ctcss_tone: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", tonebuf[0], tone_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
tone_len -= 2;
|
2002-03-06 21:10:08 +00:00
|
|
|
|
2003-04-09 06:37:37 +00:00
|
|
|
*tone = from_bcd_be(tonebuf+2, tone_len*2);
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_ctcss_tone: *tone=%d\n",*tone);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* optoscan_get_dcs_code
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_get_dcs_code(RIG * rig, vfo_t vfo, tone_t *code)
|
|
|
|
{
|
|
|
|
const struct rig_caps *caps;
|
|
|
|
unsigned char tonebuf[MAXFRAMELEN];
|
|
|
|
int tone_len, retval;
|
|
|
|
|
|
|
|
caps = rig->caps;
|
|
|
|
|
|
|
|
retval = icom_transaction(rig, C_CTL_MISC, S_OPTO_RDDCS, NULL, 0,
|
|
|
|
tonebuf, &tone_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (tone_len != 4) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_dcs_code: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", tonebuf[0], tone_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
tone_len -= 2;
|
|
|
|
|
|
|
|
*code = from_bcd_be(tonebuf+2, tone_len*2);
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_dcs_code: *code=%d\n",*code);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int optoscan_recv_dtmf(RIG *rig, vfo_t vfo, char *digits, int *length)
|
|
|
|
{
|
|
|
|
const struct rig_caps *caps;
|
|
|
|
unsigned char dtmfbuf[MAXFRAMELEN],digit;
|
|
|
|
int len, retval, digitpos;
|
2003-04-09 06:43:54 +00:00
|
|
|
unsigned char xlate[] = {'0','1','2','3','4','5','6',
|
|
|
|
'7','8','9','A','B','C','D',
|
|
|
|
'*','#'};
|
2003-04-09 06:37:37 +00:00
|
|
|
caps = rig->caps;
|
|
|
|
digitpos=0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
retval = icom_transaction(rig, C_CTL_MISC, S_OPTO_RDDTMF,
|
|
|
|
NULL,0,dtmfbuf, &len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (len != 3) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_recv_dtmf: ack NG (%#.2x), len=%d\n", dtmfbuf[0], len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
digit = dtmfbuf[2];
|
|
|
|
|
|
|
|
if( digit < 0x16 )
|
|
|
|
{
|
|
|
|
digits[digitpos] = xlate[digit];
|
|
|
|
digitpos++;
|
|
|
|
}
|
|
|
|
} while( (digit != 0x99) && (digitpos < *length) );
|
|
|
|
|
|
|
|
*length = digitpos;
|
|
|
|
digits[digitpos]=0;
|
|
|
|
|
|
|
|
if(*length > 0)
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_recv_dtmf: %d digits - %s\n",*length,digits);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_recv_dtmf: no digits to read.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
2003-05-19 06:57:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_set_ext_parm(RIG *rig, token_t token, value_t val)
|
|
|
|
{
|
|
|
|
unsigned char epbuf[MAXFRAMELEN], ackbuf[MAXFRAMELEN];
|
|
|
|
int ack_len, val_len;
|
|
|
|
int retval,subcode;
|
|
|
|
|
|
|
|
memset(epbuf,0,MAXFRAMELEN);
|
|
|
|
memset(ackbuf,0,MAXFRAMELEN);
|
|
|
|
|
|
|
|
val_len = 1;
|
|
|
|
|
|
|
|
switch(token) {
|
|
|
|
case TOK_TAPECNTL:
|
|
|
|
if( val.i == 0 ) {
|
|
|
|
subcode = S_OPTO_TAPE_OFF;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
subcode = S_OPTO_TAPE_ON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TOK_5KHZWIN:
|
|
|
|
if( val.i == 0 ) {
|
|
|
|
subcode = S_OPTO_5KSCOFF;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
subcode = S_OPTO_5KSCON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TOK_SPEAKER:
|
|
|
|
if( val.i == 0 ) {
|
|
|
|
subcode = S_OPTO_SPKROFF;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
subcode = S_OPTO_SPKRON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = icom_transaction (rig, C_CTL_MISC, subcode, epbuf, 0,
|
|
|
|
ackbuf, &ack_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (ack_len != 1 || ackbuf[0] != ACK) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", __FUNCTION__, ackbuf[0], ack_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
* and val points to a buffer big enough to hold the conf value.
|
|
|
|
*/
|
|
|
|
int optoscan_get_ext_parm(RIG *rig, token_t token, value_t *val)
|
|
|
|
{
|
|
|
|
struct optostat status_block;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
retval = optoscan_get_status_block(rig,&status_block);
|
|
|
|
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
switch(token) {
|
|
|
|
case TOK_TAPECNTL:
|
|
|
|
val->i = status_block.tape_enabled;
|
|
|
|
break;
|
|
|
|
case TOK_5KHZWIN:
|
|
|
|
val->i = status_block.fivekhz_enabled;
|
|
|
|
break;
|
|
|
|
case TOK_SPEAKER:
|
|
|
|
val->i = status_block.speaker_enabled;
|
|
|
|
break;
|
|
|
|
case TOK_AUDIO:
|
|
|
|
val->i = status_block.audio_present;
|
|
|
|
break;
|
|
|
|
case TOK_DTMFPEND:
|
|
|
|
val->i = status_block.DTMF_pending;
|
|
|
|
break;
|
|
|
|
case TOK_DTMFOVRR:
|
|
|
|
val->i = status_block.DTMF_overrun;
|
|
|
|
break;
|
|
|
|
case TOK_CTCSSACT:
|
|
|
|
val->i = status_block.CTCSS_active;
|
|
|
|
break;
|
|
|
|
case TOK_DCSACT:
|
|
|
|
val->i = status_block.DCS_active;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -RIG_ENIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* optoscan_set_level
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
|
|
|
|
{
|
|
|
|
struct icom_priv_data *priv;
|
|
|
|
struct rig_state *rs;
|
|
|
|
unsigned char lvlbuf[MAXFRAMELEN], ackbuf[MAXFRAMELEN];
|
|
|
|
int ack_len;
|
|
|
|
int lvl_cn, lvl_sc; /* Command Number, Subcommand */
|
|
|
|
int icom_val;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
rs = &rig->state;
|
|
|
|
priv = (struct icom_priv_data*)rs->priv;
|
|
|
|
|
|
|
|
memset(lvlbuf,0,MAXFRAMELEN);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* So far, levels of float type are in [0.0..1.0] range
|
|
|
|
*/
|
|
|
|
if (RIG_LEVEL_IS_FLOAT(level))
|
|
|
|
icom_val = val.f * 255;
|
|
|
|
else
|
|
|
|
icom_val = val.i;
|
|
|
|
|
|
|
|
switch (level) {
|
|
|
|
case RIG_LEVEL_AF:
|
|
|
|
lvl_cn = C_CTL_MISC;
|
|
|
|
if( icom_val == 0 ) {
|
|
|
|
lvl_sc = S_OPTO_SPKROFF;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lvl_sc = S_OPTO_SPKRON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"Unsupported set_level %d", level);
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = icom_transaction (rig, lvl_cn, lvl_sc, lvlbuf, 0,
|
|
|
|
ackbuf, &ack_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
if (ack_len != 1 || ackbuf[0] != ACK) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_set_level: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", ackbuf[0], ack_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* optoscan_get_level
|
|
|
|
* Assumes rig!=NULL, rig->state.priv!=NULL, val!=NULL
|
|
|
|
*/
|
|
|
|
int optoscan_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
|
|
|
|
{
|
|
|
|
struct optostat status_block;
|
|
|
|
struct icom_priv_data *priv;
|
|
|
|
struct rig_state *rs;
|
|
|
|
unsigned char lvlbuf[MAXFRAMELEN];
|
|
|
|
int lvl_len;
|
|
|
|
int lvl_cn, lvl_sc; /* Command Number, Subcommand */
|
|
|
|
int icom_val;
|
|
|
|
int cmdhead;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
rs = &rig->state;
|
|
|
|
priv = (struct icom_priv_data*)rs->priv;
|
|
|
|
|
|
|
|
if( level != RIG_LEVEL_AF )
|
|
|
|
{
|
|
|
|
switch (level) {
|
2003-11-16 17:14:44 +00:00
|
|
|
case RIG_LEVEL_RAWSTR:
|
2003-05-19 06:57:44 +00:00
|
|
|
lvl_cn = C_RD_SQSM;
|
|
|
|
lvl_sc = S_SML;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"Unsupported get_level %d", level);
|
|
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = icom_transaction (rig, lvl_cn, lvl_sc, NULL, 0,
|
|
|
|
lvlbuf, &lvl_len);
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* strbuf should contain Cn,Sc,Data area
|
|
|
|
*/
|
|
|
|
cmdhead = (lvl_sc == -1) ? 1:2;
|
|
|
|
lvl_len -= cmdhead;
|
|
|
|
|
|
|
|
if (lvlbuf[0] != ACK && lvlbuf[0] != lvl_cn) {
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_level: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", lvlbuf[0],lvl_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The result is a 3 digit BCD, but in *big endian* order: 0000..0255
|
|
|
|
* (from_bcd is little endian)
|
|
|
|
*/
|
|
|
|
icom_val = from_bcd_be(lvlbuf+cmdhead, lvl_len*2);
|
|
|
|
}
|
|
|
|
else /* level == RIG_LEVEL_AF */
|
|
|
|
{
|
|
|
|
retval = optoscan_get_status_block(rig,&status_block);
|
|
|
|
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
icom_val = 0;
|
|
|
|
if( status_block.speaker_enabled == 1 )
|
|
|
|
icom_val = 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (level) {
|
2003-11-16 17:14:44 +00:00
|
|
|
case RIG_LEVEL_RAWSTR:
|
|
|
|
val->i = icom_val;
|
2003-05-19 06:57:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (RIG_LEVEL_IS_FLOAT(level))
|
|
|
|
val->f = (float)icom_val/255;
|
|
|
|
else
|
|
|
|
val->i = icom_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_TRACE,"optoscan_get_level: %d %d %d %f\n", lvl_len,
|
|
|
|
icom_val, val->i, val->f);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
2003-08-17 22:39:07 +00:00
|
|
|
/* OS456 Pipeline tuning algorithm:
|
|
|
|
* Step 2: Send the next frequency and mode to the receiver using the
|
|
|
|
* TRANSFER NEXT FREQUENCY/MODE command.
|
|
|
|
*
|
|
|
|
* Step 3: Change the state of the RTS interface signal to cause the
|
|
|
|
* next frequency and mode to become the current frequency and
|
|
|
|
* mode, and the receiver to begin settling.
|
|
|
|
*
|
|
|
|
* Step 4: While the receiver is still settling on the current
|
|
|
|
* frequency and mode, send the next frequency and mode to the
|
|
|
|
* receiver using the TRANSFER NEXT FREQUENCY/MODE command.
|
|
|
|
*
|
|
|
|
* Step 5: Wait for the receiver to finish settling. The total
|
|
|
|
* settling time, including sending the next frequency and
|
|
|
|
* mode, is 20 milliseconds (0.02 seconds).
|
|
|
|
*
|
|
|
|
* Step 6: Check the squelch status by reading the DCD interface
|
|
|
|
* signal. If the squelch is open, scanning is stopped.
|
|
|
|
* Otherwise, scanning continues. Optionally, the status of
|
|
|
|
* the CTCSS/DCS/DTMF decoder can be checked, and the
|
|
|
|
* appropriate action taken.
|
|
|
|
*
|
|
|
|
* Step 7: Continuously repeat steps 3 through 6 above.
|
|
|
|
*/
|
|
|
|
int optoscan_scan(RIG *rig, vfo_t vfo, scan_t scan, int ch)
|
|
|
|
{
|
|
|
|
pltstate_t *state;
|
|
|
|
pltune_cb_t cb;
|
|
|
|
int rc, pin_state;
|
|
|
|
struct rig_state *rs;
|
|
|
|
|
|
|
|
if(scan != RIG_SCAN_PLT)
|
|
|
|
return -RIG_ENAVAIL;
|
|
|
|
|
|
|
|
rs=&rig->state;
|
|
|
|
cb = rig->callbacks.pltune;
|
|
|
|
state = ((struct icom_priv_data*)rs->priv)->pltstate;
|
|
|
|
|
|
|
|
if(state==NULL)
|
|
|
|
return -RIG_EINTERNAL;
|
|
|
|
|
|
|
|
if(state->freq==0) /* pltstate_t is not initialized - perform setup */
|
|
|
|
{
|
|
|
|
/* time for CIV command to be sent. this is subtracted from */
|
|
|
|
/* rcvr settle time */
|
|
|
|
state->usleep_time = (1000000 / (rig->state.rigport.parm.serial.rate))
|
|
|
|
* 13 * 9;
|
|
|
|
|
|
|
|
rc=cb(rig,vfo,&(state->next_freq),&(state->next_mode),
|
|
|
|
&(state->next_width),rig->callbacks.pltune_arg);
|
|
|
|
if(rc==RIG_SCAN_STOP)
|
|
|
|
return RIG_OK; /* callback halted loop */
|
|
|
|
|
|
|
|
/* Step 1 is implicit, since hamlib does this when it opens the device */
|
|
|
|
optoscan_send_freq(rig,state); /*Step 2*/
|
|
|
|
}
|
|
|
|
|
|
|
|
rc=!RIG_SCAN_STOP;
|
|
|
|
while(rc!=RIG_SCAN_STOP)
|
|
|
|
{
|
|
|
|
optoscan_RTS_toggle(rig); /*Step 3*/
|
|
|
|
|
|
|
|
state->freq = state->next_freq;
|
|
|
|
state->mode = state->next_mode;
|
|
|
|
|
|
|
|
optoscan_start_timer(rig,state);
|
|
|
|
|
|
|
|
rc=cb(rig,vfo,&(state->next_freq),&(state->next_mode),
|
|
|
|
&(state->next_width),rig->callbacks.pltune_arg);
|
|
|
|
if(rc!=RIG_SCAN_STOP)
|
|
|
|
{
|
|
|
|
optoscan_send_freq(rig,state); /*Step 4*/
|
|
|
|
}
|
|
|
|
|
|
|
|
optoscan_wait_timer(rig,state); /*Step 5*/
|
|
|
|
|
2004-10-02 20:18:16 +00:00
|
|
|
ser_get_car(&rs->rigport,&pin_state);
|
2003-08-17 22:39:07 +00:00
|
|
|
if( pin_state ) /*Step 6*/
|
|
|
|
{
|
|
|
|
return RIG_OK; /* we've broken squelch - return(). caller can */
|
|
|
|
/* get current freq & mode out of state str */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-07 18:30:28 +00:00
|
|
|
/* exiting pipeline loop - force state init on next call */
|
|
|
|
state->freq=0;
|
|
|
|
|
2003-08-17 22:39:07 +00:00
|
|
|
return RIG_OK;
|
|
|
|
}
|
2003-05-19 06:57:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Assumes rig!=NULL, status_block !=NULL
|
|
|
|
*/
|
|
|
|
static int optoscan_get_status_block(RIG *rig, struct optostat *status_block)
|
|
|
|
{
|
2003-09-07 18:30:28 +00:00
|
|
|
int retval, ack_len, expected_len;
|
2003-05-19 06:57:44 +00:00
|
|
|
unsigned char ackbuf[MAXFRAMELEN];
|
|
|
|
|
|
|
|
memset(status_block,0,sizeof(struct optostat));
|
|
|
|
|
|
|
|
retval = icom_transaction (rig, C_CTL_MISC, S_OPTO_RDSTAT, NULL, 0,
|
|
|
|
ackbuf, &ack_len);
|
|
|
|
|
|
|
|
if (retval != RIG_OK)
|
|
|
|
return retval;
|
|
|
|
|
2003-09-07 18:30:28 +00:00
|
|
|
switch( rig->caps->rig_model )
|
|
|
|
{
|
|
|
|
case RIG_MODEL_OS456:
|
|
|
|
expected_len=4;
|
|
|
|
break;
|
|
|
|
case RIG_MODEL_OS535:
|
|
|
|
expected_len=5;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_status_block: unknown rig model");
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ack_len != expected_len ) {
|
2003-05-19 06:57:44 +00:00
|
|
|
rig_debug(RIG_DEBUG_ERR,"optoscan_get_status_block: ack NG (%#.2x), "
|
|
|
|
"len=%d\n", ackbuf[0], ack_len);
|
|
|
|
return -RIG_ERJCTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ackbuf[2] & 1 ) status_block->remote_control = 1;
|
|
|
|
if( ackbuf[2] & 2 ) status_block->DTMF_pending = 1;
|
|
|
|
if( ackbuf[2] & 4 ) status_block->DTMF_overrun = 1;
|
|
|
|
if( ackbuf[2] & 16 ) status_block->squelch_open = 1;
|
|
|
|
if( ackbuf[2] & 32 ) status_block->CTCSS_active = 1;
|
|
|
|
if( ackbuf[2] & 64 ) status_block->DCS_active = 1;
|
|
|
|
|
|
|
|
if( ackbuf[3] & 1 ) status_block->tape_enabled = 1;
|
|
|
|
if( ackbuf[3] & 2 ) status_block->speaker_enabled = 1;
|
|
|
|
if( ackbuf[3] & 4 ) status_block->fivekhz_enabled = 1;
|
|
|
|
if( ackbuf[3] & 16 ) status_block->audio_present = 1;
|
|
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"remote_control = %d\n",status_block->remote_control);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"DTMF_pending = %d\n",status_block->DTMF_pending);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"DTMF_overrun = %d\n",status_block->DTMF_overrun);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"squelch_open = %d\n",status_block->squelch_open);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"CTCSS_active = %d\n",status_block->CTCSS_active);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"DCS_active = %d\n",status_block->DCS_active);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"tape_enabled = %d\n",status_block->tape_enabled );
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"speaker_enabled = %d\n",status_block->speaker_enabled);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"fivekhz_enabled = %d\n",status_block->fivekhz_enabled);
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE,"audio_present = %d\n",status_block->audio_present);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
2003-08-17 22:39:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int optoscan_send_freq(RIG *rig,pltstate_t *state)
|
|
|
|
{
|
|
|
|
unsigned char buff[OPTO_BUFF_SIZE];
|
|
|
|
struct icom_priv_data *priv;
|
|
|
|
struct rig_state *rs;
|
|
|
|
const port_t *port;
|
2003-09-07 18:30:28 +00:00
|
|
|
int fd;
|
2003-08-17 22:39:07 +00:00
|
|
|
char md,pd;
|
|
|
|
freq_t freq;
|
|
|
|
rmode_t mode;
|
|
|
|
|
|
|
|
port = &(rig->state.rigport);
|
|
|
|
fd = port->fd;
|
|
|
|
rs = &rig->state;
|
|
|
|
priv = (struct icom_priv_data*)rs->priv;
|
|
|
|
freq=state->next_freq;
|
|
|
|
mode=state->next_mode;
|
|
|
|
|
|
|
|
memset(buff,0,OPTO_BUFF_SIZE);
|
|
|
|
|
|
|
|
to_bcd(buff,freq,5*2); /* to_bcd requires nibble len */
|
|
|
|
|
|
|
|
rig2icom_mode(rig,mode,0,&md,&pd);
|
|
|
|
buff[5]=md;
|
|
|
|
|
|
|
|
/* read echo'd chars only...there will be no ACK from this command
|
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* It may have waited fro pltstate->usleep_time before reading the echo'd
|
|
|
|
* chars, but the read will be blocking anyway. --SF
|
|
|
|
* */
|
|
|
|
return icom_transaction (rig, C_CTL_MISC, S_OPTO_NXT, buff, 6, NULL, NULL);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int optoscan_RTS_toggle(RIG *rig)
|
|
|
|
{
|
|
|
|
struct rig_state *rs;
|
|
|
|
int state=0;
|
|
|
|
|
|
|
|
rs=&rig->state;
|
|
|
|
ser_get_rts(&rs->rigport,&state);
|
|
|
|
ser_set_rts(&rs->rigport,!state);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int optoscan_start_timer(RIG *rig, pltstate_t *state)
|
|
|
|
{
|
|
|
|
gettimeofday(&(state->timer_start),NULL);
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int optoscan_wait_timer(RIG *rig, pltstate_t *state)
|
|
|
|
{
|
|
|
|
struct icom_priv_caps *priv_caps;
|
|
|
|
int usec_diff;
|
|
|
|
int settle_usec;
|
|
|
|
|
|
|
|
priv_caps = (struct icom_priv_caps *)rig->caps->priv;
|
|
|
|
settle_usec = priv_caps->settle_time * 1000; /*convert settle time (ms) to */
|
|
|
|
/* settle time (usec) */
|
|
|
|
|
|
|
|
gettimeofday(&(state->timer_current),NULL);
|
|
|
|
|
|
|
|
usec_diff = abs( (state->timer_current.tv_usec) -
|
|
|
|
(state->timer_start.tv_usec) );
|
|
|
|
|
|
|
|
if( usec_diff < settle_usec )
|
|
|
|
{
|
|
|
|
usleep( settle_usec - usec_diff ); /* sleep balance of settle_time */
|
|
|
|
}
|
|
|
|
|
|
|
|
return RIG_OK;
|
|
|
|
}
|
|
|
|
|