From: Bert Vermeulen Date: Thu, 22 May 2014 23:21:58 +0000 (+0200) Subject: Add new triggering framework. X-Git-Tag: libsigrok-0.4.0~1311 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=7b5e6d2978b9fe7afa952b7fa9f8837c87e8ed26;p=libsigrok.git Add new triggering framework. 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. --- diff --git a/Makefile.am b/Makefile.am index dbe46665..39423f54 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,7 @@ libsigrok_la_SOURCES = \ session_file.c \ session_driver.c \ hwdriver.c \ + trigger.c \ strutil.c \ log.c \ version.c \ diff --git a/device.c b/device.c index f87bb66d..889f02df 100644 --- 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); diff --git a/libsigrok-internal.h b/libsigrok-internal.h index eb4b1a2c..008fc4f3 100644 --- a/libsigrok-internal.h +++ b/libsigrok-internal.h @@ -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 -----------------------------------------------------------------*/ diff --git a/libsigrok.h b/libsigrok.h index abcc2895..ade82771 100644 --- a/libsigrok.h +++ b/libsigrok.h @@ -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 49353d55..2a2b9a6a 100644 --- 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); diff --git a/session.c b/session.c index 0540942f..742619a6 100644 --- 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 index 00000000..97a7ef68 --- /dev/null +++ b/trigger.c @@ -0,0 +1,96 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2014 Bert Vermeulen + * + * 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 . + */ + +#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; +}