]> sigrok.org Git - libsigrok.git/commitdiff
greatfet: feed the session with constant width sample data
authorGerhard Sittig <redacted>
Thu, 21 Dec 2023 20:24:33 +0000 (21:24 +0100)
committerGerhard Sittig <redacted>
Thu, 21 Dec 2023 20:34:24 +0000 (21:34 +0100)
Rename identifiers to tell the sigrok session feed's width and the width
of sample data in device firmware communication apart. Always feed the
session with sample data of a width which corresponds to the device's
channels count. Some output modules and applications may not be prepared
to handle different cases.

src/hardware/greatfet/api.c
src/hardware/greatfet/protocol.c
src/hardware/greatfet/protocol.h

index 49d6730d7f1715168bacc0f2299d5e6fe339a613..db05c3d8d283201f3de51834678bb6e339b0f844 100644 (file)
@@ -307,6 +307,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
                        ch_off++;
                        cg->channels = g_slist_append(cg->channels, ch);
                }
+               devc->feed_unit_size = (ch_max + 8 - 1) / 8;
 
                sr_sw_limits_init(&devc->sw_limits);
                devc->samplerate = DEFAULT_SAMPLERATE;
@@ -510,7 +511,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
 
        if (!acq->feed_queue) {
                acq->feed_queue = feed_queue_logic_alloc(sdi,
-                       BUFFER_SIZE, acq->unit_size);
+                       BUFFER_SIZE, devc->feed_unit_size);
                if (!acq->feed_queue) {
                        sr_err("Cannot allocate session feed buffer.");
                        return SR_ERR_MALLOC;
index c39b1fceccc7e872e748d0bbf35bf76f270a87d2..4b1d1d964935faf23f3528116727f22e4bf4e086 100644 (file)
@@ -588,7 +588,7 @@ static int greatfet_logic_config(const struct sr_dev_inst *sdi)
        g_free(print_bw);
        bw = acq->capture_samplerate * 8 / acq->points_per_byte;
        if (!acq->use_upper_pins)
-               bw *= acq->unit_size;
+               bw *= acq->wire_unit_size;
        print_bw = sr_si_string_u64(bw, "bps");
        sr_info("Resulting USB bandwidth: %s.", print_bw);
        g_free(print_bw);
@@ -708,17 +708,15 @@ static int greatfet_calc_capture_chans(const struct sr_dev_inst *sdi)
        if (!fw_ch_count)
                return SR_ERR_ARG;
        if (fw_ch_count > 8) {
-               acq->unit_size = sizeof(uint16_t);
+               acq->wire_unit_size = sizeof(uint16_t);
                acq->points_per_byte = 1;
        } else {
-               acq->unit_size = sizeof(uint8_t);
-               if (acq->use_upper_pins)
-                       acq->unit_size = sizeof(uint16_t);
+               acq->wire_unit_size = sizeof(uint8_t);
                acq->points_per_byte = 8 / fw_ch_count;
        }
        acq->channel_shift = fw_ch_count % 8;
        sr_dbg("unit %zu, dense %d -> shift %zu, points %zu",
-               acq->unit_size, !!acq->channel_shift,
+               acq->wire_unit_size, !!acq->channel_shift,
                acq->channel_shift, acq->points_per_byte);
 
        return SR_OK;
@@ -1229,14 +1227,20 @@ SR_PRIV void greatfet_release_resources(const struct sr_dev_inst *sdi)
 
 /*
  * Process received sample date. There are two essential modes:
- * - The straight forward case. The device provides 8 bits per sample
- *   point. Forward each byte as is to the sigrok session. It matches
- *   the sizeof(uint8_t) feed queue allocation parameter.
+ * - The straight forward case. The device provides 16 bits per sample
+ *   point. Forward raw received data as is to the sigrok session. The
+ *   device's endianess matches the session's LE expectation. And the
+ *   data matches the device's announced total channel count.
  * - The compact presentation where a smaller number of channels is
  *   active, and their data spans only part of a byte per sample point.
  *   Multiple samples' data is sharing bytes, and bytes will carry data
  *   that was taken at different times. This requires some untangling
- *   before forwarding byte sized sample data to the sigrok session.
+ *   before forwarding sample data to the sigrok session which is of
+ *   the expected width (unit size) and carries one sample per item.
+ * - The cases where one sample point's data occupies full bytes, but
+ *   the firmware only communicates one byte per sample point, are seen
+ *   as a special case of the above bit packing. The "complex case"
+ *   logic covers the "bytes extension" as well.
  *
  * Implementation details:
  * - Samples taken first are found in the least significant bits of a
@@ -1264,12 +1268,11 @@ static int greatfet_process_receive_data(const struct sr_dev_inst *sdi,
        struct feed_queue_logic *q;
        uint64_t samples_remain;
        gboolean exceeded;
-       gboolean full_bytes, lower_empty;
        size_t samples_rcvd;
-       uint8_t raw_mask;
+       uint8_t raw_mask, raw_data;
        size_t points_per_byte, points_count;
-       uint8_t raw_data, wr_data;
-       uint8_t accum[16];
+       uint16_t wr_data;
+       uint8_t accum[8 * sizeof(wr_data)];
        const uint8_t *rdptr;
        uint8_t *wrptr;
        int ret;
@@ -1296,24 +1299,17 @@ static int greatfet_process_receive_data(const struct sr_dev_inst *sdi,
                return SR_OK;
 
        /*
-        * Check for the simple case first. Where bytes carry samples
-        * of exactly one sample point. Pass memory in verbatim form.
+        * Check for the simple case first. Where the firmware provides
+        * sample data for all logic channels supported by the device.
+        * Pass sample memory as received from the device in verbatim
+        * form to the session feed.
         *
-        * This approach applies to two cases: Captures of the first 8
-        * channels, and captures for 16 channels where both banks are
-        * involved (the device firmware provides all 16 bits of data
-        * for any given sample point). The 16bit case happens to work
-        * because sample data received from the device and logic data
-        * in sigrok sessions both use the little endian format.
-        *
-        * The "upper pins" case must be handled below because the
-        * device will not provide data for the lower pin bank, but the
-        * samples (all-zero values) must be sent to the sigrok session.
+        * This happens to work because sample data received from the
+        * device and logic data in sigrok sessions both are in little
+        * endian format.
         */
-       full_bytes = !acq->channel_shift;
-       lower_empty = acq->use_upper_pins;
-       if (full_bytes && !lower_empty) {
-               samples_rcvd = dlen / acq->unit_size;
+       if (acq->wire_unit_size == devc->feed_unit_size) {
+               samples_rcvd = dlen / acq->wire_unit_size;
                if (samples_remain && samples_rcvd > samples_remain)
                        samples_rcvd = samples_remain;
                ret = feed_queue_logic_submit_many(q, data, samples_rcvd);
@@ -1322,11 +1318,17 @@ static int greatfet_process_receive_data(const struct sr_dev_inst *sdi,
                sr_sw_limits_update_samples_read(&devc->sw_limits, samples_rcvd);
                return SR_OK;
        }
+       if (sizeof(wr_data) != devc->feed_unit_size) {
+               sr_err("Unhandled unit size mismatch. Flawed implementation?");
+               return SR_ERR_BUG;
+       }
 
        /*
         * Handle the complex cases where one byte carries values that
         * were taken at multiple sample points, or where the firmware
-        * does not communicate the lower pin bank's data (upper pins).
+        * does not communicate all pin banks to the host (upper pins
+        * or lower pins only on the wire).
+        *
         * This involves manipulation between reception and forwarding.
         * It helps that the firmware provides sample data in units of
         * power-of-two bit counts per sample point. This eliminates
@@ -1363,9 +1365,8 @@ static int greatfet_process_receive_data(const struct sr_dev_inst *sdi,
                while (points_count--) {
                        wr_data = raw_data & raw_mask;
                        if (acq->use_upper_pins)
-                               write_u16le_inc(&wrptr, wr_data << 8);
-                       else
-                               write_u8_inc(&wrptr, wr_data);
+                               wr_data <<= 8;
+                       write_u16le_inc(&wrptr, wr_data);
                        raw_data >>= acq->channel_shift;
                }
                points_count = points_per_byte;
index 8fe7e1d87df73ed7f3a80b75b58de71536ab88b1..fe344a758806af63b524ecdc019b29b97b15a8c0 100644 (file)
@@ -37,11 +37,12 @@ struct dev_context {
        char *serial_number;
        size_t channel_count;
        char **channel_names;
+       size_t feed_unit_size;
        struct sr_sw_limits sw_limits;
        uint64_t samplerate;
        struct dev_acquisition_t {
                uint64_t bandwidth_threshold;
-               size_t unit_size;
+               size_t wire_unit_size;
                struct feed_queue_logic *feed_queue;
                size_t capture_channels;
                gboolean use_upper_pins;