From f0e6b41f7a11daaef1ed0783c25768ad90b1a765 Mon Sep 17 00:00:00 2001 From: Gerhard Sittig Date: Fri, 6 Oct 2017 01:38:26 +0200 Subject: [PATCH] uni-t-ut32x: rephrase the receive buffer and packets relation The previous implementation assumed that a receive data chunk ends exactly with a sensor packet's end. Yet the buffer had 32 bytes while the packets have 19 bytes. Separate the data reception from the packet processing. Collect whatever chunks the USB connection provides, and scan the resulting buffer for packets. Cope with either incomplete or corrupt or misaligned packets as well as with multiple packets in receive chunks. The latter might happen upon initial synchronization, when a device already sends data or the serial port buffered previously communicated data. In the regular case, the computer will process so fast that each single character will be handled individually. We don't mind. The frequency is some 60 times per second, and the data volume is 19 bytes. The software works for the regular case, and synchronizes fast at startup or after comm errors. --- src/hardware/uni-t-ut32x/protocol.c | 75 ++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/src/hardware/uni-t-ut32x/protocol.c b/src/hardware/uni-t-ut32x/protocol.c index 7d69091e..4da24662 100644 --- a/src/hardware/uni-t-ut32x/protocol.c +++ b/src/hardware/uni-t-ut32x/protocol.c @@ -156,6 +156,62 @@ static void process_packet(struct sr_dev_inst *sdi, uint8_t *pkt, size_t len) sr_dev_acquisition_stop(sdi); } +static int process_buffer(struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + uint8_t *pkt; + size_t remain, idx; + + /* + * Specifically do not insist on finding the packet boundary at + * the end of the most recently received data chunk. Serial + * ports might involve hardware buffers (FIFO). We want to sync + * as fast as possible. + * + * Handle the synchronized situation first. Process complete + * packets that reside at the start of the buffer. Then fallback + * to incomplete or unaligned packets if the receive buffer + * still contains data bytes. (Depending on the bitrate and the + * poll interval, we may always end up in the manual search. But + * considering the update rate - two or three packets per second + * - this is not an issue.) + */ + devc = sdi->priv; + pkt = &devc->packet[0]; + while (devc->packet_len >= PACKET_SIZE && + pkt[PACKET_SIZE - 2] == SEP[0] && + pkt[PACKET_SIZE - 1] == SEP[1]) { + process_packet(sdi, &pkt[0], PACKET_SIZE); + remain = devc->packet_len - PACKET_SIZE; + if (remain) + memmove(&pkt[0], &pkt[PACKET_SIZE], remain); + devc->packet_len -= PACKET_SIZE; + } + + /* + * The 'for' loop and the increment upon re-iteration after + * setting the loop var to zero is not an issue. The marker has + * two bytes, so effectively starting the search at offset 1 is + * fine for the specific packet layout. + */ + for (idx = 0; idx < devc->packet_len; idx++) { + if (idx < 1) + continue; + if (pkt[idx - 1] != SEP[0] || pkt[idx] != SEP[1]) + continue; + /* Found a packet that spans up to and including 'idx'. */ + idx++; + process_packet(sdi, &pkt[0], idx); + remain = devc->packet_len - idx; + if (remain) + memmove(&pkt[0], &pkt[idx], remain); + devc->packet_len -= idx; + idx = 0; + } + + return 0; +} + SR_PRIV void LIBUSB_CALL uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer) { struct dev_context *devc; @@ -171,19 +227,16 @@ SR_PRIV void LIBUSB_CALL uni_t_ut32x_receive_transfer(struct libusb_transfer *tr memcpy(devc->packet + devc->packet_len, transfer->buffer + 1, hid_payload_len); devc->packet_len += hid_payload_len; - if (devc->packet_len >= 2 - && devc->packet[devc->packet_len - 2] == SEP[0] - && devc->packet[devc->packet_len - 1] == SEP[1]) { - /* Got end of packet. */ - process_packet(sdi, devc->packet, devc->packet_len); - devc->packet_len = 0; - } else if (devc->packet_len > PACKET_SIZE) { - /* Guard against garbage from the device overrunning - * our packet buffer. */ - sr_dbg("Buffer overrun!"); - process_packet(sdi, devc->packet, devc->packet_len); + /* + * Discard receive data when the buffer is exhausted. This shall + * allow to (re-)synchronize to the data stream when we find it + * in an arbitrary state. Check the receive buffer for packets. + */ + if (devc->packet_len == sizeof(devc->packet)) { + process_packet(sdi, &devc->packet[0], devc->packet_len); devc->packet_len = 0; } + process_buffer(sdi); } /* Get the next transfer (unless we're shutting down). */ -- 2.30.2