X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fsoft-trigger.c;h=50fdd41cec094999764311fc66475dcfbb1f91dc;hb=4555d3bda00ed6f12016d4aca28bbef3cb459988;hp=386f8cc662ac4481ca4188f555ac09db78c45168;hpb=155b680da482cea2381becb73c51cfb838bff31e;p=libsigrok.git diff --git a/src/soft-trigger.c b/src/soft-trigger.c index 386f8cc6..50fdd41c 100644 --- a/src/soft-trigger.c +++ b/src/soft-trigger.c @@ -17,8 +17,9 @@ * along with this program. If not, see . */ +#include #include -#include "libsigrok.h" +#include #include "libsigrok-internal.h" /* @cond PRIVATE */ @@ -26,7 +27,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 +37,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) { + 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 +149,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 +185,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 +215,8 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, } } + if (offset == -1) + pre_trigger_append(stl, buf, len); + return offset; } -