]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/rdtech-um/protocol.c
rdtech-um: rephrase channel count in profile description
[libsigrok.git] / src / hardware / rdtech-um / protocol.c
index e2afc67d8a9f4c2117212485ed8450de3f865fc0..5d3ab6ea0211bc4c92df6fd1988cbff25566e448 100644 (file)
 #include "libsigrok-internal.h"
 #include "protocol.h"
 
-#define SERIAL_WRITE_TIMEOUT_MS 1
+/* Read/write timeouts, poll request intervals. */
+#define PROBE_TO_MS 1000
+#define WRITE_TO_MS 1
+#define POLL_PERIOD_MS 100
 
-#define UM_POLL_LEN 130
-#define UM_POLL_PERIOD_MS 100
-#define UM_TIMEOUT_MS 1000
+/* Expected receive data size for poll responses. */
+#define POLL_RECV_LEN 130
 
+/* Command code to request another poll response. */
 #define UM_CMD_POLL 0xf0
 
-static const struct binary_analog_channel rdtech_default_channels[] = {
+static const struct binary_analog_channel default_channels[] = {
        { "V", { 2, BVT_BE_UINT16, 0.01, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
        { "I", { 4, BVT_BE_UINT16, 0.001, }, 3, SR_MQ_CURRENT, SR_UNIT_AMPERE },
        { "D+", { 96, BVT_BE_UINT16, 0.01, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
@@ -44,10 +47,9 @@ static const struct binary_analog_channel rdtech_default_channels[] = {
        { "T", { 10, BVT_BE_UINT16, 1.0, }, 0, SR_MQ_TEMPERATURE, SR_UNIT_CELSIUS },
        /* Threshold-based recording (mWh) */
        { "E", { 106, BVT_BE_UINT32, 0.001, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
-       ALL_ZERO,
 };
 
-static const struct binary_analog_channel rdtech_um25c_channels[] = {
+static const struct binary_analog_channel um25c_channels[] = {
        { "V", { 2, BVT_BE_UINT16, 0.001, }, 3, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
        { "I", { 4, BVT_BE_UINT16, 0.0001, }, 4, SR_MQ_CURRENT, SR_UNIT_AMPERE },
        { "D+", { 96, BVT_BE_UINT16, 0.01, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
@@ -55,14 +57,13 @@ static const struct binary_analog_channel rdtech_um25c_channels[] = {
        { "T", { 10, BVT_BE_UINT16, 1.0, }, 0, SR_MQ_TEMPERATURE, SR_UNIT_CELSIUS },
        /* Threshold-based recording (mWh) */
        { "E", { 106, BVT_BE_UINT32, 0.001, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
-       ALL_ZERO,
 };
 
 static gboolean csum_ok_fff1(const uint8_t *buf, size_t len)
 {
        uint16_t csum_recv;
 
-       if (len != UM_POLL_LEN)
+       if (len != POLL_RECV_LEN)
                return FALSE;
 
        csum_recv = read_u16be(&buf[len - sizeof(uint16_t)]);
@@ -83,7 +84,7 @@ static gboolean csum_ok_um34c(const uint8_t *buf, size_t len)
        size_t i;
        uint8_t csum_calc, csum_recv;
 
-       if (len != UM_POLL_LEN)
+       if (len != POLL_RECV_LEN)
                return FALSE;
 
        csum_calc = 0;
@@ -97,18 +98,20 @@ static gboolean csum_ok_um34c(const uint8_t *buf, size_t len)
 }
 
 static const struct rdtech_um_profile um_profiles[] = {
-       { "UM24C", RDTECH_UM24C, rdtech_default_channels, csum_ok_fff1, },
-       { "UM25C", RDTECH_UM25C, rdtech_um25c_channels, csum_ok_fff1, },
-       { "UM34C", RDTECH_UM34C, rdtech_default_channels, csum_ok_um34c, },
+       { "UM24C", RDTECH_UM24C, ARRAY_AND_SIZE(default_channels), csum_ok_fff1, },
+       { "UM25C", RDTECH_UM25C, ARRAY_AND_SIZE(um25c_channels), csum_ok_fff1, },
+       { "UM34C", RDTECH_UM34C, ARRAY_AND_SIZE(default_channels), csum_ok_um34c, },
 };
 
 static const struct rdtech_um_profile *find_profile(uint16_t id)
 {
-       unsigned int i;
+       size_t i;
+       const struct rdtech_um_profile *profile;
 
        for (i = 0; i < ARRAY_SIZE(um_profiles); i++) {
-               if (um_profiles[i].model_id == id)
-                       return &um_profiles[i];
+               profile = &um_profiles[i];
+               if (profile->model_id == id)
+                       return profile;
        }
        return NULL;
 }
@@ -116,31 +119,34 @@ static const struct rdtech_um_profile *find_profile(uint16_t id)
 SR_PRIV const struct rdtech_um_profile *rdtech_um_probe(struct sr_serial_dev_inst *serial)
 {
        const struct rdtech_um_profile *p;
-       uint8_t request;
+       uint8_t req;
+       int ret;
        uint8_t buf[RDTECH_UM_BUFSIZE];
-       int len;
+       int rcvd;
+       uint16_t model_id;
 
-       request = UM_CMD_POLL;
-       if (serial_write_blocking(serial, &request, sizeof(request),
-                       SERIAL_WRITE_TIMEOUT_MS) < 0) {
-               sr_err("Unable to send probe request.");
+       req = UM_CMD_POLL;
+       ret = serial_write_blocking(serial, &req, sizeof(req), WRITE_TO_MS);
+       if (ret < 0) {
+               sr_err("Failed to send probe request.");
                return NULL;
        }
 
-       len = serial_read_blocking(serial, buf, UM_POLL_LEN, UM_TIMEOUT_MS);
-       if (len != UM_POLL_LEN) {
+       rcvd = serial_read_blocking(serial, buf, POLL_RECV_LEN, PROBE_TO_MS);
+       if (rcvd != POLL_RECV_LEN) {
                sr_err("Failed to read probe response.");
                return NULL;
        }
 
-       p = find_profile(RB16(&buf[0]));
+       model_id = read_u16be(&buf[0]);
+       p = find_profile(model_id);
        if (!p) {
-               sr_err("Unrecognized UM device (0x%.4" PRIx16 ")!", RB16(&buf[0]));
+               sr_err("Unrecognized UM device (0x%.4" PRIx16 ").", model_id);
                return NULL;
        }
 
-       if (!p->csum_ok(buf, len)) {
-               sr_err("Probe response contains illegal checksum or end marker.\n");
+       if (!p->csum_ok(buf, rcvd)) {
+               sr_err("Probe response fails checksum verification.");
                return NULL;
        }
 
@@ -152,20 +158,21 @@ SR_PRIV int rdtech_um_poll(const struct sr_dev_inst *sdi, gboolean force)
        struct dev_context *devc;
        int64_t now, elapsed;
        struct sr_serial_dev_inst *serial;
-       uint8_t request;
+       uint8_t req;
+       int ret;
 
        /* Check for expired intervals or forced requests. */
        devc = sdi->priv;
        now = g_get_monotonic_time() / 1000;
        elapsed = now - devc->cmd_sent_at;
-       if (!force && elapsed < UM_POLL_PERIOD_MS)
+       if (!force && elapsed < POLL_PERIOD_MS)
                return SR_OK;
 
        /* Send another poll request. Update interval only on success. */
        serial = sdi->conn;
-       request = UM_CMD_POLL;
-       if (serial_write_blocking(serial, &request, sizeof(request),
-                       SERIAL_WRITE_TIMEOUT_MS) < 0) {
+       req = UM_CMD_POLL;
+       ret = serial_write_blocking(serial, &req, sizeof(req), WRITE_TO_MS);
+       if (ret < 0) {
                sr_err("Unable to send poll request.");
                return SR_ERR;
        }
@@ -177,20 +184,22 @@ SR_PRIV int rdtech_um_poll(const struct sr_dev_inst *sdi, gboolean force)
 static void handle_poll_data(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
-       int i;
+       size_t ch_idx;
        GSList *ch;
 
        devc = sdi->priv;
        sr_spew("Received poll packet (len: %zu).", devc->buflen);
-       if (devc->buflen != UM_POLL_LEN) {
+       if (devc->buflen != POLL_RECV_LEN) {
                sr_err("Unexpected poll packet length: %zu", devc->buflen);
                return;
        }
 
-       for (ch = sdi->channels, i = 0; ch; ch = g_slist_next(ch), i++) {
+       ch_idx = 0;
+       for (ch = sdi->channels; ch; ch = g_slist_next(ch)) {
                bv_send_analog_channel(sdi, ch->data,
-                       &devc->profile->channels[i],
+                       &devc->profile->channels[ch_idx],
                        devc->buf, devc->buflen);
+               ch_idx++;
        }
 
        sr_sw_limits_update_samples_read(&devc->limits, 1);
@@ -205,12 +214,11 @@ static void recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *s
        /* Serial data arrived. */
        devc = sdi->priv;
        p = devc->profile;
-       while (devc->buflen < UM_POLL_LEN) {
+       while (devc->buflen < POLL_RECV_LEN) {
                len = serial_read_nonblocking(serial, devc->buf + devc->buflen, 1);
                if (len < 1)
                        return;
-
-               devc->buflen++;
+               devc->buflen += len;
 
                /* Check if the poll model ID matches the profile. */
                if (devc->buflen == 2 && RB16(devc->buf) != p->model_id) {
@@ -222,11 +230,12 @@ static void recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *s
                }
        }
 
-       if (devc->buflen == UM_POLL_LEN && p->csum_ok(devc->buf, devc->buflen))
-               handle_poll_data(sdi);
+       if (devc->buflen != POLL_RECV_LEN)
+               sr_warn("Skipping packet, unexpected receive length.");
+       else if (!p->csum_ok(devc->buf, devc->buflen))
+               sr_warn("Skipping packet, checksum verification failed.");
        else
-               sr_warn("Skipping packet with illegal checksum / end marker.");
-
+               handle_poll_data(sdi);
        devc->buflen = 0;
 }
 
@@ -240,19 +249,21 @@ SR_PRIV int rdtech_um_receive_data(int fd, int revents, void *cb_data)
 
        if (!(sdi = cb_data))
                return TRUE;
-
        if (!(devc = sdi->priv))
                return TRUE;
 
+       /* Drain and process receive data as it becomes available. */
        serial = sdi->conn;
        if (revents == G_IO_IN)
                recv_poll_data(sdi, serial);
 
+       /* Check configured acquisition limits. */
        if (sr_sw_limits_check(&devc->limits)) {
                sr_dev_acquisition_stop(sdi);
                return TRUE;
        }
 
+       /* Periodically emit measurement requests. */
        (void)rdtech_um_poll(sdi, FALSE);
 
        return TRUE;