]> sigrok.org Git - libsigrok.git/blobdiff - src/output/srzip.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / output / srzip.c
index fb6d5a392e979c9cd894e70693c01366c5429701..3be0bccb29f3cd316095ad48d3895d570e4f6381 100644 (file)
@@ -38,7 +38,7 @@ struct out_context {
        size_t analog_ch_count;
        gint *analog_index_map;
        struct logic_buff {
-               size_t unit_size;
+               size_t zip_unit_size;
                size_t alloc_size;
                uint8_t *samples;
                size_t fill_size;
@@ -61,7 +61,7 @@ static int init(struct sr_output *o, GHashTable *options)
                return SR_ERR_ARG;
        }
 
-       outc = g_malloc0(sizeof(struct out_context));
+       outc = g_malloc0(sizeof(*outc));
        outc->filename = g_strdup(o->filename);
        o->priv = outc;
 
@@ -158,7 +158,7 @@ static int zip_create(const struct sr_output *o)
        g_key_file_set_integer(meta, devgroup, "total analog", enabled_analog_channels);
 
        outc->analog_ch_count = enabled_analog_channels;
-       alloc_size = sizeof(gint) * outc->analog_ch_count;
+       alloc_size = sizeof(gint) * outc->analog_ch_count + 1;
        outc->analog_index_map = g_malloc0(alloc_size);
 
        index = 0;
@@ -197,19 +197,25 @@ static int zip_create(const struct sr_output *o)
         * archive update calls, and decouple the srzip output module
         * from implementation details in other acquisition device
         * drivers and input modules.
+        *
+        * Avoid allocating zero bytes, to not depend on platform
+        * specific malloc(0) return behaviour. Avoid division by zero,
+        * holding a local buffer won't harm when no data is seen later
+        * during execution. This simplifies other locations.
         */
        alloc_size = CHUNK_SIZE;
-       outc->logic_buff.unit_size = logic_channels;
-       outc->logic_buff.unit_size += 8 - 1;
-       outc->logic_buff.unit_size /= 8;
+       outc->logic_buff.zip_unit_size = logic_channels;
+       outc->logic_buff.zip_unit_size += 8 - 1;
+       outc->logic_buff.zip_unit_size /= 8;
        outc->logic_buff.samples = g_try_malloc0(alloc_size);
        if (!outc->logic_buff.samples)
                return SR_ERR_MALLOC;
-       alloc_size /= outc->logic_buff.unit_size;
+       if (outc->logic_buff.zip_unit_size)
+               alloc_size /= outc->logic_buff.zip_unit_size;
        outc->logic_buff.alloc_size = alloc_size;
        outc->logic_buff.fill_size = 0;
 
-       alloc_size = sizeof(outc->analog_buff[0]) * outc->analog_ch_count;
+       alloc_size = sizeof(outc->analog_buff[0]) * outc->analog_ch_count + 1;
        outc->analog_buff = g_malloc0(alloc_size);
        for (index = 0; index < outc->analog_ch_count; index++) {
                alloc_size = CHUNK_SIZE;
@@ -390,50 +396,101 @@ static int zip_append(const struct sr_output *o,
  * @returns SR_OK et al error codes.
  */
 static int zip_append_queue(const struct sr_output *o,
-       uint8_t *buf, size_t unitsize, size_t length, gboolean flush)
+       const uint8_t *buf, size_t feed_unitsize, size_t length,
+       gboolean flush)
 {
+       static gboolean sizes_seen;
+
        struct out_context *outc;
        struct logic_buff *buff;
-       size_t send_size, remain, copy_size;
-       uint8_t *wrptr, *rdptr;
+       size_t sample_copy_size, sample_skip_size, sample_pad_size;
+       size_t send_count, remain, copy_count;
+       const uint8_t *rdptr;
+       uint8_t *wrptr;
        int ret;
 
+       /*
+        * Check input parameters. Prepare to either grab data as is,
+        * or to adjust between differing input and output unit sizes.
+        * Diagnostics is rate limited for improved usability, assumes
+        * that session feeds are consistent across calls. Processing
+        * would cope with inconsistent calls though when required.
+        */
        outc = o->priv;
        buff = &outc->logic_buff;
-       if (length && unitsize != buff->unit_size)
-               return SR_ERR_ARG;
+       if (length) {
+               if (!sizes_seen) {
+                       sr_info("output unit size %zu, feed unit size %zu.",
+                               buff->zip_unit_size, feed_unitsize);
+               }
+               if (feed_unitsize > buff->zip_unit_size) {
+                       if (!sizes_seen)
+                               sr_info("Large unit size, discarding excess logic data.");
+                       sample_copy_size = buff->zip_unit_size;
+                       sample_skip_size = feed_unitsize - buff->zip_unit_size;
+                       sample_pad_size = 0;
+               } else if (feed_unitsize < buff->zip_unit_size) {
+                       if (!sizes_seen)
+                               sr_info("Small unit size, padding logic data.");
+                       sample_copy_size = feed_unitsize;
+                       sample_skip_size = 0;
+                       sample_pad_size = buff->zip_unit_size - feed_unitsize;
+               } else {
+                       if (!sizes_seen)
+                               sr_dbg("Matching unit size, passing logic data as is.");
+                       sample_copy_size = buff->zip_unit_size;
+                       sample_skip_size = 0;
+                       sample_pad_size = 0;
+               }
+               if (sample_copy_size + sample_skip_size != feed_unitsize) {
+                       sr_err("Inconsistent input unit size. Implementation flaw?");
+                       return SR_ERR_BUG;
+               }
+               if (sample_copy_size + sample_pad_size != buff->zip_unit_size) {
+                       sr_err("Inconsistent output unit size. Implementation flaw?");
+                       return SR_ERR_BUG;
+               }
+               sizes_seen = TRUE;
+       }
 
        /*
         * Queue most recently received samples to the local buffer.
         * Flush to the ZIP archive when the buffer space is exhausted.
         */
        rdptr = buf;
-       send_size = length / buff->unit_size;
-       while (send_size) {
+       send_count = feed_unitsize ? length / feed_unitsize : 0;
+       while (send_count) {
                remain = buff->alloc_size - buff->fill_size;
+               wrptr = &buff->samples[buff->fill_size * buff->zip_unit_size];
                if (remain) {
-                       wrptr = &buff->samples[buff->fill_size * buff->unit_size];
-                       copy_size = MIN(send_size, remain);
-                       send_size -= copy_size;
-                       buff->fill_size += copy_size;
-                       memcpy(wrptr, rdptr, copy_size * buff->unit_size);
-                       rdptr += copy_size * buff->unit_size;
-                       remain -= copy_size;
+                       copy_count = MIN(send_count, remain);
+                       if (sample_skip_size || sample_pad_size)
+                               copy_count = 1;
+                       send_count -= copy_count;
+                       buff->fill_size += copy_count;
+                       memcpy(wrptr, rdptr, copy_count * sample_copy_size);
+                       if (sample_pad_size) {
+                               wrptr += sample_copy_size;
+                               memset(wrptr, 0, sample_pad_size);
+                       }
+                       rdptr += copy_count * sample_copy_size;
+                       if (sample_skip_size)
+                               rdptr += sample_skip_size;
+                       remain -= copy_count;
                }
-               if (send_size && !remain) {
-                       ret = zip_append(o, buff->samples, buff->unit_size,
-                               buff->fill_size * buff->unit_size);
+               if (send_count && !remain) {
+                       ret = zip_append(o, buff->samples, buff->zip_unit_size,
+                               buff->fill_size * buff->zip_unit_size);
                        if (ret != SR_OK)
                                return ret;
                        buff->fill_size = 0;
-                       remain = buff->alloc_size - buff->fill_size;
                }
        }
 
        /* Flush to the ZIP archive if the caller wants us to. */
        if (flush && buff->fill_size) {
-               ret = zip_append(o, buff->samples, buff->unit_size,
-                       buff->fill_size * buff->unit_size);
+               ret = zip_append(o, buff->samples, buff->zip_unit_size,
+                       buff->fill_size * buff->zip_unit_size);
                if (ret != SR_OK)
                        return ret;
                buff->fill_size = 0;
@@ -656,8 +713,9 @@ static int receive(const struct sr_output *o, const struct sr_datafeed_packet *p
                        outc->zip_created = TRUE;
                }
                logic = packet->payload;
-               ret = zip_append_queue(o, logic->data,
-                       logic->unitsize, logic->length, FALSE);
+               ret = zip_append_queue(o,
+                       logic->data, logic->unitsize, logic->length,
+                       FALSE);
                if (ret != SR_OK)
                        return ret;
                break;