Skip to content

Commit 5c52d96

Browse files
committed
output/srzip: accept arbitrary input and output unit sizes
Commit c03aaf3 introduced a check and refused to store sample data when the feed would not exactly match an expected width that was derived from the device's or input's total count of logic channels. Earlier versions assumed the match but never checked (immediately forwarded session feed content to the ZIP archive). Existing applications may not be prepared to process the resulting archive where meta data and samples disagree on essential properties. The fatal condition aborted execution, which was perceived as a regression. A message was added later to communicate that the condition was hit, but its WARN severity was misleading, and its meaning still was obscure to users. This commit extends the reception of sample data in the session feed and its accumulation in the local buffer before ZIP archive appends. Any combination of input and output unit sizes are accepted. It's perfectly legal for sources to not communicate data for disabled channels, as well as to communicate wider data images than strictly necessary to simplify their support for a variety of input formats or device models. Details are available to users at higher log levels (INFO). Default levels only communicate fatal conditions (which should be implementation flaws now exclusively). The issue reproduces especially well with input formats that are rather flexible, or device drivers which support a range of devices with many configurations or models of differing capabilities. The issue was most recently reported for the OLS driver and an Arduino SUMP firmware. Given how many input modules and device drivers can feed into a few output modules, it's assumed that addressing the general issue in a common location is preferrable over local adjustment of individual input modules or device drivers. Adjusting both places doesn't harm either, increases overall robustness. The implementation results in a negligable runtime overhead for the regular case of matching unit sizes (a few integer checks). And an acceptable overhead when the session feed is wider than the srzip archive's unit size (multiple memcpy() calls where previously was only one which would have been incorrect without the consistency check). The code path which needs to apply padding to the output is most expensive, but the implementation is only as expensive as it needs to be. The added cost only occurs in the case of mismatches, which were not handled at all before this change. The combination of extensive diagnostics and internal consistency checks shall increase robustness and help during future maintenance. Reported-By: Pavel Fedin <[email protected]>
1 parent 7bf35e6 commit 5c52d96

File tree

1 file changed

+55
-7
lines changed

1 file changed

+55
-7
lines changed

src/output/srzip.c

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,38 +396,86 @@ static int zip_append(const struct sr_output *o,
396396
* @returns SR_OK et al error codes.
397397
*/
398398
static int zip_append_queue(const struct sr_output *o,
399-
const uint8_t *buf, size_t unitsize, size_t length,
399+
const uint8_t *buf, size_t feed_unitsize, size_t length,
400400
gboolean flush)
401401
{
402+
static gboolean sizes_seen;
403+
402404
struct out_context *outc;
403405
struct logic_buff *buff;
406+
size_t sample_copy_size, sample_skip_size, sample_pad_size;
404407
size_t send_count, remain, copy_count;
405408
const uint8_t *rdptr;
406409
uint8_t *wrptr;
407410
int ret;
408411

412+
/*
413+
* Check input parameters. Prepare to either grab data as is,
414+
* or to adjust between differing input and output unit sizes.
415+
* Diagnostics is rate limited for improved usability, assumes
416+
* that session feeds are consistent across calls. Processing
417+
* would cope with inconsistent calls though when required.
418+
*/
409419
outc = o->priv;
410420
buff = &outc->logic_buff;
411-
if (length && unitsize != buff->zip_unit_size) {
412-
sr_warn("Unexpected unit size, discarding logic data.");
413-
return SR_ERR_ARG;
421+
if (length) {
422+
if (!sizes_seen) {
423+
sr_info("output unit size %zu, feed unit size %zu.",
424+
buff->zip_unit_size, feed_unitsize);
425+
}
426+
if (feed_unitsize > buff->zip_unit_size) {
427+
if (!sizes_seen)
428+
sr_info("Large unit size, discarding excess logic data.");
429+
sample_copy_size = buff->zip_unit_size;
430+
sample_skip_size = feed_unitsize - buff->zip_unit_size;
431+
sample_pad_size = 0;
432+
} else if (feed_unitsize < buff->zip_unit_size) {
433+
if (!sizes_seen)
434+
sr_info("Small unit size, padding logic data.");
435+
sample_copy_size = feed_unitsize;
436+
sample_skip_size = 0;
437+
sample_pad_size = buff->zip_unit_size - feed_unitsize;
438+
} else {
439+
if (!sizes_seen)
440+
sr_dbg("Matching unit size, passing logic data as is.");
441+
sample_copy_size = buff->zip_unit_size;
442+
sample_skip_size = 0;
443+
sample_pad_size = 0;
444+
}
445+
if (sample_copy_size + sample_skip_size != feed_unitsize) {
446+
sr_err("Inconsistent input unit size. Implementation flaw?");
447+
return SR_ERR_BUG;
448+
}
449+
if (sample_copy_size + sample_pad_size != buff->zip_unit_size) {
450+
sr_err("Inconsistent output unit size. Implementation flaw?");
451+
return SR_ERR_BUG;
452+
}
453+
sizes_seen = TRUE;
414454
}
415455

416456
/*
417457
* Queue most recently received samples to the local buffer.
418458
* Flush to the ZIP archive when the buffer space is exhausted.
419459
*/
420460
rdptr = buf;
421-
send_count = buff->zip_unit_size ? length / buff->zip_unit_size : 0;
461+
send_count = feed_unitsize ? length / feed_unitsize : 0;
422462
while (send_count) {
423463
remain = buff->alloc_size - buff->fill_size;
424464
if (remain) {
425465
wrptr = &buff->samples[buff->fill_size * buff->zip_unit_size];
426466
copy_count = MIN(send_count, remain);
467+
if (sample_skip_size || sample_pad_size)
468+
copy_count = 1;
427469
send_count -= copy_count;
428470
buff->fill_size += copy_count;
429-
memcpy(wrptr, rdptr, copy_count * buff->zip_unit_size);
430-
rdptr += copy_count * buff->zip_unit_size;
471+
memcpy(wrptr, rdptr, copy_count * sample_copy_size);
472+
if (sample_pad_size) {
473+
wrptr += sample_copy_size;
474+
memset(wrptr, 0, sample_pad_size);
475+
}
476+
rdptr += copy_count * sample_copy_size;
477+
if (sample_skip_size)
478+
rdptr += sample_skip_size;
431479
remain -= copy_count;
432480
}
433481
if (send_count && !remain) {

0 commit comments

Comments
 (0)