]> sigrok.org Git - libsigrok.git/commitdiff
Add new triggering framework.
authorBert Vermeulen <redacted>
Thu, 22 May 2014 23:21:58 +0000 (01:21 +0200)
committerBert Vermeulen <redacted>
Tue, 27 May 2014 21:53:27 +0000 (23:53 +0200)
The new triggers consist of a set of structs and an API to manipulate
them.  Both logic and analog triggers are supported, in an unlimited
number of stages.

A single struct sr_trigger containing its stages and triggers is then
added to the session.

In case of a driver where the hardware supports triggering, the struct
is then converted and used to arm the hardware trigger. Drivers without
hardware trigger support, such as fx2lafw or multimeter drivers, use it
as the basis for a software-based trigger implementation instead.

Makefile.am
device.c
libsigrok-internal.h
libsigrok.h
proto.h
session.c
trigger.c [new file with mode: 0644]

index dbe46665e7d5c3f8248de7dfb6a04838083a5978..39423f54ab0d8b6a1ce47c5db376ef0487250667 100644 (file)
@@ -32,6 +32,7 @@ libsigrok_la_SOURCES = \
        session_file.c \
        session_driver.c \
        hwdriver.c \
+       trigger.c \
        strutil.c \
        log.c \
        version.c \
index f87bb66dada542edacef70a94077e62566fae193..889f02df6e37ac01f4a0e9cea00564be2b8ebdda 100644 (file)
--- a/device.c
+++ b/device.c
@@ -306,7 +306,6 @@ SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
        for (l = sdi->channels; l; l = l->next) {
                ch = l->data;
                g_free(ch->name);
-               g_free(ch->trigger);
                g_free(ch);
        }
        g_slist_free(sdi->channels);
index eb4b1a2cf862d859c50352f29a7e7773c8434ed3..008fc4f386cad5dee2737d6b932110ecb9f8dea2 100644 (file)
@@ -228,8 +228,6 @@ SR_PRIV int sr_err(const char *format, ...);
 enum {
        /** The enabled state of the channel has been changed. */
        SR_CHANNEL_SET_ENABLED = 1 << 0,
-       /** The trigger setup of the channel has been changed. */
-       SR_CHANNEL_SET_TRIGGER = 1 << 1,
 };
 
 SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
@@ -274,6 +272,7 @@ struct sr_session {
        GSList *devs;
        /** List of struct datafeed_callback pointers. */
        GSList *datafeed_callbacks;
+       struct sr_trigger *trigger;
        GTimeVal starttime;
        gboolean running;
 
@@ -304,6 +303,7 @@ SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
                const struct sr_datafeed_packet *packet);
 SR_PRIV int sr_session_stop_sync(void);
 SR_PRIV int sr_sessionfile_check(const char *filename);
+SR_PRIV struct sr_trigger *sr_session_trigger_get(void);
 
 /*--- std.c -----------------------------------------------------------------*/
 
index abcc28958fbb1a85085105cb73d0481560f615e6..ade8277151c4e1711f4a66d7e184ea0474bad0d0 100644 (file)
@@ -304,6 +304,59 @@ enum sr_mqflag {
        SR_MQFLAG_AVG = 0x40000,
 };
 
+enum sr_trigger_matches {
+       SR_TRIGGER_ZERO = 1,
+       SR_TRIGGER_ONE,
+       SR_TRIGGER_RISING,
+       SR_TRIGGER_FALLING,
+       SR_TRIGGER_EDGE,
+       SR_TRIGGER_OVER,
+       SR_TRIGGER_UNDER,
+};
+
+/** The representation of a trigger, consisting of one or more stages
+ * containing one or more matches on a channel.
+ */
+struct sr_trigger {
+       /** A name for this trigger. This may be NULL if none is needed. */
+       char *name;
+       /** List of pointers to struct sr_trigger_stage. */
+       GSList *stages;
+};
+
+/** A trigger stage. */
+struct sr_trigger_stage {
+       /** Starts at 0. */
+       int stage;
+       /** List of pointers to struct sr_trigger_match. */
+       GSList *matches;
+};
+
+/** A channel to match and what to match it on. */
+struct sr_trigger_match {
+       /** The channel to trigger on. */
+       struct sr_channel *channel;
+       /** The trigger match to use.
+        * For logic channels, only the following matches may be used:
+        * SR_TRIGGER_ZERO
+        * SR_TRIGGER_ONE
+        * SR_TRIGGER_RISING
+        * SR_TRIGGER_FALLING
+        * SR_TRIGGER_EDGE
+        *
+        * For analog channels, only these matches may be used:
+        * SR_TRIGGER_RISING
+        * SR_TRIGGER_FALLING
+        * SR_TRIGGER_OVER
+        * SR_TRIGGER_UNDER
+        *
+        */
+       int match;
+       /** If the trigger match is one of SR_TRIGGER_OVER or SR_TRIGGER_UNDER,
+        * this contains the value to compare against. */
+       float value;
+};
+
 /**
  * @struct sr_context
  * Opaque structure representing a libsigrok context.
@@ -535,7 +588,8 @@ enum sr_channeltype {
 
 /** Information on single channel. */
 struct sr_channel {
-       /** Number of channels, starting at 0. */
+       /** The index of this channel, starting at 0. Logic channels will
+        * be encoded according to this index in SR_DF_LOGIC packets. */
        int index;
        /** Channel type (SR_CHANNEL_LOGIC, ...) */
        int type;
@@ -543,8 +597,6 @@ struct sr_channel {
        gboolean enabled;
        /** Name of channel. */
        char *name;
-       /** Trigger string, format like used by sigrok-cli */
-       char *trigger;
 };
 
 /** Structure for groups of channels that have common properties. */
diff --git a/proto.h b/proto.h
index 49353d55c10533eec1d470c5f0fbc4da4c40d168..2a2b9a6a397f24e7718991a53db7fb5acfe7c2ec 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -90,6 +90,7 @@ SR_API int sr_session_destroy(void);
 SR_API int sr_session_dev_remove_all(void);
 SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi);
 SR_API int sr_session_dev_list(GSList **devlist);
+SR_API int sr_session_trigger_set(struct sr_trigger *trig);
 
 /* Datafeed setup */
 SR_API int sr_session_datafeed_callback_remove_all(void);
@@ -129,6 +130,14 @@ SR_API int sr_output_send(struct sr_output *o,
                const struct sr_datafeed_packet *packet, GString **out);
 SR_API int sr_output_free(struct sr_output *o);
 
+/*--- trigger.c -------------------------------------------------------------*/
+
+SR_API struct sr_trigger *sr_trigger_new(char *name);
+SR_API void sr_trigger_free(struct sr_trigger *trig);
+SR_API struct sr_trigger_stage *sr_trigger_stage_new(struct sr_trigger *trig);
+SR_API int sr_trigger_match_add(struct sr_trigger_stage *stage,
+               struct sr_channel *ch, int trigger_match, float value);
+
 /*--- strutil.c -------------------------------------------------------------*/
 
 SR_API char *sr_si_string_u64(uint64_t x, const char *unit);
index 0540942f5f53ea053391e495595505f255a9a77a..742619a684272115729d428679794ce7b62c672c 100644 (file)
--- a/session.c
+++ b/session.c
@@ -292,6 +292,18 @@ SR_API int sr_session_datafeed_callback_add(sr_datafeed_callback cb, void *cb_da
        return SR_OK;
 }
 
+SR_PRIV struct sr_trigger *sr_session_trigger_get(void)
+{
+       return session->trigger;
+}
+
+SR_API int sr_session_trigger_set(struct sr_trigger *trig)
+{
+       session->trigger = trig;
+
+       return SR_OK;
+}
+
 /**
  * Call every device in the session's callback.
  *
@@ -347,6 +359,42 @@ static int sr_session_iteration(gboolean block)
        return SR_OK;
 }
 
+
+static int verify_trigger(struct sr_trigger *trigger)
+{
+       struct sr_trigger_stage *stage;
+       struct sr_trigger_match *match;
+       GSList *l, *m;
+
+       if (!trigger->stages) {
+               sr_err("No trigger stages defined.");
+               return SR_ERR;
+       }
+
+       sr_spew("Checking trigger:");
+       for (l = trigger->stages; l; l = l->next) {
+               stage = l->data;
+               if (!stage->matches) {
+                       sr_err("Stage %d has no matches defined.", stage->stage);
+                       return SR_ERR;
+               }
+               for (m = stage->matches; m; m = m->next) {
+                       match = m->data;
+                       if (!match->channel) {
+                               sr_err("Stage %d match has no channel.", stage->stage);
+                               return SR_ERR;
+                       }
+                       if (!match->match) {
+                               sr_err("Stage %d match is not defined.", stage->stage);
+                               return SR_ERR;
+                       }
+                       sr_spew("Stage %d match on channel %s, match %d", stage->stage,
+                                       match->channel->name, match->match);
+               }
+       }
+
+       return SR_OK;
+}
 /**
  * Start a session.
  *
@@ -375,6 +423,9 @@ SR_API int sr_session_start(void)
                return SR_ERR_BUG;
        }
 
+       if (session->trigger && verify_trigger(session->trigger) != SR_OK)
+               return SR_ERR;
+
        sr_info("Starting.");
 
        ret = SR_OK;
diff --git a/trigger.c b/trigger.c
new file mode 100644 (file)
index 0000000..97a7ef6
--- /dev/null
+++ b/trigger.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/* * @cond PRIVATE */
+#define LOG_PREFIX "trigger"
+/* * @endcond */
+   
+SR_API struct sr_trigger *sr_trigger_new(char *name)
+{
+       struct sr_trigger *trig;
+
+       trig = g_malloc0(sizeof(struct sr_trigger));
+       if (name)
+               trig->name = g_strdup(name);
+
+       return trig;
+}
+
+SR_API void sr_trigger_free(struct sr_trigger *trig)
+{
+       struct sr_trigger_stage *stage;
+       GSList *l;
+
+       for (l = trig->stages; l; l = l->next) {
+               stage = l->data;
+               g_slist_free_full(stage->matches, g_free);
+       }
+       g_slist_free_full(trig->stages, (GDestroyNotify)g_slist_free);
+
+       g_free(trig->name);
+       g_free(trig);
+}
+
+SR_API struct sr_trigger_stage *sr_trigger_stage_new(struct sr_trigger *trig)
+{
+       struct sr_trigger_stage *stage;
+
+       stage = g_malloc0(sizeof(struct sr_trigger_stage));
+       stage->stage = g_slist_length(trig->stages);
+       trig->stages = g_slist_append(trig->stages, stage);
+
+       return stage;
+}
+
+SR_API int sr_trigger_match_add(struct sr_trigger_stage *stage,
+               struct sr_channel *ch, int trigger_match, float value)
+{
+       struct sr_trigger_match *match;
+
+       if (ch->type == SR_CHANNEL_LOGIC) {
+               if (trigger_match != SR_TRIGGER_ZERO &&
+                               trigger_match != SR_TRIGGER_ONE &&
+                               trigger_match != SR_TRIGGER_RISING &&
+                               trigger_match != SR_TRIGGER_FALLING &&
+                               trigger_match != SR_TRIGGER_EDGE) {
+                       sr_err("Invalid trigger match for a logic channel.");
+                       return SR_ERR_ARG;
+               }
+
+
+       } else if (ch->type == SR_CHANNEL_ANALOG) {
+               if (trigger_match != SR_TRIGGER_FALLING &&
+                               trigger_match != SR_TRIGGER_OVER &&
+                               trigger_match != SR_TRIGGER_UNDER) {
+                       sr_err("Invalid trigger match for an analog channel.");
+                       return SR_ERR_ARG;
+               }
+       }
+
+       match = g_malloc0(sizeof(struct sr_trigger_match));
+       match->channel = ch;
+       match->match = trigger_match;
+       match->value = value;
+       stage->matches = g_slist_append(stage->matches, match);
+
+       return SR_OK;
+}