- while (devc->buflen < POLL_RECV_LEN) {
- len = serial_read_nonblocking(serial, devc->buf + devc->buflen, 1);
- if (len < 1)
- return;
- devc->buflen += len;
-
- /* Check if the poll model ID matches the profile. */
- if (devc->buflen == 2 && RB16(devc->buf) != p->model_id) {
- sr_warn("Illegal model ID in poll response (0x%.4" PRIx16 "),"
- " skipping 1 byte.",
- RB16(devc->buf));
- devc->buflen--;
- memmove(devc->buf, devc->buf + 1, devc->buflen);
+ rdptr = &devc->buf[devc->buflen];
+ space = sizeof(devc->buf) - devc->buflen;
+ do_sync_check = FALSE;
+ sync_len = sizeof(uint16_t);
+ while (space) {
+ ret = serial_read_nonblocking(serial, rdptr, space);
+ if (ret < 0)
+ return SR_ERR_IO;
+ rcvd = (size_t)ret;
+ if (rcvd == 0)
+ break;
+ if (rcvd > space)
+ return SR_ERR_BUG;
+ if (devc->buflen < sync_len)
+ do_sync_check = TRUE;
+ devc->buflen += rcvd;
+ if (devc->buflen < sync_len)
+ do_sync_check = FALSE;
+ space -= rcvd;
+ rdptr += rcvd;
+ }
+
+ /*
+ * Synchronize to the packetized input stream. Check the model
+ * ID at the start of receive data. Which is a weak condition,
+ * but going out of sync should be rare, and repeated attempts
+ * to synchronize should eventually succeed. Try to rate limit
+ * the emission of diagnostics messages. (Re-)run this logic
+ * at the first reception which makes enough data available,
+ * but not during subsequent accumulation of more data.
+ *
+ * Reducing redundancy in the implementation at the same time as
+ * increasing robustness would involve the creation of a checker
+ * routine, which just gets called for every byte position until
+ * it succeeds. Similar to what a previous implementation of the
+ * read loop did, which was expensive on the serial transport.
+ */
+ sync_idx = 0;
+ if (do_sync_check && read_u16be(&devc->buf[sync_idx]) != p->model_id)
+ sr_warn("Unexpected response data, trying to synchronize.");
+ while (do_sync_check) {
+ if (sync_idx + sync_len >= devc->buflen)
+ break;
+ if (read_u16be(&devc->buf[sync_idx]) == p->model_id)
+ break;
+ sync_idx++;
+ }
+ if (do_sync_check && sync_idx) {
+ sr_dbg("Skipping %zu bytes in attempt to sync.", sync_idx);
+ sync_len = devc->buflen - sync_idx;
+ if (sync_len)
+ memmove(&devc->buf[0], &devc->buf[sync_idx], sync_len);
+ devc->buflen -= sync_idx;
+ }
+
+ /*
+ * Process packets as their reception completes. Periodically
+ * re-transmit poll requests. Discard consumed data after all
+ * processing has completed.
+ */
+ rdptr = devc->buf;
+ rdlen = devc->buflen;
+ ret = SR_OK;
+ while (ret == SR_OK && rdlen >= POLL_RECV_LEN) {
+ ret = process_data(sdi, rdptr, rdlen);
+ if (ret != SR_OK) {
+ sr_err("Processing response packet failed.");
+ break;