From: Aurelien Jacobs Date: Tue, 25 Nov 2014 11:23:34 +0000 (+0100) Subject: soft-trigger: Add support for pre-triggering. X-Git-Tag: libsigrok-0.4.0~709 X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=commitdiff_plain;h=fe5a735553470fe372ff1c12eb55398bd0f098b8 soft-trigger: Add support for pre-triggering. --- diff --git a/src/hardware/beaglelogic/api.c b/src/hardware/beaglelogic/api.c index 46abde3d..3c8cc3b3 100644 --- a/src/hardware/beaglelogic/api.c +++ b/src/hardware/beaglelogic/api.c @@ -361,7 +361,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, /* Configure triggers & send header packet */ if ((trigger = sr_session_trigger_get(sdi->session))) { - devc->stl = soft_trigger_logic_new(sdi, trigger); + devc->stl = soft_trigger_logic_new(sdi, trigger, 0); devc->trigger_fired = FALSE; } else devc->trigger_fired = TRUE; diff --git a/src/hardware/beaglelogic/protocol.c b/src/hardware/beaglelogic/protocol.c index 1c01b64f..05dcccf1 100644 --- a/src/hardware/beaglelogic/protocol.c +++ b/src/hardware/beaglelogic/protocol.c @@ -67,9 +67,7 @@ SR_PRIV int beaglelogic_receive_data(int fd, int revents, void *cb_data) } else { /* Check for trigger */ trigger_offset = soft_trigger_logic_check(devc->stl, - logic.data, - packetsize); - + logic.data, packetsize, NULL); if (trigger_offset > -1) { trigger_offset *= logic.unitsize; logic.length = MIN(packetsize - trigger_offset, diff --git a/src/hardware/fx2lafw/api.c b/src/hardware/fx2lafw/api.c index 7559f437..796749a3 100644 --- a/src/hardware/fx2lafw/api.c +++ b/src/hardware/fx2lafw/api.c @@ -567,7 +567,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) devc->empty_transfer_count = 0; if ((trigger = sr_session_trigger_get(sdi->session))) { - devc->stl = soft_trigger_logic_new(sdi, trigger); + devc->stl = soft_trigger_logic_new(sdi, trigger, 0); devc->trigger_fired = FALSE; } else devc->trigger_fired = TRUE; diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c index 1a623ec6..d1d2d6a6 100644 --- a/src/hardware/fx2lafw/protocol.c +++ b/src/hardware/fx2lafw/protocol.c @@ -458,7 +458,7 @@ SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer) } } else { trigger_offset = soft_trigger_logic_check(devc->stl, - transfer->buffer, transfer->actual_length); + transfer->buffer, transfer->actual_length, NULL); if (trigger_offset > -1) { packet.type = SR_DF_LOGIC; packet.payload = &logic; diff --git a/src/hardware/saleae-logic16/api.c b/src/hardware/saleae-logic16/api.c index c30900b2..3ab979d8 100644 --- a/src/hardware/saleae-logic16/api.c +++ b/src/hardware/saleae-logic16/api.c @@ -719,7 +719,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) memset(devc->channel_data, 0, sizeof(devc->channel_data)); if ((trigger = sr_session_trigger_get(sdi->session))) { - devc->stl = soft_trigger_logic_new(sdi, trigger); + devc->stl = soft_trigger_logic_new(sdi, trigger, 0); devc->trigger_fired = FALSE; } else devc->trigger_fired = TRUE; diff --git a/src/hardware/saleae-logic16/protocol.c b/src/hardware/saleae-logic16/protocol.c index bf71ea60..ac0316d4 100644 --- a/src/hardware/saleae-logic16/protocol.c +++ b/src/hardware/saleae-logic16/protocol.c @@ -785,7 +785,7 @@ SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer) devc->sent_samples += new_samples; } else { trigger_offset = soft_trigger_logic_check(devc->stl, - devc->convbuffer, new_samples * 2); + devc->convbuffer, new_samples * 2, NULL); if (trigger_offset > -1) { packet.type = SR_DF_LOGIC; packet.payload = &logic; diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index e61fb464..a8d680eb 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -646,13 +646,18 @@ struct soft_trigger_logic { int unitsize; int cur_stage; uint8_t *prev_sample; + uint8_t *pre_trigger_buffer; + uint8_t *pre_trigger_head; + int pre_trigger_size; + int pre_trigger_fill; }; SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new( - const struct sr_dev_inst *sdi, struct sr_trigger *trigger); + const struct sr_dev_inst *sdi, struct sr_trigger *trigger, + int pre_trigger_samples); SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *st); SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *st, uint8_t *buf, - int len); + int len, int *pre_trigger_samples); /*--- hardware/serial.c -----------------------------------------------------*/ diff --git a/src/soft-trigger.c b/src/soft-trigger.c index 386f8cc6..107e6219 100644 --- a/src/soft-trigger.c +++ b/src/soft-trigger.c @@ -26,7 +26,8 @@ /* @endcond */ SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new( - const struct sr_dev_inst *sdi, struct sr_trigger *trigger) + const struct sr_dev_inst *sdi, struct sr_trigger *trigger, + int pre_trigger_samples) { struct soft_trigger_logic *stl; @@ -35,16 +36,83 @@ SR_PRIV struct soft_trigger_logic *soft_trigger_logic_new( stl->trigger = trigger; stl->unitsize = (g_slist_length(sdi->channels) + 7) / 8; stl->prev_sample = g_malloc0(stl->unitsize); + stl->pre_trigger_size = stl->unitsize * pre_trigger_samples; + stl->pre_trigger_buffer = g_malloc(stl->pre_trigger_size); + stl->pre_trigger_head = stl->pre_trigger_buffer; + + if (stl->pre_trigger_size > 0 && stl->pre_trigger_buffer == NULL) { + soft_trigger_logic_free(stl); + return NULL; + } return stl; } SR_PRIV void soft_trigger_logic_free(struct soft_trigger_logic *stl) { + g_free(stl->pre_trigger_buffer); g_free(stl->prev_sample); g_free(stl); } +static void pre_trigger_append(struct soft_trigger_logic *stl, + uint8_t *buf, int len) +{ + /* Avoid uselessly copying more than the pre-trigger size. */ + if (len > stl->pre_trigger_size) { + buf += len - stl->pre_trigger_size; + len = stl->pre_trigger_size; + } + + /* Update the filling level of the pre-trigger circular buffer. */ + stl->pre_trigger_fill = MIN(stl->pre_trigger_fill + len, + stl->pre_trigger_size); + + /* Actually copy data to the pre-trigger circular buffer. */ + while (len > 0) { + size_t size = MIN(stl->pre_trigger_buffer + stl->pre_trigger_size + - stl->pre_trigger_head, len); + memcpy(stl->pre_trigger_head, buf, size); + stl->pre_trigger_head += size; + if (stl->pre_trigger_head >= stl->pre_trigger_buffer + + stl->pre_trigger_size) + stl->pre_trigger_head = stl->pre_trigger_buffer; + buf += size; + len -= size; + } +} + +static void pre_trigger_send(struct soft_trigger_logic *stl, + int *pre_trigger_samples) +{ + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; + + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.unitsize = stl->unitsize; + + if (pre_trigger_samples) + *pre_trigger_samples = 0; + + /* If pre-trigger buffer not full, rewind head to the first valid sample. */ + if (stl->pre_trigger_fill < stl->pre_trigger_size) + stl->pre_trigger_head = stl->pre_trigger_buffer; + + /* Send logic packets for the pre-trigger circular buffer content. */ + while (stl->pre_trigger_fill > 0) { + size_t size = MIN(stl->pre_trigger_buffer + stl->pre_trigger_size + - stl->pre_trigger_head, stl->pre_trigger_fill); + logic.length = size; + logic.data = stl->pre_trigger_head; + sr_session_send(stl->sdi, &packet); + stl->pre_trigger_head = stl->pre_trigger_buffer; + stl->pre_trigger_fill -= size; + if (pre_trigger_samples) + *pre_trigger_samples += size / stl->unitsize; + } +} + static gboolean logic_check_match(struct soft_trigger_logic *stl, uint8_t *sample, struct sr_trigger_match *match) { @@ -80,7 +148,7 @@ static gboolean logic_check_match(struct soft_trigger_logic *stl, /* Returns the offset (in samples) within buf of where the trigger * occurred, or -1 if not triggered. */ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, - uint8_t *buf, int len) + uint8_t *buf, int len, int *pre_trigger_samples) { struct sr_datafeed_packet packet; struct sr_trigger_stage *stage; @@ -116,7 +184,11 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, /* Advance to next stage. */ stl->cur_stage++; } else { - /* Matched on last stage, fire trigger. */ + /* Matched on last stage, send pre-trigger data. */ + pre_trigger_append(stl, buf, i); + pre_trigger_send(stl, pre_trigger_samples); + + /* Fire trigger. */ offset = i / stl->unitsize; packet.type = SR_DF_TRIGGER; @@ -142,6 +214,9 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, } } + if (offset == -1) + pre_trigger_append(stl, buf, len); + return offset; }