]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/rdtech-tc/protocol.c
rdtech-tc: concentrate request transmit handling in one spot
[libsigrok.git] / src / hardware / rdtech-tc / protocol.c
index 3b94890d43b30f8926b3321d4533a3602c0a3e7e..36477858876cbaa588db2f15e5f67734dd2d5701 100644 (file)
  */
 
 #include <config.h>
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
+
 #include <glib.h>
-#include <nettle/aes.h>
 #include <libsigrok/libsigrok.h>
+#include <math.h>
+#include <nettle/aes.h>
+#include <stdlib.h>
+#include <string.h>
+
 #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;
 }