]> sigrok.org Git - libsigrok.git/commitdiff
fx2lafw: Imported software triggering from fx2lafw
authorJoel Holdsworth <redacted>
Wed, 21 Mar 2012 20:42:41 +0000 (20:42 +0000)
committerJoel Holdsworth <redacted>
Wed, 21 Mar 2012 22:47:25 +0000 (22:47 +0000)
hardware/fx2lafw/fx2lafw.c
hardware/fx2lafw/fx2lafw.h

index 3ad0d671ebe3dc40c8f9202d5e7db49510c050f3..44716c99415de54dca8fa4aa906391dab73b922e 100644 (file)
@@ -243,6 +243,50 @@ static void close_dev(struct sr_dev_inst *sdi)
        sdi->status = SR_ST_INACTIVE;
 }
 
+static int configure_probes(struct context *ctx, GSList *probes)
+{
+       struct sr_probe *probe;
+       GSList *l;
+       int probe_bit, stage, i;
+       char *tc;
+
+       for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
+               ctx->trigger_mask[i] = 0;
+               ctx->trigger_value[i] = 0;
+       }
+
+       stage = -1;
+       for (l = probes; l; l = l->next) {
+               probe = (struct sr_probe *)l->data;
+               if (probe->enabled == FALSE)
+                       continue;
+               probe_bit = 1 << (probe->index - 1);
+               if (!(probe->trigger))
+                       continue;
+
+               stage = 0;
+               for (tc = probe->trigger; *tc; tc++) {
+                       ctx->trigger_mask[stage] |= probe_bit;
+                       if (*tc == '1')
+                               ctx->trigger_value[stage] |= probe_bit;
+                       stage++;
+                       if (stage > NUM_TRIGGER_STAGES)
+                               return SR_ERR;
+               }
+       }
+
+       if (stage == -1)
+               /*
+                * We didn't configure any triggers, make sure acquisition
+                * doesn't wait for any.
+                */
+               ctx->trigger_stage = TRIGGER_FIRED;
+       else
+               ctx->trigger_stage = 0;
+
+       return SR_OK;
+}
+
 static struct context *fx2lafw_device_new(void)
 {
        struct context *ctx;
@@ -252,6 +296,8 @@ static struct context *fx2lafw_device_new(void)
                return NULL;
        }
 
+       ctx->trigger_stage = TRIGGER_FIRED;
+
        return ctx;
 }
 
@@ -500,7 +546,7 @@ static int hw_dev_config_set(int dev_index, int hwcap, void *value)
                ctx->cur_samplerate = *(uint64_t *)value;
                ret = SR_OK;
        } else if (hwcap == SR_HWCAP_PROBECONFIG) {
-               ret = SR_OK;
+               ret = configure_probes(ctx, (GSList *) value);
        } else if (hwcap == SR_HWCAP_LIMIT_SAMPLES) {
                ctx->limit_samples = *(uint64_t *)value;
                ret = SR_OK;
@@ -545,7 +591,7 @@ static void receive_transfer(struct libusb_transfer *transfer)
        struct sr_datafeed_packet packet;
        struct sr_datafeed_logic logic;
        struct context *ctx = transfer->user_data;
-       int cur_buflen;
+       int cur_buflen, trigger_offset, i;
        unsigned char *cur_buf, *new_buf;
 
        /*
@@ -594,19 +640,81 @@ static void receive_transfer(struct libusb_transfer *transfer)
                empty_transfer_count = 0;
        }
 
-       /* Send the incoming transfer to the session bus. */
-       packet.type = SR_DF_LOGIC;
-       packet.payload = &logic;
-       logic.length = cur_buflen;
-       logic.unitsize = 1;
-       logic.data = cur_buf;
-       sr_session_send(ctx->session_dev_id, &packet);
-       g_free(cur_buf);
+       trigger_offset = 0;
+       if (ctx->trigger_stage >= 0) {
+               for (i = 0; i < cur_buflen; i++) {
+
+                       if ((cur_buf[i] & ctx->trigger_mask[ctx->trigger_stage]) == ctx->trigger_value[ctx->trigger_stage]) {
+                               /* Match on this trigger stage. */
+                               ctx->trigger_buffer[ctx->trigger_stage] = cur_buf[i];
+                               ctx->trigger_stage++;
+
+                               if (ctx->trigger_stage == NUM_TRIGGER_STAGES || ctx->trigger_mask[ctx->trigger_stage] == 0) {
+                                       /* Match on all trigger stages, we're done. */
+                                       trigger_offset = i + 1;
+
+                                       /*
+                                        * TODO: Send pre-trigger buffer to session bus.
+                                        * Tell the frontend we hit the trigger here.
+                                        */
+                                       packet.type = SR_DF_TRIGGER;
+                                       packet.payload = NULL;
+                                       sr_session_send(ctx->session_dev_id, &packet);
+
+                                       /*
+                                        * Send the samples that triggered it, since we're
+                                        * skipping past them.
+                                        */
+                                       packet.type = SR_DF_LOGIC;
+                                       packet.payload = &logic;
+                                       logic.length = ctx->trigger_stage;
+                                       logic.unitsize = 1;
+                                       logic.data = ctx->trigger_buffer;
+                                       sr_session_send(ctx->session_dev_id, &packet);
+
+                                       ctx->trigger_stage = TRIGGER_FIRED;
+                                       break;
+                               }
+                               return;
+                       }
+
+                       /*
+                        * We had a match before, but not in the next sample. However, we may
+                        * have a match on this stage in the next bit -- trigger on 0001 will
+                        * fail on seeing 00001, so we need to go back to stage 0 -- but at
+                        * the next sample from the one that matched originally, which the
+                        * counter increment at the end of the loop takes care of.
+                        */
+                       if (ctx->trigger_stage > 0) {
+                               i -= ctx->trigger_stage;
+                               if (i < -1)
+                                       i = -1; /* Oops, went back past this buffer. */
+                               /* Reset trigger stage. */
+                               ctx->trigger_stage = 0;
+                       }
+               }
+       }
 
-       ctx->num_samples += cur_buflen;
-       if (ctx->limit_samples &&
-               (unsigned int) ctx->num_samples > ctx->limit_samples) {
-               abort_acquisition(ctx);
+       if (ctx->trigger_stage == TRIGGER_FIRED) {
+               /* Send the incoming transfer to the session bus. */
+               packet.type = SR_DF_LOGIC;
+               packet.payload = &logic;
+               logic.length = cur_buflen - trigger_offset;
+               logic.unitsize = 1;
+               logic.data = cur_buf + trigger_offset;
+               sr_session_send(ctx->session_dev_id, &packet);
+               g_free(cur_buf);
+
+               ctx->num_samples += cur_buflen;
+               if (ctx->limit_samples &&
+                       (unsigned int)ctx->num_samples > ctx->limit_samples) {
+                       abort_acquisition(ctx);
+               }
+       } else {
+               /*
+                * TODO: Buffer pre-trigger data in capture
+                * ratio-sized buffer.
+                */
        }
 }
 
index e124f8e9ac7d80d60f6312d74efd7e6e14a3c572..310a55d217b88e67226f744a8e77e51f54d7de86 100644 (file)
 
 #define USB_INTERFACE          0
 #define USB_CONFIGURATION      1
-#define TRIGGER_TYPES          "01rf"
+#define NUM_TRIGGER_STAGES     4
+#define TRIGGER_TYPES          "01"
 
 #define MAX_RENUM_DELAY                3000 /* ms */
 #define NUM_SIMUL_TRANSFERS    32
 #define MAX_EMPTY_TRANSFERS    (NUM_SIMUL_TRANSFERS * 2)
 
+/* Software trigger implementation: positive values indicate trigger stage. */
+#define TRIGGER_FIRED          -1
+
 struct fx2lafw_profile {
        uint16_t vid;
        uint16_t pid;
@@ -56,6 +60,11 @@ struct context {
        uint64_t cur_samplerate;
        uint64_t limit_samples;
 
+       uint8_t trigger_mask[NUM_TRIGGER_STAGES];
+       uint8_t trigger_value[NUM_TRIGGER_STAGES];
+       int trigger_stage;
+       uint8_t trigger_buffer[NUM_TRIGGER_STAGES];
+
        int num_samples;
 
        void *session_dev_id;