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
pull/1787/head
声纳 2025-06-28 10:11:21 +08:00
rodzic 862fda58be
commit c9161e2e25
4 zmienionych plików z 366 dodań i 237 usunięć

Wyświetl plik

@ -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;

Wyświetl plik

@ -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_

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;