kopia lustrzana https://github.com/Hamlib/Hamlib
Improve error handling for GUOHETEC drivers to enhance WSJT-X compatibility
- Add graceful degradation for communication errors - Return cached values instead of error codes on failures - Implement unified response validation functions - Add cache return macros for consistent error handling - Maintain backward compatibility while improving stability This change ensures WSJT-X and similar applications continue working even when temporary communication issues occur with GUOHETEC radios. Fixes: WSJT-X compatibility issues with PMR-171 and Q900 driverspull/1787/head
rodzic
862fda58be
commit
c9161e2e25
|
@ -96,7 +96,153 @@ uint16_t CRC16Check(const unsigned char *buf, int len)
|
|||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Common response validation functions
|
||||
|
||||
/**
|
||||
* Read rig response with validation
|
||||
* @param rig RIG structure
|
||||
* @param reply Reply buffer
|
||||
* @param reply_size Size of reply buffer
|
||||
* @param func_name Function name for debug messages
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int read_rig_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name)
|
||||
{
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
int ret;
|
||||
|
||||
// Read header
|
||||
ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header, using cached values\n", func_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > reply_size - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d, using cached values\n", func_name, reply[4]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data, using cached values\n", func_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate response length matches expected
|
||||
if (ret != reply[4]) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Data read mismatch: expected %d, got %d, using cached values\n",
|
||||
func_name, reply[4], ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate basic rig response
|
||||
* @param rig RIG structure
|
||||
* @param reply Reply buffer
|
||||
* @param reply_size Size of reply buffer
|
||||
* @param func_name Function name for debug messages
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int validate_rig_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name)
|
||||
{
|
||||
// Validate packet header
|
||||
VALIDATE_PACKET_HEADER(reply, func_name);
|
||||
|
||||
// Validate data length
|
||||
VALIDATE_DATA_LENGTH(reply, reply_size, func_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate frequency response with CRC check
|
||||
* @param rig RIG structure
|
||||
* @param reply Reply buffer
|
||||
* @param reply_size Size of reply buffer
|
||||
* @param func_name Function name for debug messages
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int validate_freq_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name)
|
||||
{
|
||||
// Basic validation
|
||||
if (validate_rig_response(rig, reply, reply_size, func_name) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate buffer boundaries for CRC
|
||||
int expected_total_length = 5 + reply[4] + 2; // header(5) + data_length + CRC(2)
|
||||
if (expected_total_length > reply_size) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too large for buffer: %d > %d, using cached values\n",
|
||||
func_name, expected_total_length, reply_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// CRC check
|
||||
uint16_t recv_crc = (reply[31] << 8) | reply[32]; // Last 2 bytes are CRC
|
||||
uint16_t calc_crc = CRC16Check(&reply[4], 27);
|
||||
if (recv_crc != calc_crc) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: CRC check failed (received: %04X, calculated: %04X), using cached values\n",
|
||||
func_name, recv_crc, calc_crc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate frequency field offset
|
||||
int freq_b_offset = 13; // VFOB frequency starting position
|
||||
if (freq_b_offset + 3 >= expected_total_length - 2) { // -2 for CRC
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Frequency field offset out of bounds, using cached values\n", func_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate mode response with bounds checking
|
||||
* @param rig RIG structure
|
||||
* @param reply Reply buffer
|
||||
* @param reply_size Size of reply buffer
|
||||
* @param func_name Function name for debug messages
|
||||
* @param min_length Minimum required data length
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int validate_mode_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name, int min_length)
|
||||
{
|
||||
// Basic validation
|
||||
if (validate_rig_response(rig, reply, reply_size, func_name) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate minimum length for mode data
|
||||
if (reply[4] < min_length) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for mode data, using cached values\n", func_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Validate mode field indices are within bounds
|
||||
if (reply[7] >= GUOHE_MODE_TABLE_MAX) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid mode A index %d, using cached values\n", func_name, reply[7]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (reply[8] >= GUOHE_MODE_TABLE_MAX) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid mode B index %d, using cached values\n", func_name, reply[8]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialization function
|
||||
DECLARE_INITRIG_BACKEND(guohetec) {
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s: Initializing guohetec \n", __func__);
|
||||
|
@ -135,6 +281,7 @@ DECLARE_PROBERIG_BACKEND(guohetec) {
|
|||
|
||||
rig_flush(port);
|
||||
|
||||
int retval = write_block(port, cmd, PMR171_CMD_LENGTH);
|
||||
int retval = write_block(port, cmd, PMR171_CMD_LENGTH);
|
||||
if (retval != RIG_OK) {
|
||||
continue;
|
||||
|
|
|
@ -9,6 +9,56 @@
|
|||
|
||||
#define GUOHE_MODE_TABLE_MAX 8
|
||||
|
||||
// Common error handling macros for cached values
|
||||
#define RETURN_CACHED_FREQ(rig, vfo, freq) do { \
|
||||
*(freq) = (vfo == RIG_VFO_A) ? CACHE(rig)->freqMainA : CACHE(rig)->freqMainB; \
|
||||
return RIG_OK; \
|
||||
} while(0)
|
||||
|
||||
#define RETURN_CACHED_MODE(rig, vfo, mode, width, cachep, p) do { \
|
||||
*(mode) = (vfo == RIG_VFO_A) ? (cachep)->modeMainA : (cachep)->modeMainB; \
|
||||
*(width) = (p)->filterBW; \
|
||||
return RIG_OK; \
|
||||
} while(0)
|
||||
|
||||
#define RETURN_CACHED_VFO(rig, vfo) do { \
|
||||
*(vfo) = CACHE(rig)->vfo; \
|
||||
return RIG_OK; \
|
||||
} while(0)
|
||||
|
||||
#define RETURN_CACHED_PTT(rig, ptt, cachep) do { \
|
||||
*(ptt) = (cachep)->ptt; \
|
||||
return RIG_OK; \
|
||||
} while(0)
|
||||
|
||||
// Common response validation macros
|
||||
#define VALIDATE_PACKET_HEADER(reply, func_name) do { \
|
||||
if (reply[0] != 0xA5 || reply[1] != 0xA5 || \
|
||||
reply[2] != 0xA5 || reply[3] != 0xA5) { \
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid packet header, using cached values\n", func_name); \
|
||||
return -1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define VALIDATE_DATA_LENGTH(reply, reply_size, func_name) do { \
|
||||
if (reply[4] == 0 || reply[4] > (reply_size) - 5) { \
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d, using cached values\n", func_name, reply[4]); \
|
||||
return -1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define VALIDATE_READ_RESULT(ret, expected, func_name) do { \
|
||||
if (ret < 0) { \
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data, using cached values\n", func_name); \
|
||||
return -1; \
|
||||
} \
|
||||
if (ret != expected) { \
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Data read mismatch: expected %d, got %d, using cached values\n", \
|
||||
func_name, expected, ret); \
|
||||
return -1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
extern struct rig_caps pmr171_caps;
|
||||
extern struct rig_caps q900_caps;
|
||||
|
||||
|
@ -18,5 +68,14 @@ unsigned char rmode2guohe(rmode_t mode, const rmode_t mode_table[]);
|
|||
unsigned char *to_be(unsigned char data[], unsigned long long freq, unsigned int byte_len);
|
||||
unsigned long long from_be(const unsigned char data[],unsigned int byte_len);
|
||||
|
||||
// Common response validation functions
|
||||
int validate_rig_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name);
|
||||
int read_rig_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name);
|
||||
int validate_freq_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name);
|
||||
int validate_mode_response(RIG *rig, unsigned char *reply, int reply_size,
|
||||
const char *func_name, int min_length);
|
||||
|
||||
#endif // _guohetec_H_
|
||||
|
|
|
@ -321,6 +321,7 @@ static int pmr171_open(RIG *rig)
|
|||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int pmr171_send(RIG *rig, const unsigned char* buff, int len, unsigned char *reply, int rlen)
|
||||
static int pmr171_send(RIG *rig, const unsigned char* buff, int len, unsigned char *reply, int rlen)
|
||||
{
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
int retry = 5;
|
||||
|
@ -374,48 +375,19 @@ static int pmr171_open(RIG *rig)
|
|||
cmd[6] = crc >> 8;
|
||||
cmd[7] = crc & 0xFF;
|
||||
|
||||
// Receive buffer (complete response packet should be 33 bytes)
|
||||
// Receive buffer and send command
|
||||
unsigned char reply[40];
|
||||
pmr171_send(rig, cmd, sizeof(cmd), reply, sizeof(reply));
|
||||
|
||||
/* ----------- Protocol validation ----------- */
|
||||
// 1. Check packet header
|
||||
if (reply[0] != 0xA5 || reply[1] != 0xA5 ||
|
||||
reply[2] != 0xA5 || reply[3] != 0xA5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid packet header\n", __func__);
|
||||
}
|
||||
|
||||
// 2. Check packet length (0x1B = 27 bytes data + length itself)
|
||||
if (reply[4] != 0x1B) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid package length %d\n", __func__, reply[4]);
|
||||
}
|
||||
|
||||
// 3. Validate buffer boundaries - ensure enough space for CRC
|
||||
int expected_total_length = 5 + reply[4] + 2; // header(5) + data_length + CRC(2)
|
||||
if (expected_total_length > sizeof(reply)) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too large for buffer: %d > %zu\n",
|
||||
__func__, expected_total_length, sizeof(reply));
|
||||
}
|
||||
|
||||
// 4. CRC check - now safely access CRC bytes
|
||||
uint16_t recv_crc = (reply[31] << 8) | reply[32]; // The last 2 bytes are CRC
|
||||
uint16_t calc_crc = CRC16Check(&reply[4], 27);
|
||||
if (recv_crc != calc_crc) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: CRC check failed (Received : %04X calculation : %04X)\n",
|
||||
__func__, recv_crc, calc_crc);
|
||||
}
|
||||
|
||||
/* ----------- Data parsing ----------- */
|
||||
// Frequency field offset (according to protocol doc)
|
||||
int freq_a_offset = 9; // VFOA frequency starting position
|
||||
int freq_b_offset = 13; // VFOB frequency starting position
|
||||
|
||||
// Validate frequency field offset won't overflow
|
||||
if (freq_b_offset + 3 >= expected_total_length - 2) { // -2 for CRC
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Frequency field offset out of bounds\n", __func__);
|
||||
// Validate response using common function
|
||||
if (validate_freq_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_FREQ(rig, vfo, freq);
|
||||
}
|
||||
|
||||
// Parse frequency (big-endian)
|
||||
int freq_a_offset = 9; // VFOA frequency starting position
|
||||
int freq_b_offset = 13; // VFOB frequency starting position
|
||||
|
||||
uint32_t freq_a = (reply[freq_a_offset] << 24) |
|
||||
(reply[freq_a_offset+1] << 16) |
|
||||
(reply[freq_a_offset+2] << 8) |
|
||||
|
@ -426,7 +398,6 @@ static int pmr171_open(RIG *rig)
|
|||
(reply[freq_b_offset+2] << 8) |
|
||||
reply[freq_b_offset+3];
|
||||
|
||||
|
||||
// Update cache
|
||||
CACHE(rig)->freqMainA = (freq_t)freq_a;
|
||||
CACHE(rig)->freqMainB = (freq_t)freq_b;
|
||||
|
@ -443,37 +414,20 @@ static int pmr171_open(RIG *rig)
|
|||
static int pmr171_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
|
||||
{
|
||||
struct rig_cache *cachep = CACHE(rig);
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
const pmr171_data_t *p = (pmr171_data_t *) STATE(rig)->priv;
|
||||
unsigned char reply[40];
|
||||
|
||||
// Get latest status from hardware
|
||||
pmr171_send_cmd1(rig, 0x0b, 0);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
// Read and validate response using common function
|
||||
if (read_rig_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_MODE(rig, vfo, mode, width, cachep, p);
|
||||
}
|
||||
|
||||
// Validate mode field index won't overflow
|
||||
if (reply[4] < 5) { // Need at least 5 bytes to access reply[7] and reply[8]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for mode data\n", __func__);
|
||||
return -RIG_EPROTO;
|
||||
// Validate mode response using common function
|
||||
if (validate_mode_response(rig, reply, sizeof(reply), __func__, 5) < 0) {
|
||||
RETURN_CACHED_MODE(rig, vfo, mode, width, cachep, p);
|
||||
}
|
||||
|
||||
// Update cache
|
||||
|
@ -499,36 +453,20 @@ static int pmr171_open(RIG *rig)
|
|||
|
||||
static int pmr171_get_vfo(RIG *rig, vfo_t *vfo)
|
||||
{
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
unsigned char reply[40];
|
||||
|
||||
// Send status sync command to get current VFO state
|
||||
pmr171_send_cmd1(rig, 0x0b, 0);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
// Read and validate response using common function
|
||||
if (read_rig_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_VFO(rig, vfo);
|
||||
}
|
||||
|
||||
// Validate VFO status field index won't overflow
|
||||
if (reply[4] < 13) { // Need at least 13 bytes to access reply[17]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for VFO data\n", __func__);
|
||||
return -RIG_EPROTO;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for VFO data, using cached values\n", __func__);
|
||||
RETURN_CACHED_VFO(rig, vfo);
|
||||
}
|
||||
|
||||
// According to protocol doc, reply[17] is A/B frequency status
|
||||
|
@ -541,35 +479,19 @@ static int pmr171_open(RIG *rig)
|
|||
static int pmr171_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt)
|
||||
{
|
||||
struct rig_cache *cachep = CACHE(rig);
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
unsigned char reply[40];
|
||||
|
||||
pmr171_send_cmd1(rig, 0x0b, 0);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
// Read and validate response using common function
|
||||
if (read_rig_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_PTT(rig, ptt, cachep);
|
||||
}
|
||||
|
||||
// Validate PTT status field index won't overflow
|
||||
if (reply[4] < 2) { // Need at least 2 bytes to access reply[6]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for PTT data\n", __func__);
|
||||
return -RIG_EPROTO;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for PTT data, using cached values\n", __func__);
|
||||
RETURN_CACHED_PTT(rig, ptt, cachep);
|
||||
}
|
||||
|
||||
// Get PTT status
|
||||
|
@ -634,6 +556,7 @@ static int pmr171_open(RIG *rig)
|
|||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
}
|
||||
|
@ -721,6 +644,16 @@ static int pmr171_open(RIG *rig)
|
|||
unsigned char reply[10];
|
||||
unsigned char i = rmode2guohe(mode, pmr171_modes);
|
||||
|
||||
if (vfo == RIG_VFO_B)
|
||||
{
|
||||
cmd[6] = rmode2guohe(CACHE(rig)->modeMainA, pmr171_modes);
|
||||
cmd[7] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd[6] = i;
|
||||
cmd[7] = rmode2guohe(CACHE(rig)->modeMainB, pmr171_modes);
|
||||
}
|
||||
if (vfo == RIG_VFO_B)
|
||||
{
|
||||
cmd[6] = rmode2guohe(CACHE(rig)->modeMainA, pmr171_modes);
|
||||
|
@ -762,6 +695,39 @@ static int pmr171_open(RIG *rig)
|
|||
|
||||
dump_hex(reply, reply[4] + 5);
|
||||
|
||||
// Update cache
|
||||
CACHE(rig)->modeMainA = guohe2rmode(reply[6], pmr171_modes);
|
||||
CACHE(rig)->modeMainB = guohe2rmode(reply[7], pmr171_modes);
|
||||
int crc = CRC16Check(&cmd[4], 4);
|
||||
cmd[8] = crc >> 8;
|
||||
cmd[9] = crc & 0xff;
|
||||
rig_flush(rp);
|
||||
write_block(rp, cmd, 10);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: read_block failed for header\n", __func__);
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: invalid reply length %d\n", __func__, reply[4]);
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: read_block failed for data\n", __func__);
|
||||
}
|
||||
|
||||
// Validate mode field index won't overflow
|
||||
if (reply[4] < 3) { // Need at least 3 bytes to access reply[6] and reply[7]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for mode data\n", __func__);
|
||||
}
|
||||
|
||||
dump_hex(reply, reply[4] + 5);
|
||||
|
||||
// Update cache
|
||||
CACHE(rig)->modeMainA = guohe2rmode(reply[6], pmr171_modes);
|
||||
CACHE(rig)->modeMainB = guohe2rmode(reply[7], pmr171_modes);
|
||||
|
@ -785,6 +751,7 @@ static int pmr171_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt)
|
|||
|
||||
unsigned char reply[9];
|
||||
pmr171_send(rig, cmd, sizeof(cmd), reply, sizeof(reply));
|
||||
pmr171_send(rig, cmd, sizeof(cmd), reply, sizeof(reply));
|
||||
|
||||
CACHE(rig)->ptt = ptt;
|
||||
|
||||
|
|
|
@ -62,8 +62,7 @@ static int q900_get_vfo(RIG *rig, vfo_t *vfo);
|
|||
static int q900_set_freq(RIG *rig, vfo_t vfo, freq_t freq);
|
||||
static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq);
|
||||
static int q900_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width);
|
||||
static int q900_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode,
|
||||
pbwidth_t *width);
|
||||
static int q900_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width);
|
||||
static int q900_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt);
|
||||
static int q900_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt);
|
||||
static int q900_get_split_vfo(RIG *rig, vfo_t vfo, split_t *split,
|
||||
|
@ -320,6 +319,7 @@ static int q900_open(RIG *rig)
|
|||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static int q900_send(RIG *rig, const unsigned char* buff, int len, unsigned char *reply, int rlen)
|
||||
static int q900_send(RIG *rig, const unsigned char* buff, int len, unsigned char *reply, int rlen)
|
||||
{
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
int retry = 5;
|
||||
|
@ -374,38 +374,15 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
unsigned char reply[40];
|
||||
q900_send(rig, cmd, sizeof(cmd), reply, sizeof(reply));
|
||||
|
||||
if (reply[0] != 0xA5 || reply[1] != 0xA5 ||
|
||||
reply[2] != 0xA5 || reply[3] != 0xA5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid packet header\n", __func__);
|
||||
}
|
||||
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Validate buffer boundaries - ensure enough space for CRC
|
||||
int expected_total_length = 5 + reply[4] + 2; // header(5) + data_length + CRC(2)
|
||||
if (expected_total_length > sizeof(reply)) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too large for buffer: %d > %zu\n",
|
||||
__func__, expected_total_length, sizeof(reply));
|
||||
}
|
||||
|
||||
uint16_t recv_crc = (reply[31] << 8) | reply[32]; // Last 2 bytes are CRC
|
||||
uint16_t calc_crc = CRC16Check(&reply[4], 27);
|
||||
if (recv_crc != calc_crc) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: CRC check failed (received: %04X, calculated: %04X)\n",
|
||||
__func__, recv_crc, calc_crc);
|
||||
// Validate response using common function
|
||||
if (validate_freq_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_FREQ(rig, vfo, freq);
|
||||
}
|
||||
|
||||
// Parse frequency (big-endian)
|
||||
int freq_a_offset = 9;
|
||||
int freq_b_offset = 13;
|
||||
|
||||
// Validate frequency field offset won't overflow
|
||||
if (freq_b_offset + 3 >= expected_total_length - 2) { // -2 for CRC
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Frequency field offset out of bounds\n", __func__);
|
||||
}
|
||||
|
||||
uint32_t freq_a = (reply[freq_a_offset] << 24) |
|
||||
(reply[freq_a_offset+1] << 16) |
|
||||
(reply[freq_a_offset+2] << 8) |
|
||||
|
@ -416,7 +393,6 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
(reply[freq_b_offset+2] << 8) |
|
||||
reply[freq_b_offset+3];
|
||||
|
||||
|
||||
CACHE(rig)->freqMainA = (freq_t)freq_a;
|
||||
CACHE(rig)->freqMainB = (freq_t)freq_b;
|
||||
|
||||
|
@ -431,54 +407,19 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
static int q900_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
|
||||
{
|
||||
struct rig_cache *cachep = CACHE(rig);
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
const q900_data_t *p = (q900_data_t *) STATE(rig)->priv;
|
||||
unsigned char reply[255];
|
||||
|
||||
q900_send_cmd1(rig, 0x0b, 0);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate response length matches expected
|
||||
if (ret != reply[4]) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Data read mismatch: expected %d, got %d\n",
|
||||
__func__, reply[4], ret);
|
||||
return -RIG_EPROTO;
|
||||
// Read and validate response using common function
|
||||
if (read_rig_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_MODE(rig, vfo, mode, width, cachep, p);
|
||||
}
|
||||
|
||||
// Validate mode field index won't overflow
|
||||
if (reply[4] < 5) { // Need at least 5 bytes to access reply[7] and reply[8]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for mode data\n", __func__);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Validate mode field indices are within bounds
|
||||
if (reply[7] >= GUOHE_MODE_TABLE_MAX) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid mode A index %d\n", __func__, reply[7]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
if (reply[8] >= GUOHE_MODE_TABLE_MAX) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid mode B index %d\n", __func__, reply[8]);
|
||||
return -RIG_EPROTO;
|
||||
// Validate mode response using common function
|
||||
if (validate_mode_response(rig, reply, sizeof(reply), __func__, 5) < 0) {
|
||||
RETURN_CACHED_MODE(rig, vfo, mode, width, cachep, p);
|
||||
}
|
||||
|
||||
cachep->modeMainA = guohe2rmode(reply[7], q900_modes);
|
||||
|
@ -502,48 +443,25 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
|
||||
static int q900_get_vfo(RIG *rig, vfo_t *vfo)
|
||||
{
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
unsigned char reply[255];
|
||||
|
||||
q900_send_cmd1(rig, 0x0b, 0);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate response length matches expected
|
||||
if (ret != reply[4]) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Data read mismatch: expected %d, got %d\n",
|
||||
__func__, reply[4], ret);
|
||||
return -RIG_EPROTO;
|
||||
// Read and validate response using common function
|
||||
if (read_rig_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_VFO(rig, vfo);
|
||||
}
|
||||
|
||||
// Validate VFO status field index won't overflow
|
||||
if (reply[4] < 13) { // Need at least 13 bytes to access reply[17]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for VFO data\n", __func__);
|
||||
return -RIG_EPROTO;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for VFO data, using cached values\n", __func__);
|
||||
RETURN_CACHED_VFO(rig, vfo);
|
||||
}
|
||||
|
||||
// Validate VFO status value
|
||||
if (reply[17] != 0 && reply[17] != 1) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid VFO status value %d\n", __func__, reply[17]);
|
||||
return -RIG_EPROTO;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid VFO status value %d, using cached values\n", __func__, reply[17]);
|
||||
RETURN_CACHED_VFO(rig, vfo);
|
||||
}
|
||||
|
||||
*vfo = (reply[17] == 1) ? RIG_VFO_B : RIG_VFO_A;
|
||||
|
@ -552,58 +470,35 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
}
|
||||
|
||||
|
||||
static int q900_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt)
|
||||
{
|
||||
static int q900_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt)
|
||||
{
|
||||
struct rig_cache *cachep = CACHE(rig);
|
||||
hamlib_port_t *rp = RIGPORT(rig);
|
||||
unsigned char reply[255];
|
||||
|
||||
q900_send_cmd1(rig, 0x0b, 0);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read header\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
return -RIG_EPROTO;
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Failed to read data\n", __func__);
|
||||
return -RIG_ETIMEOUT;
|
||||
}
|
||||
|
||||
// Validate response length matches expected
|
||||
if (ret != reply[4]) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Data read mismatch: expected %d, got %d\n",
|
||||
__func__, reply[4], ret);
|
||||
return -RIG_EPROTO;
|
||||
// Read and validate response using common function
|
||||
if (read_rig_response(rig, reply, sizeof(reply), __func__) < 0) {
|
||||
RETURN_CACHED_PTT(rig, ptt, cachep);
|
||||
}
|
||||
|
||||
// Validate PTT status field index won't overflow
|
||||
if (reply[4] < 2) { // Need at least 2 bytes to access reply[6]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for PTT data\n", __func__);
|
||||
return -RIG_EPROTO;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for PTT data, using cached values\n", __func__);
|
||||
RETURN_CACHED_PTT(rig, ptt, cachep);
|
||||
}
|
||||
|
||||
// Validate PTT status value
|
||||
if (reply[6] != 0 && reply[6] != 1) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid PTT status value %d\n", __func__, reply[6]);
|
||||
return -RIG_EPROTO;
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid PTT status value %d, using cached values\n", __func__, reply[6]);
|
||||
RETURN_CACHED_PTT(rig, ptt, cachep);
|
||||
}
|
||||
|
||||
cachep->ptt = reply[6];
|
||||
*ptt = cachep->ptt;
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
@ -663,6 +558,7 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid data length %d\n", __func__, reply[4]);
|
||||
}
|
||||
|
@ -813,6 +709,65 @@ static int q900_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
|
|||
CACHE(rig)->modeMainA = guohe2rmode(reply[6], q900_modes);
|
||||
CACHE(rig)->modeMainB = guohe2rmode(reply[7], q900_modes);
|
||||
|
||||
if (vfo == RIG_VFO_B)
|
||||
{
|
||||
cmd[6] = rmode2guohe(CACHE(rig)->modeMainA, q900_modes);
|
||||
cmd[7] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd[6] = i;
|
||||
cmd[7] = rmode2guohe(CACHE(rig)->modeMainB, q900_modes);
|
||||
}
|
||||
|
||||
int crc = CRC16Check(&cmd[4], 4);
|
||||
cmd[8] = crc >> 8;
|
||||
cmd[9] = crc & 0xff;
|
||||
rig_flush(rp);
|
||||
write_block(rp, cmd, 10);
|
||||
|
||||
// Read header
|
||||
int ret = read_block(rp, reply, 5);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: read_block failed for header\n", __func__);
|
||||
}
|
||||
|
||||
// Validate data length
|
||||
if (reply[4] == 0 || reply[4] > sizeof(reply) - 5) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: invalid reply length %d\n", __func__, reply[4]);
|
||||
}
|
||||
|
||||
// Read data section
|
||||
ret = read_block(rp, &reply[5], reply[4]);
|
||||
if (ret < 0) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: read_block failed for data\n", __func__);
|
||||
}
|
||||
|
||||
// Validate response length matches expected
|
||||
if (ret != reply[4]) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Data read mismatch: expected %d, got %d\n",
|
||||
__func__, reply[4], ret);
|
||||
}
|
||||
|
||||
// Validate mode field index won't overflow
|
||||
if (reply[4] < 3) { // Need at least 3 bytes to access reply[6] and reply[7]
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Response too short for mode data\n", __func__);
|
||||
}
|
||||
|
||||
// Validate mode field indices are within bounds
|
||||
if (reply[6] >= GUOHE_MODE_TABLE_MAX) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid mode A index %d\n", __func__, reply[6]);
|
||||
}
|
||||
|
||||
if (reply[7] >= GUOHE_MODE_TABLE_MAX) {
|
||||
rig_debug(RIG_DEBUG_ERR, "%s: Invalid mode B index %d\n", __func__, reply[7]);
|
||||
}
|
||||
|
||||
dump_hex(reply, reply[4] + 5);
|
||||
|
||||
CACHE(rig)->modeMainA = guohe2rmode(reply[6], q900_modes);
|
||||
CACHE(rig)->modeMainB = guohe2rmode(reply[7], q900_modes);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
|
@ -832,6 +787,7 @@ static int q900_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt)
|
|||
|
||||
unsigned char reply[9];
|
||||
q900_send(rig, cmd, sizeof(cmd), reply, sizeof(reply));
|
||||
q900_send(rig, cmd, sizeof(cmd), reply, sizeof(reply));
|
||||
|
||||
// Update cache
|
||||
CACHE(rig)->ptt = ptt;
|
||||
|
|
Ładowanie…
Reference in New Issue