]> sigrok.org Git - libsigrok.git/commitdiff
hameg-hmo: Map logic data from second digital pod to channels D8-D15
authorGerhard Sittig <redacted>
Fri, 6 Jan 2017 19:53:50 +0000 (20:53 +0100)
committerUwe Hermann <redacted>
Fri, 20 Jan 2017 17:53:43 +0000 (18:53 +0100)
An internal libsigrok implementation detail prevents partial submission
of logic data for different channel groups in multiple calls. Instead
one logic packet needs to be sent in a single call, which combines data
for all channels.

Introduce a logic data storage which folds samples from several channel
groups that were received at different points in time into a combined
memory layout of larger unitsize. Stick with the former shortcut of
passing on the input bytes directly when only the first digital pod is
used during acquisition.

This change correctly maps data from the second pod to channels D8-D15.

src/hardware/hameg-hmo/api.c
src/hardware/hameg-hmo/protocol.c
src/hardware/hameg-hmo/protocol.h

index f47489315d903f63a9515bc1ba09ee43b639f1f7..00d57c5ef3a8d103877b11a041a9189b9dc469ba 100644 (file)
@@ -707,7 +707,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
 {
        GSList *l;
        gboolean digital_added[MAX_DIGITAL_GROUP_COUNT];
-       size_t group;
+       size_t group, pod_count;
        struct sr_channel *ch;
        struct dev_context *devc;
        struct sr_scpi_dev_inst *scpi;
@@ -726,8 +726,10 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
        devc->enabled_channels = NULL;
 
        /*
-        * Contruct the list of enabled channels.
+        * Contruct the list of enabled channels. Determine the highest
+        * number of digital pods involved in the acquisition.
         */
+       pod_count = 0;
        for (l = sdi->channels; l; l = l->next) {
                ch = l->data;
                if (!ch->enabled)
@@ -737,12 +739,17 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
                if (ch->type != SR_CHANNEL_LOGIC || !digital_added[group]) {
                        devc->enabled_channels = g_slist_append(
                                        devc->enabled_channels, ch);
-                       if (ch->type == SR_CHANNEL_LOGIC)
+                       if (ch->type == SR_CHANNEL_LOGIC) {
                                digital_added[group] = TRUE;
+                               if (pod_count < group + 1)
+                                       pod_count = group + 1;
+                       }
                }
        }
        if (!devc->enabled_channels)
                return SR_ERR;
+       devc->pod_count = pod_count;
+       devc->logic_data = NULL;
 
        /*
         * Check constraints. Some channels can be either analog or
index 978708c46c2aaca5ebe8948ff1750ca0f0482add..b25165953dd31749f8aa89cb7d17064ffbbbc3a5 100644 (file)
 #include "scpi.h"
 #include "protocol.h"
 
+SR_PRIV void hmo_queue_logic_data(struct dev_context *devc,
+                                 size_t group, GByteArray *pod_data);
+SR_PRIV void hmo_send_logic_packet(struct sr_dev_inst *sdi,
+                                  struct dev_context *devc);
+SR_PRIV void hmo_cleanup_logic_data(struct dev_context *devc);
+
 static const char *hameg_scpi_dialect[] = {
        [SCPI_CMD_GET_DIG_DATA]             = ":FORM UINT,8;:POD%d:DATA?",
        [SCPI_CMD_GET_TIMEBASE]             = ":TIM:SCAL?",
@@ -764,6 +770,89 @@ SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
+/* Queue data of one channel group, for later submission. */
+SR_PRIV void hmo_queue_logic_data(struct dev_context *devc,
+                                 size_t group, GByteArray *pod_data)
+{
+       size_t size;
+       GByteArray *store;
+       uint8_t *logic_data;
+       size_t idx, logic_step;
+
+       /*
+        * Upon first invocation, allocate the array which can hold the
+        * combined logic data for all channels. Assume that each channel
+        * will yield an identical number of samples per receive call.
+        *
+        * As a poor man's safety measure: (Silently) skip processing
+        * for unexpected sample counts, and ignore samples for
+        * unexpected channel groups. Don't bother with complicated
+        * resize logic, considering that many models only support one
+        * pod, and the most capable supported models have two pods of
+        * identical size. We haven't yet seen any "odd" configuration.
+        */
+       if (!devc->logic_data) {
+               size = pod_data->len * devc->pod_count;
+               store = g_byte_array_sized_new(size);
+               memset(store->data, 0, size);
+               store = g_byte_array_set_size(store, size);
+               devc->logic_data = store;
+       } else {
+               store = devc->logic_data;
+               size = store->len / devc->pod_count;
+               if (size != pod_data->len)
+                       return;
+               if (group >= devc->pod_count)
+                       return;
+       }
+
+       /*
+        * Fold the data of the most recently received channel group into
+        * the storage, where data resides for all channels combined.
+        */
+       logic_data = store->data;
+       logic_data += group;
+       logic_step = devc->pod_count;
+       for (idx = 0; idx < pod_data->len; idx++) {
+               *logic_data = pod_data->data[idx];
+               logic_data += logic_step;
+       }
+}
+
+/* Submit data for all channels, after the individual groups got collected. */
+SR_PRIV void hmo_send_logic_packet(struct sr_dev_inst *sdi,
+                                  struct dev_context *devc)
+{
+       struct sr_datafeed_packet packet;
+       struct sr_datafeed_logic logic;
+
+       if (!devc->logic_data)
+               return;
+
+       logic.data = devc->logic_data->data;
+       logic.length = devc->logic_data->len;
+       logic.unitsize = devc->pod_count;
+
+       packet.type = SR_DF_LOGIC;
+       packet.payload = &logic;
+
+       sr_session_send(sdi, &packet);
+}
+
+/* Undo previous resource allocation. */
+SR_PRIV void hmo_cleanup_logic_data(struct dev_context *devc)
+{
+
+       if (devc->logic_data) {
+               g_byte_array_free(devc->logic_data, TRUE);
+               devc->logic_data = NULL;
+       }
+       /*
+        * Keep 'pod_count'! It's required when more frames will be
+        * received, and does not harm when kept after acquisition.
+        */
+}
+
 SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
 {
        struct sr_channel *ch;
@@ -777,6 +866,7 @@ SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
        struct sr_analog_meaning meaning;
        struct sr_analog_spec spec;
        struct sr_datafeed_logic logic;
+       size_t group;
 
        (void)fd;
        (void)revents;
@@ -866,13 +956,31 @@ SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
                        return TRUE;
                }
 
+               /*
+                * If only data from the first pod is involved in the
+                * acquisition, then the raw input bytes can get passed
+                * forward for performance reasons. When the second pod
+                * is involved (either alone, or in combination with the
+                * first pod), then the received bytes need to be put
+                * into memory in such a layout that all channel groups
+                * get combined, and a unitsize larger than a single byte
+                * applies. The "queue" logic transparently copes with
+                * any such configuration. This works around the lack
+                * of support for "meaning" to logic data, which is used
+                * above for analog data.
+                */
+               if (devc->pod_count == 1) {
+                       packet.type = SR_DF_LOGIC;
+                       logic.data = data->data;
+                       logic.length = data->len;
+                       logic.unitsize = 1;
+                       packet.payload = &logic;
+                       sr_session_send(sdi, &packet);
+               } else {
+                       group = ch->index / 8;
+                       hmo_queue_logic_data(devc, group, data);
+               }
 
-               logic.length = data->len;
-               logic.unitsize = 1;
-               logic.data = data->data;
-               packet.type = SR_DF_LOGIC;
-               packet.payload = &logic;
-               sr_session_send(sdi, &packet);
                g_byte_array_free(data, TRUE);
                data = NULL;
                break;
@@ -883,13 +991,24 @@ SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
 
        /*
         * Advance to the next enabled channel. When data for all enabled
-        * channels was received, then send the "frame end" packet.
+        * channels was received, then flush potentially queued logic data,
+        * and send the "frame end" packet.
         */
        if (devc->current_channel->next) {
                devc->current_channel = devc->current_channel->next;
                hmo_request_data(sdi);
                return TRUE;
        }
+       hmo_send_logic_packet(sdi, devc);
+
+       /*
+        * Release the logic data storage after each frame. This copes
+        * with sample counts that differ in length per frame. -- Is
+        * this a real constraint when acquiring multiple frames with
+        * identical device settings?
+        */
+       hmo_cleanup_logic_data(devc);
+
        packet.type = SR_DF_FRAME_END;
        sr_session_send(sdi, &packet);
 
@@ -900,6 +1019,7 @@ SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
         */
        if (++devc->num_frames == devc->frame_limit) {
                sdi->driver->dev_acquisition_stop(sdi);
+               hmo_cleanup_logic_data(devc);
        } else {
                devc->current_channel = devc->enabled_channels;
                hmo_request_data(sdi);
index 24deb3f759ae99b39e8d720d6250f3630093f08d..b251bc823b3aadfe147af3070c7a2637d5bfb3ec 100644 (file)
@@ -103,6 +103,9 @@ struct dev_context {
        uint64_t num_frames;
 
        uint64_t frame_limit;
+
+       size_t pod_count;
+       GByteArray *logic_data;
 };
 
 SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi);