]> sigrok.org Git - libsigrok.git/commitdiff
soft-trigger: Add support for pre-triggering.
authorAurelien Jacobs <redacted>
Tue, 25 Nov 2014 11:23:34 +0000 (12:23 +0100)
committerAurelien Jacobs <redacted>
Tue, 25 Nov 2014 15:56:34 +0000 (16:56 +0100)
src/hardware/beaglelogic/api.c
src/hardware/beaglelogic/protocol.c
src/hardware/fx2lafw/api.c
src/hardware/fx2lafw/protocol.c
src/hardware/saleae-logic16/api.c
src/hardware/saleae-logic16/protocol.c
src/libsigrok-internal.h
src/soft-trigger.c

index 46abde3d881aa8e16a89e8272e7fb58efe5c9c19..3c8cc3b39f72c309c56cccaef94b04b06632285c 100644 (file)
@@ -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;
index 1c01b64f758405955e5715d3b9a4a67998b51c9d..05dcccf1ffac25bc0a1f0e3784e150f94bd68c7e 100644 (file)
@@ -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,
index 7559f437b5da0282209bd9f8280f5768e7e03c37..796749a34dbd0d3f004c7111654b6aa4e604f77f 100644 (file)
@@ -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;
index 1a623ec63de1698eb65e38193b6f1ca9d05c9855..d1d2d6a6df627710bea1e370a4bc859b1610d9ee 100644 (file)
@@ -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;
index c30900b2ccdea4abe111d61c8bee27de0aa763dc..3ab979d8134f7b336dca3b93481493c05c15e345 100644 (file)
@@ -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;
index bf71ea60f432908fe08399fe10ca55e334a0a58e..ac0316d4bd2bb86118a76e6b4951fccc09b59137 100644 (file)
@@ -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;
index e61fb464d4b7bb8ff4e4bfed4185bae0f4ca252a..a8d680ebcf45266ee1f5fcb902b8cc67cfd6de4c 100644 (file)
@@ -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 -----------------------------------------------------*/
 
index 386f8cc662ac4481ca4188f555ac09db78c45168..107e6219c58071597debddcc666c760577c622e6 100644 (file)
@@ -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;
 }