X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Frdtech-tc%2Fprotocol.c;h=36477858876cbaa588db2f15e5f67734dd2d5701;hb=a82490b6f7ea4a65a45d96e1a55c7bd74a4e49c1;hp=3b94890d43b30f8926b3321d4533a3602c0a3e7e;hpb=0988d4ae2d7a47258b1ec3278381a973aa12831e;p=libsigrok.git diff --git a/src/hardware/rdtech-tc/protocol.c b/src/hardware/rdtech-tc/protocol.c index 3b94890d..36477858 100644 --- a/src/hardware/rdtech-tc/protocol.c +++ b/src/hardware/rdtech-tc/protocol.c @@ -18,36 +18,44 @@ */ #include -#include -#include -#include + #include -#include #include +#include +#include +#include +#include + #include "libsigrok-internal.h" #include "protocol.h" #define SERIAL_WRITE_TIMEOUT_MS 1 -#define TC_POLL_LEN 192 #define TC_POLL_PERIOD_MS 100 #define TC_TIMEOUT_MS 1000 -static const char POLL_CMD[] = "getva"; +static const char *poll_cmd = "getva"; + +/* + * Response data (raw sample data) consists of three adjacent chunks + * of 64 bytes each. These chunks start with their magic string, and + * end in a 32bit checksum field. Measurement values are scattered + * across these 192 bytes total size. All multi-byte integer values + * are represented in little endian format. Typical size is 32 bits. + */ -#define MAGIC_PAC1 0x31636170UL -#define MAGIC_PAC2 0x32636170UL -#define MAGIC_PAC3 0x33636170UL +#define MAGIC_PAC1 0x70616331 /* 'pac1' */ +#define MAGIC_PAC2 0x70616332 /* 'pac2' */ +#define MAGIC_PAC3 0x70616333 /* 'pac3' */ -/* Length of PAC block excluding CRC */ -#define PAC_DATA_LEN 60 -/* Length of PAC block including CRC */ #define PAC_LEN 64 +#define PAC_CRC_POS (PAC_LEN - sizeof(uint32_t)) /* Offset to PAC block from start of poll data */ #define OFF_PAC1 (0 * PAC_LEN) #define OFF_PAC2 (1 * PAC_LEN) #define OFF_PAC3 (2 * PAC_LEN) +#define TC_POLL_LEN (3 * PAC_LEN) #define OFF_MODEL 4 #define LEN_MODEL 4 @@ -74,55 +82,58 @@ static const struct binary_analog_channel rdtech_tc_channels[] = { ALL_ZERO, }; -static int check_pac_crc(uint8_t *data) +static gboolean check_pac_crc(uint8_t *data) { uint16_t crc; uint32_t crc_field; - crc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_DATA_LEN); - crc_field = RL32(data + PAC_DATA_LEN); - + crc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_CRC_POS); + crc_field = read_u32le(&data[PAC_CRC_POS]); if (crc != crc_field) { sr_spew("CRC error. Calculated: %0x" PRIx16 ", expected: %0x" PRIx32, crc, crc_field); - return 0; - } else { - return 1; + return FALSE; } + + return TRUE; } -static int process_poll_pkt(struct dev_context *devc, uint8_t *dst) +static int process_poll_pkt(struct dev_context *devc, uint8_t *dst) { struct aes256_ctx ctx; + gboolean ok; aes256_set_decrypt_key(&ctx, AES_KEY); aes256_decrypt(&ctx, TC_POLL_LEN, dst, devc->buf); - if (RL32(dst + OFF_PAC1) != MAGIC_PAC1 || - RL32(dst + OFF_PAC2) != MAGIC_PAC2 || - RL32(dst + OFF_PAC3) != MAGIC_PAC3) { - sr_err("Invalid poll packet magic values!"); - return SR_ERR; + ok = TRUE; + ok &= read_u32be(&dst[OFF_PAC1]) == MAGIC_PAC1; + ok &= read_u32be(&dst[OFF_PAC2]) == MAGIC_PAC2; + ok &= read_u32be(&dst[OFF_PAC3]) == MAGIC_PAC3; + if (!ok) { + sr_err("Invalid poll response packet (magic values)."); + return SR_ERR_DATA; } - if (!check_pac_crc(dst + OFF_PAC1) || - !check_pac_crc(dst + OFF_PAC2) || - !check_pac_crc(dst + OFF_PAC3)) { - sr_err("Invalid poll checksum!"); - return SR_ERR; + ok &= check_pac_crc(&dst[OFF_PAC1]); + ok &= check_pac_crc(&dst[OFF_PAC2]); + ok &= check_pac_crc(&dst[OFF_PAC3]); + if (!ok) { + sr_err("Invalid poll response packet (checksum)."); + return SR_ERR_DATA; } return SR_OK; } -SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_context *devc) +SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_context *devc) { int len; uint8_t poll_pkt[TC_POLL_LEN]; - if (serial_write_blocking(serial, &POLL_CMD, sizeof(POLL_CMD) - 1, - SERIAL_WRITE_TIMEOUT_MS) < 0) { - sr_err("Unable to send probe request."); + if (serial_write_blocking(serial, poll_cmd, strlen(poll_cmd), + SERIAL_WRITE_TIMEOUT_MS) < 0) { + sr_err("Failed to send probe request."); return SR_ERR; } @@ -138,39 +149,47 @@ SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_contex } devc->channels = rdtech_tc_channels; - devc->dev_info.model_name = g_strndup((const char *)poll_pkt + OFF_MODEL, LEN_MODEL); - devc->dev_info.fw_ver = g_strndup((const char *)poll_pkt + OFF_FW_VER, LEN_FW_VER); - devc->dev_info.serial_num = RL32(poll_pkt + OFF_SERIAL); + devc->dev_info.model_name = g_strndup((const char *)&poll_pkt[OFF_MODEL], LEN_MODEL); + devc->dev_info.fw_ver = g_strndup((const char *)&poll_pkt[OFF_FW_VER], LEN_FW_VER); + devc->dev_info.serial_num = read_u32le(&poll_pkt[OFF_SERIAL]); return SR_OK; } -SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi) +SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi, gboolean force) { - struct dev_context *devc = sdi->priv; - struct sr_serial_dev_inst *serial = sdi->conn; + struct dev_context *devc; + int64_t now, elapsed; + struct sr_serial_dev_inst *serial; - if (serial_write_blocking(serial, &POLL_CMD, sizeof(POLL_CMD) - 1, - SERIAL_WRITE_TIMEOUT_MS) < 0) { + devc = sdi->priv; + now = g_get_monotonic_time() / 1000; + elapsed = now - devc->cmd_sent_at; + if (!force && elapsed < TC_POLL_PERIOD_MS) + return SR_OK; + + serial = sdi->conn; + if (serial_write_blocking(serial, poll_cmd, strlen(poll_cmd), + SERIAL_WRITE_TIMEOUT_MS) < 0) { sr_err("Unable to send poll request."); return SR_ERR; } - - devc->cmd_sent_at = g_get_monotonic_time() / 1000; + devc->cmd_sent_at = now; return SR_OK; } static void handle_poll_data(const struct sr_dev_inst *sdi) { - struct dev_context *devc = sdi->priv; + struct dev_context *devc; uint8_t poll_pkt[TC_POLL_LEN]; - int i; + size_t i; GSList *ch; - sr_spew("Received poll packet (len: %d).", devc->buflen); + devc = sdi->priv; + sr_spew("Received poll packet (len: %zu).", devc->buflen); if (devc->buflen != TC_POLL_LEN) { - sr_err("Unexpected poll packet length: %i", devc->buflen); + sr_err("Unexpected poll packet length: %zu", devc->buflen); return; } @@ -179,20 +198,23 @@ static void handle_poll_data(const struct sr_dev_inst *sdi) return; } - for (ch = sdi->channels, i = 0; ch; ch = g_slist_next(ch), i++) { + i = 0; + for (ch = sdi->channels; ch; ch = g_slist_next(ch)) { bv_send_analog_channel(sdi, ch->data, - &devc->channels[i], poll_pkt, TC_POLL_LEN); - } + &devc->channels[i], poll_pkt, TC_POLL_LEN); + i++; + } sr_sw_limits_update_samples_read(&devc->limits, 1); } static void recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *serial) { - struct dev_context *devc = sdi->priv; + struct dev_context *devc; int len; /* Serial data arrived. */ + devc = sdi->priv; while (devc->buflen < TC_POLL_LEN) { len = serial_read_nonblocking(serial, devc->buf + devc->buflen, 1); if (len < 1) @@ -212,13 +234,11 @@ SR_PRIV int rdtech_tc_receive_data(int fd, int revents, void *cb_data) struct sr_dev_inst *sdi; struct dev_context *devc; struct sr_serial_dev_inst *serial; - int64_t now, elapsed; (void)fd; if (!(sdi = cb_data)) return TRUE; - if (!(devc = sdi->priv)) return TRUE; @@ -231,11 +251,7 @@ SR_PRIV int rdtech_tc_receive_data(int fd, int revents, void *cb_data) return TRUE; } - now = g_get_monotonic_time() / 1000; - elapsed = now - devc->cmd_sent_at; - - if (elapsed > TC_POLL_PERIOD_MS) - rdtech_tc_poll(sdi); + rdtech_tc_poll(sdi, FALSE); return TRUE; }