X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fsoft-trigger.c;h=245eb4fff8c94ed652233de2676a341961eeb691;hb=a058de0410d21686c7cfe1795aa899a8f49ff71d;hp=386f8cc662ac4481ca4188f555ac09db78c45168;hpb=155b680da482cea2381becb73c51cfb838bff31e;p=libsigrok.git
diff --git a/src/soft-trigger.c b/src/soft-trigger.c
index 386f8cc6..245eb4ff 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 */
#define LOG_PREFIX "soft-trigger"
/* @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;
}
-