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; +}