X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Frdtech-um%2Fprotocol.c;h=e4e4c6055101bb42a60008aa47668042969708c1;hb=bcbf2b5953328142d99ef15bbd76cd703317f512;hp=54416f6c1456f6a477ce3356a8e6ffacbe58e13e;hpb=323b32f482ce49104d10d663dc03ff6f0ecc8049;p=libsigrok.git diff --git a/src/hardware/rdtech-um/protocol.c b/src/hardware/rdtech-um/protocol.c index 54416f6c..e4e4c605 100644 --- a/src/hardware/rdtech-um/protocol.c +++ b/src/hardware/rdtech-um/protocol.c @@ -18,11 +18,13 @@ */ #include -#include -#include -#include + #include #include +#include +#include +#include + #include "libsigrok-internal.h" #include "protocol.h" @@ -56,42 +58,54 @@ static const struct binary_analog_channel rdtech_um25c_channels[] = { ALL_ZERO, }; -static int poll_csum_fff1(char buf[], int len) +static gboolean csum_ok_fff1(const uint8_t *buf, size_t len) { + uint16_t csum_recv; + if (len != UM_POLL_LEN) - return 0; - else - return RB16(&buf[len - 2]) == 0xFFF1; + return FALSE; + + csum_recv = read_u16be(&buf[len - sizeof(uint16_t)]); + if (csum_recv != 0xfff1) + return FALSE; + + return TRUE; } -static int poll_csum_um34c(char buf[], int len) +static gboolean csum_ok_um34c(const uint8_t *buf, size_t len) { static const int positions[] = { 1, 3, 7, 9, 15, 17, 19, 23, 31, 39, 41, 45, 49, 53, 55, 57, 59, 63, 67, 69, 73, 79, 83, 89, 97, 99, 109, 111, 113, 119, 121, 127, }; - unsigned int i; - uint8_t csum = 0; + + size_t i; + uint8_t csum_calc, csum_recv; if (len != UM_POLL_LEN) - return 0; + return FALSE; + csum_calc = 0; for (i = 0; i < ARRAY_SIZE(positions); i++) - csum ^= buf[positions[i]]; + csum_calc ^= buf[positions[i]]; + csum_recv = read_u8(&buf[len - sizeof(uint8_t)]); + if (csum_recv != csum_calc) + return FALSE; - return csum == (uint8_t)buf[len - 1]; + return TRUE; } static const struct rdtech_um_profile um_profiles[] = { - { "UM24C", RDTECH_UM24C, rdtech_default_channels, &poll_csum_fff1, }, - { "UM25C", RDTECH_UM25C, rdtech_um25c_channels, &poll_csum_fff1, }, - { "UM34C", RDTECH_UM34C, rdtech_default_channels, &poll_csum_um34c, }, + { "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, }, }; static const struct rdtech_um_profile *find_profile(uint16_t id) { unsigned int i; + for (i = 0; i < ARRAY_SIZE(um_profiles); i++) { if (um_profiles[i].model_id == id) return &um_profiles[i]; @@ -102,10 +116,12 @@ 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; - static const uint8_t request = UM_CMD_POLL; - char buf[RDTECH_UM_BUFSIZE]; + uint8_t request; + uint8_t buf[RDTECH_UM_BUFSIZE]; int len; + 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."); @@ -118,46 +134,58 @@ SR_PRIV const struct rdtech_um_profile *rdtech_um_probe(struct sr_serial_dev_ins 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->poll_csum(buf, len)) { - sr_err("Probe response contains illegal checksum or end marker.\n"); + if (!p->csum_ok(buf, len)) { + sr_err("Probe response fails checksum verification."); return NULL; } return p; } -SR_PRIV int rdtech_um_poll(const struct sr_dev_inst *sdi) +SR_PRIV int rdtech_um_poll(const struct sr_dev_inst *sdi, gboolean force) { - struct dev_context *devc = sdi->priv; - struct sr_serial_dev_inst *serial = sdi->conn; - static const uint8_t request = UM_CMD_POLL; + struct dev_context *devc; + int64_t now, elapsed; + struct sr_serial_dev_inst *serial; + uint8_t request; + + /* 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) + 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) { 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; int 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 != UM_POLL_LEN) { - sr_err("Unexpected poll packet length: %i", devc->buflen); + sr_err("Unexpected poll packet length: %zu", devc->buflen); return; } @@ -172,17 +200,18 @@ static void handle_poll_data(const struct sr_dev_inst *sdi) static void recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *serial) { - struct dev_context *devc = sdi->priv; - const struct rdtech_um_profile *p = devc->profile; + struct dev_context *devc; + const struct rdtech_um_profile *p; int len; /* Serial data arrived. */ + devc = sdi->priv; + p = devc->profile; while (devc->buflen < UM_POLL_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) { @@ -194,11 +223,12 @@ static void recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *s } } - if (devc->buflen == UM_POLL_LEN && p->poll_csum(devc->buf, devc->buflen)) - handle_poll_data(sdi); + if (devc->buflen != UM_POLL_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; } @@ -207,7 +237,6 @@ SR_PRIV int rdtech_um_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; @@ -226,11 +255,7 @@ SR_PRIV int rdtech_um_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 > UM_POLL_PERIOD_MS) - rdtech_um_poll(sdi); + (void)rdtech_um_poll(sdi, FALSE); return TRUE; }