X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fsoft-trigger.c;h=0c5bb466da416100719f617c397badf7f4ca8d63;hb=82b9f3d116ce0c982291a2dfdd15cd8a1c4cc16e;hp=386f8cc662ac4481ca4188f555ac09db78c45168;hpb=155b680da482cea2381becb73c51cfb838bff31e;p=libsigrok.git diff --git a/src/soft-trigger.c b/src/soft-trigger.c index 386f8cc6..0c5bb466 100644 --- a/src/soft-trigger.c +++ b/src/soft-trigger.c @@ -17,34 +17,127 @@ * along with this program. If not, see . */ +#include #include -#include "libsigrok.h" +#include #include "libsigrok-internal.h" -/* @cond PRIVATE */ +/** @cond PRIVATE */ #define LOG_PREFIX "soft-trigger" -/* @endcond */ +/** @endcond */ + +SR_PRIV int logic_channel_unitsize(GSList *channels) +{ + int number = 0; + struct sr_channel *channel; + GSList *l; + + for (l = channels; l; l = l->next) { + channel = l->data; + if (channel->type == SR_CHANNEL_LOGIC) + number++; + } + + return (number + 7) / 8; +} 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; stl = g_malloc0(sizeof(struct soft_trigger_logic)); stl->sdi = sdi; stl->trigger = trigger; - stl->unitsize = (g_slist_length(sdi->channels) + 7) / 8; + stl->unitsize = logic_channel_unitsize(sdi->channels); stl->prev_sample = g_malloc0(stl->unitsize); + stl->pre_trigger_size = stl->unitsize * pre_trigger_samples; + stl->pre_trigger_buffer = g_try_malloc(stl->pre_trigger_size); + if (pre_trigger_samples > 0 && !stl->pre_trigger_buffer) { + /* + * Error out if g_try_malloc() failed (or was invoked as + * g_try_malloc(0)) *and* more than 0 pretrigger samples + * were requested. + */ + soft_trigger_logic_free(stl); + return NULL; + } + 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 +173,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 +209,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 +239,8 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, } } + if (offset == -1) + pre_trigger_append(stl, buf, len); + return offset; } -