X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fsoft-trigger.c;h=1f81fae54e11575d226cb1fd0aaf9fc0ef9a9ddb;hp=386f8cc662ac4481ca4188f555ac09db78c45168;hb=22fdb67fa0714c11cc0a58ee1423f55d18a4f080;hpb=155b680da482cea2381becb73c51cfb838bff31e diff --git a/src/soft-trigger.c b/src/soft-trigger.c index 386f8cc6..1f81fae5 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,9 +173,8 @@ 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; struct sr_trigger_match *match; GSList *l, *l_stage; @@ -116,12 +208,14 @@ 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; - packet.payload = NULL; - sr_session_send(stl->sdi, &packet); + std_session_send_df_trigger(stl->sdi); break; } } else if (stl->cur_stage > 0) { @@ -142,6 +236,8 @@ SR_PRIV int soft_trigger_logic_check(struct soft_trigger_logic *stl, } } + if (offset == -1) + pre_trigger_append(stl, buf, len); + return offset; } -