kopia lustrzana https://github.com/Hamlib/Hamlib
Attempt to handle asynchronously pushed Icom CI-V frames (transceive and spectrum data) as these frame will get interleaved with command responses
rodzic
503897c41c
commit
263c16984a
|
@ -23,9 +23,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* String function definitions */
|
||||
#include <unistd.h> /* UNIX standard function definitions */
|
||||
|
||||
#include "hamlib/rig.h"
|
||||
#include "serial.h"
|
||||
|
@ -90,6 +88,26 @@ int make_cmd_frame(char frame[], char re_id, char ctrl_id, char cmd, int subcmd,
|
|||
RETURNFUNC(i);
|
||||
}
|
||||
|
||||
int icom_frame_fix_preamble(int frame_len, unsigned char *frame)
|
||||
{
|
||||
if (frame[0] == PR)
|
||||
{
|
||||
// Sometimes the second preamble byte is missing -> TODO: Find out why!
|
||||
if (frame[1] != PR)
|
||||
{
|
||||
memmove(frame + 1, frame, frame_len);
|
||||
frame_len++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rig_debug(RIG_DEBUG_WARN, "%s: invalid Icom CI-V frame, no preamble found\n", __func__);
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
return frame_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* icom_one_transaction
|
||||
*
|
||||
|
@ -109,11 +127,12 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
|
|||
struct icom_priv_data *priv;
|
||||
const struct icom_priv_caps *priv_caps;
|
||||
struct rig_state *rs;
|
||||
struct timeval start_time, current_time, elapsed_time;
|
||||
// this buf needs to be large enough for 0xfe strings for power up
|
||||
// at 115,200 this is now at least 150
|
||||
unsigned char buf[200];
|
||||
unsigned char sendbuf[MAXFRAMELEN];
|
||||
int frm_len, retval;
|
||||
int frm_len, frm_data_len, retval;
|
||||
int ctrl_id;
|
||||
|
||||
ENTERFUNC;
|
||||
|
@ -168,12 +187,14 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
|
|||
|
||||
if (retval < 0)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
/* Other error, return it */
|
||||
RETURNFUNC(retval);
|
||||
}
|
||||
|
||||
if (retval < 1)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
|
@ -223,6 +244,9 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
|
|||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
gettimeofday(&start_time, NULL);
|
||||
|
||||
read_another_frame:
|
||||
/*
|
||||
* wait for ACK ...
|
||||
* FIXME: handle padding/collisions
|
||||
|
@ -245,10 +269,9 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
|
|||
|
||||
#endif
|
||||
|
||||
Unhold_Decode(rig);
|
||||
|
||||
if (frm_len < 0)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
/* RIG_TIMEOUT: timeout getting response, return timeout */
|
||||
/* other error: return it */
|
||||
RETURNFUNC(frm_len);
|
||||
|
@ -256,12 +279,23 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
|
|||
|
||||
if (frm_len < 1)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
retval = icom_frame_fix_preamble(frm_len, buf);
|
||||
if (retval < 0)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(retval);
|
||||
}
|
||||
|
||||
frm_len = retval;
|
||||
|
||||
switch (buf[frm_len - 1])
|
||||
{
|
||||
case COL:
|
||||
Unhold_Decode(rig);
|
||||
/* Collision */
|
||||
RETURNFUNC(-RIG_BUSBUSY);
|
||||
|
||||
|
@ -270,30 +304,70 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd,
|
|||
break;
|
||||
|
||||
case NAK:
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_ERJCTED);
|
||||
|
||||
default:
|
||||
Unhold_Decode(rig);
|
||||
/* Timeout after reading at least one character */
|
||||
/* Problem on ci-v bus? */
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
if (frm_len < ACKFRMLEN) { RETURNFUNC(-RIG_EPROTO); }
|
||||
if (frm_len < ACKFRMLEN)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
// if we send a bad command we will get back a NAK packet
|
||||
// e.g. fe fe e0 50 fa fd
|
||||
if (frm_len == 6 && NAK == buf[frm_len - 2]) { RETURNFUNC(-RIG_ERJCTED); }
|
||||
if (frm_len == 6 && NAK == buf[frm_len - 2])
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_ERJCTED);
|
||||
}
|
||||
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: frm_len=%d, frm_len-1=%02x, frm_len-2=%02x\n",
|
||||
__func__, frm_len, buf[frm_len - 1], buf[frm_len - 2]);
|
||||
|
||||
// has to be one of these two now or frame is corrupt
|
||||
if (FI != buf[frm_len - 1] && ACK != buf[frm_len - 1]) { RETURNFUNC(-RIG_BUSBUSY); }
|
||||
if (FI != buf[frm_len - 1] && ACK != buf[frm_len - 1])
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_BUSBUSY);
|
||||
}
|
||||
|
||||
*data_len = frm_len - (ACKFRMLEN - 1);
|
||||
frm_data_len = frm_len - (ACKFRMLEN - 1);
|
||||
|
||||
if (*data_len <= 0) { RETURNFUNC(-RIG_EPROTO); }
|
||||
if (frm_data_len <= 0)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
if (icom_is_async_frame(rig, frm_len, buf))
|
||||
{
|
||||
int elapsed_ms;
|
||||
icom_process_async_frame(rig, frm_len, buf);
|
||||
|
||||
gettimeofday(¤t_time, NULL);
|
||||
timersub(¤t_time, &start_time, &elapsed_time);
|
||||
|
||||
elapsed_ms = (int) (elapsed_time.tv_sec * 1000 + elapsed_time.tv_usec / 1000);
|
||||
|
||||
if (elapsed_ms > rs->rigport.timeout)
|
||||
{
|
||||
Unhold_Decode(rig);
|
||||
RETURNFUNC(-RIG_ETIMEOUT);
|
||||
}
|
||||
|
||||
goto read_another_frame;
|
||||
}
|
||||
|
||||
Unhold_Decode(rig);
|
||||
|
||||
*data_len = frm_data_len;
|
||||
memcpy(data, buf + 4, *data_len);
|
||||
|
||||
/*
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* helper functions
|
||||
*/
|
||||
int make_cmd_frame(char frame[], char re_id, char ctrl_id, char cmd, int subcmd, const unsigned char *data, int data_len);
|
||||
int icom_frame_fix_preamble(int frame_len, unsigned char *frame);
|
||||
|
||||
int icom_transaction (RIG *rig, int cmd, int subcmd, const unsigned char *payload, int payload_len, unsigned char *data, int *data_len);
|
||||
int read_icom_frame(hamlib_port_t *p, unsigned char rxbuffer[], int rxbuffer_len);
|
||||
|
|
170
rigs/icom/icom.c
170
rigs/icom/icom.c
|
@ -7933,7 +7933,7 @@ int icom_mW2power(RIG *rig, float *power, unsigned int mwpower, freq_t freq,
|
|||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
static int icom_parse_spectrum_frame(RIG *rig, int length, unsigned char *frame_data)
|
||||
static int icom_parse_spectrum_frame(RIG *rig, int length, const unsigned char *frame_data)
|
||||
{
|
||||
struct rig_caps *caps = rig->caps;
|
||||
struct icom_priv_caps *priv_caps = (struct icom_priv_caps *) caps->priv;
|
||||
|
@ -8059,6 +8059,88 @@ static int icom_parse_spectrum_frame(RIG *rig, int length, unsigned char *frame_
|
|||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
int icom_is_async_frame(RIG *rig, int frame_len, const unsigned char *frame)
|
||||
{
|
||||
struct rig_state *rs = &rig->state;
|
||||
struct icom_priv_data *priv = (struct icom_priv_data *) rs->priv;
|
||||
|
||||
if (frame_len < ACKFRMLEN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Spectrum scope data is not CI-V transceive data, but handled the same way as it is pushed by the rig */
|
||||
return frame[2] == BCASTID || (frame[2] == CTRLID && frame[4] == C_CTL_SCP && frame[5] == S_SCP_DAT);
|
||||
}
|
||||
|
||||
int icom_process_async_frame(RIG *rig, int frame_len, const unsigned char *frame)
|
||||
{
|
||||
struct rig_state *rs = &rig->state;
|
||||
struct icom_priv_data *priv = (struct icom_priv_data *) rs->priv;
|
||||
rmode_t mode;
|
||||
pbwidth_t width;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
/*
|
||||
* the first 2 bytes must be 0xfe
|
||||
* the 3rd one 0x00 since this is transceive mode
|
||||
* the 4rd one the emitter
|
||||
* then the command number
|
||||
* the rest is data
|
||||
* and don't forget one byte at the end for the EOM
|
||||
*/
|
||||
switch (frame[4])
|
||||
{
|
||||
case C_SND_FREQ:
|
||||
/*
|
||||
* TODO: the freq length might be less than 4 or 5 bytes
|
||||
* on older rigs!
|
||||
*/
|
||||
if (rig->callbacks.freq_event)
|
||||
{
|
||||
freq_t freq;
|
||||
freq = from_bcd(frame + 5, (priv->civ_731_mode ? 4 : 5) * 2);
|
||||
RETURNFUNC(rig->callbacks.freq_event(rig, RIG_VFO_CURR, freq,
|
||||
rig->callbacks.freq_arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURNFUNC(-RIG_ENAVAIL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case C_SND_MODE:
|
||||
if (rig->callbacks.mode_event)
|
||||
{
|
||||
icom2rig_mode(rig, frame[5], frame[6], &mode, &width);
|
||||
RETURNFUNC(rig->callbacks.mode_event(rig, RIG_VFO_CURR,
|
||||
mode, width, rig->callbacks.mode_arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURNFUNC(-RIG_ENAVAIL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case C_CTL_SCP:
|
||||
if (frame[5] == S_SCP_DAT)
|
||||
{
|
||||
icom_parse_spectrum_frame(rig, frame_len - (6 + 1), frame + 6);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s: transceive cmd unsupported %#2.2x\n",
|
||||
__func__, frame[4]);
|
||||
RETURNFUNC(-RIG_ENIMPL);
|
||||
}
|
||||
|
||||
RETURNFUNC(RIG_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* icom_decode is called by sa_sigio, when some asynchronous
|
||||
* data has been received from the rig
|
||||
|
@ -8068,9 +8150,7 @@ int icom_decode_event(RIG *rig)
|
|||
struct icom_priv_data *priv;
|
||||
struct rig_state *rs;
|
||||
unsigned char buf[MAXFRAMELEN];
|
||||
int frm_len;
|
||||
rmode_t mode;
|
||||
pbwidth_t width;
|
||||
int retval, frm_len;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
|
@ -8090,21 +8170,14 @@ int icom_decode_event(RIG *rig)
|
|||
RETURNFUNC(0);
|
||||
}
|
||||
|
||||
if (buf[0] == PR)
|
||||
retval = icom_frame_fix_preamble(frm_len, buf);
|
||||
if (retval < 0)
|
||||
{
|
||||
// Sometimes the second preamble byte is missing -> TODO: Find out why!
|
||||
if (buf[1] != PR)
|
||||
{
|
||||
memmove(buf + 1, buf, frm_len);
|
||||
frm_len++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rig_debug(RIG_DEBUG_WARN, "%s: invalid Icom CI-V frame, no preamble found\n", __func__);
|
||||
RETURNFUNC(-RIG_EPROTO);
|
||||
RETURNFUNC(retval);
|
||||
}
|
||||
|
||||
frm_len = retval;
|
||||
|
||||
switch (buf[frm_len - 1])
|
||||
{
|
||||
case COL:
|
||||
|
@ -8122,72 +8195,13 @@ int icom_decode_event(RIG *rig)
|
|||
RETURNFUNC(-RIG_EPROTO);
|
||||
}
|
||||
|
||||
/* Spectrum scope data is not CI-V transceive data, but handled the same way as it is pushed by the rig */
|
||||
if (buf[3] != BCASTID && buf[3] != priv->re_civ_addr && buf[4] != C_CTL_SCP)
|
||||
if (!icom_is_async_frame(rig, frm_len, buf))
|
||||
{
|
||||
rig_debug(RIG_DEBUG_WARN, "%s: CI-V %#x called for %#x!\n", __func__,
|
||||
priv->re_civ_addr, buf[3]);
|
||||
priv->re_civ_addr, buf[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* the first 2 bytes must be 0xfe
|
||||
* the 3rd one the emitter
|
||||
* the 4rd one 0x00 since this is transceive mode
|
||||
* then the command number
|
||||
* the rest is data
|
||||
* and don't forget one byte at the end for the EOM
|
||||
*/
|
||||
switch (buf[4])
|
||||
{
|
||||
case C_SND_FREQ:
|
||||
|
||||
/*
|
||||
* TODO: the freq length might be less than 4 or 5 bytes
|
||||
* on older rigs!
|
||||
*/
|
||||
if (rig->callbacks.freq_event)
|
||||
{
|
||||
freq_t freq;
|
||||
freq = from_bcd(buf + 5, (priv->civ_731_mode ? 4 : 5) * 2);
|
||||
RETURNFUNC(rig->callbacks.freq_event(rig, RIG_VFO_CURR, freq,
|
||||
rig->callbacks.freq_arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURNFUNC(-RIG_ENAVAIL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case C_SND_MODE:
|
||||
if (rig->callbacks.mode_event)
|
||||
{
|
||||
icom2rig_mode(rig, buf[5], buf[6], &mode, &width);
|
||||
RETURNFUNC(rig->callbacks.mode_event(rig, RIG_VFO_CURR,
|
||||
mode, width,
|
||||
rig->callbacks.mode_arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURNFUNC(-RIG_ENAVAIL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case C_CTL_SCP:
|
||||
if (buf[5] == S_SCP_DAT)
|
||||
{
|
||||
icom_parse_spectrum_frame(rig, frm_len - (6 + 1), buf + 6);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s: transceive cmd unsupported %#2.2x\n",
|
||||
__func__, buf[4]);
|
||||
RETURNFUNC(-RIG_ENIMPL);
|
||||
}
|
||||
|
||||
RETURNFUNC(RIG_OK);
|
||||
RETURNFUNC(icom_process_async_frame(rig, frm_len, buf));
|
||||
}
|
||||
|
||||
int icom_set_raw(RIG *rig, int cmd, int subcmd, int subcmdbuflen,
|
||||
|
|
|
@ -387,6 +387,8 @@ int icom_set_custom_parm_time(RIG *rig, int parmbuflen, unsigned char *parmbuf,
|
|||
int icom_get_custom_parm_time(RIG *rig, int parmbuflen, unsigned char *parmbuf,
|
||||
int *seconds);
|
||||
int icom_get_freq_range(RIG *rig);
|
||||
int icom_is_async_frame(RIG *rig, int frame_len, const unsigned char *frame);
|
||||
int icom_process_async_frame(RIG *rig, int frame_len, const unsigned char *frame);
|
||||
|
||||
extern const struct confparams icom_cfg_params[];
|
||||
extern const struct confparams icom_ext_levels[];
|
||||
|
|
|
@ -1904,7 +1904,7 @@ int HAMLIB_API parse_hoststr(char *hoststr, char host[256], char port[6])
|
|||
return -1;
|
||||
}
|
||||
|
||||
#undef RIG_FLUSH_REMOVE
|
||||
#define RIG_FLUSH_REMOVE
|
||||
int HAMLIB_API rig_flush(hamlib_port_t *port)
|
||||
{
|
||||
#ifndef RIG_FLUSH_REMOVE
|
||||
|
|
Ładowanie…
Reference in New Issue