From c9161e2e25d80609d5127ca0c1ebe8e78cb00040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A3=B0=E7=BA=B3?= <1595220980@qq.com> Date: Sat, 28 Jun 2025 10:11:21 +0800 Subject: [PATCH] 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 drivers --- rigs/guohetec/guohetec.c | 149 +++++++++++++++++++++++++- rigs/guohetec/guohetec.h | 59 +++++++++++ rigs/guohetec/pmr171.c | 171 ++++++++++++------------------ rigs/guohetec/q900.c | 224 ++++++++++++++++----------------------- 4 files changed, 366 insertions(+), 237 deletions(-) diff --git a/rigs/guohetec/guohetec.c b/rigs/guohetec/guohetec.c index 49b1a1a30..414bc42ae 100644 --- a/rigs/guohetec/guohetec.c +++ b/rigs/guohetec/guohetec.c @@ -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; diff --git a/rigs/guohetec/guohetec.h b/rigs/guohetec/guohetec.h index a90153834..90965a129 100644 --- a/rigs/guohetec/guohetec.h +++ b/rigs/guohetec/guohetec.h @@ -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_ diff --git a/rigs/guohetec/pmr171.c b/rigs/guohetec/pmr171.c index c89fa6744..e3ca96877 100644 --- a/rigs/guohetec/pmr171.c +++ b/rigs/guohetec/pmr171.c @@ -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; diff --git a/rigs/guohetec/q900.c b/rigs/guohetec/q900.c index 92973740a..8d4b2c1cc 100644 --- a/rigs/guohetec/q900.c +++ b/rigs/guohetec/q900.c @@ -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;