summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorStefan Radomski <github@mintwerk.de>2017-04-30 20:51:38 (GMT)
committerStefan Radomski <github@mintwerk.de>2017-04-30 20:51:38 (GMT)
commit6e1d8d25d4e7b65ca67b5d5c529ba0bedb81feb9 (patch)
treeef48948b05c1947d10ed40cb7844f0cb6d6eb86e /apps
parent8015ce2701862e6977fe12cde839a35ddb4c32e5 (diff)
downloaduscxml-6e1d8d25d4e7b65ca67b5d5c529ba0bedb81feb9.zip
uscxml-6e1d8d25d4e7b65ca67b5d5c529ba0bedb81feb9.tar.gz
uscxml-6e1d8d25d4e7b65ca67b5d5c529ba0bedb81feb9.tar.bz2
Optimized ANSI-C transformation
Diffstat (limited to 'apps')
-rw-r--r--apps/arduino/WaterPump.cxx170
-rw-r--r--apps/arduino/WaterPump.scxml70
-rw-r--r--apps/arduino/stateMachine.c1291
3 files changed, 1531 insertions, 0 deletions
diff --git a/apps/arduino/WaterPump.cxx b/apps/arduino/WaterPump.cxx
new file mode 100644
index 0000000..01f4cfa
--- /dev/null
+++ b/apps/arduino/WaterPump.cxx
@@ -0,0 +1,170 @@
+// Resources:
+// https://www.avrprogrammers.com/howto/atmega328-power
+// https://github.com/PaulStoffregen/CapacitiveSensor
+// https://de.wikipedia.org/wiki/Faustformelverfahren_%28Automatisierungstechnik%29
+// http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/
+// google://SCC3 for conformal coating
+
+#include <LowPower.h>
+#include <CapacitiveSensor.h>
+
+
+#define USCXML_NO_HISTORY
+
+#define LED 13 // LED pin on the Arduino Nano
+#define LIGHT A7 // 1:10 voltage divider soldered into the solar panel
+#define LIGHT_THRES 300 // do not actuate beneath this brightness
+#define MEASURE_INTERVAL SLEEP_1S // time between cycles
+#define DARK_SLEEP_CYCLES 1
+
+#define PUMP_ON LOW // Setting an output to LOW will trigger the relais
+#define PUMP_OFF HIGH
+
+#define ROLLOFF 0.8 // exponential smoothing for sensor readings
+
+float soil[4] = { 0, 0, 0, 0 }; // smoothed sensor readings from the capacitive sensors
+int pump[4] = { A0, A1, A2, A3 }; // we abuse analog pins as digital output
+int activePump = -1;
+
+int thrs[4] = { 1400, 1400, 1400, 1400 }; // start pumping below these values
+
+CapacitiveSensor bed[4] = { // Pins where the capacitive sensors are connected
+ CapacitiveSensor(3, 2),
+ CapacitiveSensor(5, 4),
+ CapacitiveSensor(7, 6),
+ CapacitiveSensor(9, 8)
+};
+char readCapSense = 0; // Whether the capsense invoker is active
+
+struct data_t {
+ int light;
+};
+struct event_t {
+ const char* name;
+ struct data_t data;
+};
+
+// the various events
+long pumpRemain = 0;
+struct event_t _eventIdle = {
+ name: "idle"
+};
+struct event_t _eventLight = {
+ name: "light"
+};
+struct event_t _eventPump = {
+ name: "pump"
+};
+struct event_t* _event;
+
+#include "stateMachine.c"
+
+uscxml_ctx ctx;
+
+/* state chart is invoking something */
+static int invoke(const uscxml_ctx* ctx,
+ const uscxml_state* s,
+ const uscxml_elem_invoke* invocation,
+ unsigned char uninvoke) {
+ if (strcmp(invocation->type, "pump") == 0) {
+ int pumpId = atoi(invocation->id);
+ digitalWrite(pump[pumpId], uninvoke == 0 ? PUMP_ON : PUMP_OFF);
+ } else if (strcmp(invocation->type, "capsense") == 0) {
+ readCapSense = uninvoke;
+ }
+}
+
+/* is the event matching */
+static int matched(const uscxml_ctx* ctx,
+ const uscxml_transition* transition,
+ const void* event) {
+ // we ignore most event name matching rules here
+ return strcmp(transition->event, ((const struct event_t*)event)->name) == 0;
+}
+
+static int send(const uscxml_ctx* ctx, const uscxml_elem_send* send) {
+ if (send->delay > 0)
+ pumpRemain = send->delay;
+ return USCXML_ERR_OK;
+}
+
+static void* dequeueExternal(const uscxml_ctx* ctx) {
+ // we will only call step when we have an event
+ void* tmp = _event;
+ _event = NULL;
+ return tmp;
+}
+
+static bool isInState(const char* stateId) {
+ for (size_t i = 0; i < ctx.machine->nr_states; i++) {
+ if (ctx.machine->states[i].name &&
+ strcmp(ctx.machine->states[i].name, stateId) == 0 &&
+ BIT_HAS(i, ctx.config)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void setup() {
+ // initilize the state chart
+ memset(&ctx, 0, sizeof(uscxml_ctx));
+ ctx.machine = &USCXML_MACHINE;
+ ctx.invoke = invoke;
+ ctx.is_matched = matched;
+ ctx.dequeue_external = dequeueExternal;
+ ctx.exec_content_send = send;
+
+ int err = USCXML_ERR_OK;
+
+ // run until first stable config
+ while((err = uscxml_step(&ctx)) != USCXML_ERR_IDLE) {}
+}
+
+
+void loop() {
+ digitalWrite(LED, HIGH);
+
+ int err = USCXML_ERR_OK;
+
+ if (readCapSense) {
+ // capsense invoker is active
+ for (int i = 0; i < 4; ++i) {
+ int cap = bed[i].capacitiveSensor(50);
+ if (cap > 0) {
+ soil[i] = ROLLOFF * soil[i] + (1 - ROLLOFF) * (cap - thrs[i]);
+ }
+ }
+ }
+
+ _eventLight.data.light = analogRead(LIGHT);
+ _event = &_eventLight;
+ while((err = uscxml_step(&ctx)) != USCXML_ERR_IDLE) {}
+
+ if (isInState("dark")) {
+ LowPower.powerDown(MEASURE_INTERVAL, ADC_OFF, BOD_OFF);
+ return;
+ }
+
+ if (isInState("light")) {
+ if (false) {
+ } else if (isInState("pumping")) {
+ // is time elapsed already?
+ if (pumpRemain == 0) {
+ _event = &_eventIdle;
+ while((err = uscxml_step(&ctx)) != USCXML_ERR_IDLE) {}
+ }
+ } else if (isInState("idle")) {
+ // check is we need to pump
+ _event = &_eventPump;
+ while((err = uscxml_step(&ctx)) != USCXML_ERR_IDLE) {}
+ }
+ }
+
+ pumpRemain = (pumpRemain >= 8000) ? pumpRemain - 8000 : 0;
+
+ digitalWrite(LED, LOW);
+ LowPower.powerDown(MEASURE_INTERVAL, ADC_OFF, BOD_OFF);
+
+}
diff --git a/apps/arduino/WaterPump.scxml b/apps/arduino/WaterPump.scxml
new file mode 100644
index 0000000..a7d8bad
--- /dev/null
+++ b/apps/arduino/WaterPump.scxml
@@ -0,0 +1,70 @@
+<scxml datamodel="native" initial="dark" version="1.0">
+ <!-- we provide the datamodel inline in the scaffolding -->
+ <script><![CDATA[
+ pinMode(LED, OUTPUT);
+ for (char i = 0; i < 4; ++i) {
+ pinMode(pump[i], OUTPUT);
+ digitalWrite(pump[i], PUMP_OFF);
+ bed[i].set_CS_AutocaL_Millis(0xFFFFFFFF);
+ }
+ ]]></script>
+
+ <!-- it is too dark to water flowers -->
+ <state id="dark">
+ <transition event="light" cond="_event->data.light > LIGHT_THRES" target="light" />
+ <onentry>
+ <script><![CDATA[
+ for (char i = 0; i < 4; ++i) {
+ digitalWrite(pump[i], PUMP_OFF);
+ }
+ ]]></script>
+ </onentry>
+ </state>
+
+ <!-- start to take measurements and activate single pumps if too dry -->
+ <state id="light">
+ <transition event="light" cond="_event->data.light &lt; LIGHT_THRES" target="dark" />
+
+ <!-- delivers events for all the capsense measurements -->
+ <invoke type="capsense" id="cap" />
+
+ <state id="idle">
+ <transition event="pump" cond="soil[0] &lt; 0 &amp;&amp;
+ soil[0] &lt;= soil[1] &amp;&amp;
+ soil[0] &lt;= soil[2] &amp;&amp;
+ soil[0] &lt;= soil[3]" target="pump1" />
+ <transition event="pump" cond="soil[1] &lt; 0 &amp;&amp;
+ soil[1] &lt;= soil[0] &amp;&amp;
+ soil[1] &lt;= soil[2] &amp;&amp;
+ soil[1] &lt;= soil[3]" target="pump2" />
+ <transition event="pump" cond="soil[2] &lt; 0 &amp;&amp;
+ soil[2] &lt;= soil[0] &amp;&amp;
+ soil[2] &lt;= soil[1] &amp;&amp;
+ soil[2] &lt;= soil[3]" target="pump3" />
+ <transition event="pump" cond="soil[3] &lt; 0 &amp;&amp;
+ soil[3] &lt;= soil[0] &amp;&amp;
+ soil[3] &lt;= soil[1] &amp;&amp;
+ soil[3] &lt;= soil[2]" target="pump4" />
+ </state>
+
+ <state id="pumping">
+ <transition event="idle" target="idle" />
+ <onentry>
+ <send delay="8000ms" event="idle" />
+ </onentry>
+
+ <state id="pump1">
+ <invoke type="pump" id="1" />
+ </state>
+ <state id="pump2">
+ <invoke type="pump" id="2" />
+ </state>
+ <state id="pump3">
+ <invoke type="pump" id="3" />
+ </state>
+ <state id="pump4">
+ <invoke type="pump" id="4" />
+ </state>
+ </state>
+ </state>
+</scxml>
diff --git a/apps/arduino/stateMachine.c b/apps/arduino/stateMachine.c
new file mode 100644
index 0000000..a74535b
--- /dev/null
+++ b/apps/arduino/stateMachine.c
@@ -0,0 +1,1291 @@
+/**
+ Generated from source:
+ file:///Users/sradomski/Documents/Electronics/WaterPump/WaterPump.scxml
+*/
+
+#ifndef USCXML_NO_STDTYPES_H
+# include <stdint.h> /* explicit types */
+#endif
+#include <stddef.h> /* NULL */
+
+#ifndef USCXML_NO_GEN_C_MACROS
+
+/**
+ * All macros used for the scxml types and functions
+ *
+ * ** IMPORTANT: Make sure to set the following macros prior to including. **
+ * They are used to represent the machine in the types to follow
+ * and to allocate stack memory during a micro-step function.
+ * When in doubt, overprovide.
+ *
+ * USCXML_NR_STATES_TYPE
+ * as the smallest type for positive integers that can contain the
+ * largest number of states from an individual state machine. E.g.:
+ * < 2^8 states => uint8_t
+ * < 2^16 states => uint16_t
+ * < 2^32 states => uint32_t
+ */
+
+#ifndef USCXML_NR_STATES_TYPE
+# define USCXML_NR_STATES_TYPE uint8_t
+#endif
+
+/**
+ * USCXML_NR_TRANS_TYPE
+ * the same as above but for the number of transitions.
+ */
+
+#ifndef USCXML_NR_TRANS_TYPE
+# define USCXML_NR_TRANS_TYPE uint8_t
+#endif
+
+/**
+ * USCXML_MAX_NR_STATES_BYTES
+ * the smallest multiple of 8 that, if multiplied by 8,
+ * is larger than USCXML_NR_STATES_TYPE, e.g:
+ * 1-8 states => 1
+ * 9-16 states => 2
+ * 17-24 states => 3
+ * 25-32 states => 4
+ * ...
+ */
+
+#ifndef USCXML_MAX_NR_STATES_BYTES
+# define USCXML_MAX_NR_STATES_BYTES 2
+#endif
+
+/**
+ * USCXML_MAX_NR_TRANS_BYTES
+ * same as above but for transitions.
+ */
+
+#ifndef USCXML_MAX_NR_TRANS_BYTES
+# define USCXML_MAX_NR_TRANS_BYTES 1
+#endif
+
+/**
+ * USCXML_NUMBER_STATES / USCXML_NUMBER_TRANS
+ * Per default the number of states / transitions is retrieved from the machine
+ * info in the uscxml_ctx struct, but you can also hard-code it per macro.
+ */
+
+#ifndef USCXML_NUMBER_STATES
+# define USCXML_NUMBER_STATES (ctx->machine->nr_states)
+#endif
+
+#ifndef USCXML_NUMBER_TRANS
+# define USCXML_NUMBER_TRANS (ctx->machine->nr_transitions)
+#endif
+
+/**
+ * USCXML_GET_STATE / USCXML_GET_TRANS
+ * Per default an individual state or transitions is retrieved from the machine
+ * info in the uscxml_ctx struct, but you can also hard-code it per macro.
+ */
+
+#ifndef USCXML_GET_STATE
+# define USCXML_GET_STATE(i) (ctx->machine->states[i])
+#endif
+
+#ifndef USCXML_GET_TRANS
+# define USCXML_GET_TRANS(i) (ctx->machine->transitions[i])
+#endif
+
+
+/* Common macros below */
+
+#define BIT_HAS(idx, bitset) ((bitset[idx >> 3] & (1 << (idx & 7))) != 0)
+#define BIT_SET_AT(idx, bitset) bitset[idx >> 3] |= (1 << (idx & 7));
+#define BIT_CLEAR(idx, bitset) bitset[idx >> 3] &= (1 << (idx & 7)) ^ 0xFF;
+
+#ifdef __GNUC__
+# define likely(x) (__builtin_expect(!!(x), 1))
+# define unlikely(x) (__builtin_expect(!!(x), 0))
+#else
+# define likely(x) (x)
+# define unlikely(x) (x)
+#endif
+
+/* error return codes */
+#define USCXML_ERR_OK 0
+#define USCXML_ERR_IDLE 1
+#define USCXML_ERR_DONE 2
+#define USCXML_ERR_MISSING_CALLBACK 3
+#define USCXML_ERR_FOREACH_DONE 4
+#define USCXML_ERR_EXEC_CONTENT 5
+#define USCXML_ERR_INVALID_TARGET 6
+#define USCXML_ERR_INVALID_TYPE 7
+#define USCXML_ERR_UNSUPPORTED 8
+
+#define USCXML_TRANS_SPONTANEOUS 0x01
+#define USCXML_TRANS_TARGETLESS 0x02
+#define USCXML_TRANS_INTERNAL 0x04
+#define USCXML_TRANS_HISTORY 0x08
+#define USCXML_TRANS_INITIAL 0x10
+
+#define USCXML_STATE_ATOMIC 0x01
+#define USCXML_STATE_PARALLEL 0x02
+#define USCXML_STATE_COMPOUND 0x03
+#define USCXML_STATE_FINAL 0x04
+#define USCXML_STATE_HISTORY_DEEP 0x05
+#define USCXML_STATE_HISTORY_SHALLOW 0x06
+#define USCXML_STATE_INITIAL 0x07
+#define USCXML_STATE_HAS_HISTORY 0x80 /* highest bit */
+#define USCXML_STATE_MASK(t) (t & 0x7F) /* mask highest bit */
+
+#define USCXML_CTX_PRISTINE 0x00
+#define USCXML_CTX_SPONTANEOUS 0x01
+#define USCXML_CTX_INITIALIZED 0x02
+#define USCXML_CTX_TOP_LEVEL_FINAL 0x04
+#define USCXML_CTX_TRANSITION_FOUND 0x08
+#define USCXML_CTX_FINISHED 0x10
+
+#define USCXML_ELEM_DATA_IS_SET(data) (data->id != NULL)
+#define USCXML_ELEM_DONEDATA_IS_SET(donedata) (donedata->content != NULL || donedata->contentexpr != NULL || donedata->params != NULL)
+#define USCXML_ELEM_PARAM_IS_SET(param) (param->name != NULL)
+#define USCXML_MACHINE_IS_SET(machine) (machine->nr_states > 0)
+
+#define USCXML_NO_GEN_C_MACROS
+#endif
+
+
+#ifndef USCXML_NO_GEN_C_TYPES
+
+/**
+ * All types required to represent an SCXML state chart.
+ * Just predefine the USCXML_NO_GEN_C_TYPES macro if you do not need them.
+ */
+
+typedef struct uscxml_machine uscxml_machine;
+typedef struct uscxml_transition uscxml_transition;
+typedef struct uscxml_state uscxml_state;
+typedef struct uscxml_ctx uscxml_ctx;
+typedef struct uscxml_elem_invoke uscxml_elem_invoke;
+
+typedef struct uscxml_elem_send uscxml_elem_send;
+typedef struct uscxml_elem_param uscxml_elem_param;
+typedef struct uscxml_elem_data uscxml_elem_data;
+typedef struct uscxml_elem_assign uscxml_elem_assign;
+typedef struct uscxml_elem_donedata uscxml_elem_donedata;
+typedef struct uscxml_elem_foreach uscxml_elem_foreach;
+
+typedef void* (*dequeue_internal_t)(const uscxml_ctx* ctx);
+typedef void* (*dequeue_external_t)(const uscxml_ctx* ctx);
+typedef int (*is_enabled_t)(const uscxml_ctx* ctx, const uscxml_transition* transition);
+typedef int (*is_matched_t)(const uscxml_ctx* ctx, const uscxml_transition* transition, const void* event);
+typedef int (*is_true_t)(const uscxml_ctx* ctx, const char* expr);
+typedef int (*exec_content_t)(const uscxml_ctx* ctx, const uscxml_state* state, const void* event);
+typedef int (*raise_done_event_t)(const uscxml_ctx* ctx, const uscxml_state* state, const uscxml_elem_donedata* donedata);
+typedef int (*invoke_t)(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke);
+
+typedef int (*exec_content_log_t)(const uscxml_ctx* ctx, const char* label, const char* expr);
+typedef int (*exec_content_raise_t)(const uscxml_ctx* ctx, const char* event);
+typedef int (*exec_content_send_t)(const uscxml_ctx* ctx, const uscxml_elem_send* send);
+typedef int (*exec_content_foreach_init_t)(const uscxml_ctx* ctx, const uscxml_elem_foreach* foreach);
+typedef int (*exec_content_foreach_next_t)(const uscxml_ctx* ctx, const uscxml_elem_foreach* foreach);
+typedef int (*exec_content_foreach_done_t)(const uscxml_ctx* ctx, const uscxml_elem_foreach* foreach);
+typedef int (*exec_content_assign_t)(const uscxml_ctx* ctx, const uscxml_elem_assign* assign);
+typedef int (*exec_content_init_t)(const uscxml_ctx* ctx, const uscxml_elem_data* data);
+typedef int (*exec_content_cancel_t)(const uscxml_ctx* ctx, const char* sendid, const char* sendidexpr);
+typedef int (*exec_content_finalize_t)(const uscxml_ctx* ctx, const uscxml_elem_invoke* invoker, const void* event);
+typedef int (*exec_content_script_t)(const uscxml_ctx* ctx, const char* src, const char* content);
+
+/**
+ * A single SCXML state-machine.
+ */
+struct uscxml_machine {
+ unsigned char flags; /* Unused */
+ USCXML_NR_STATES_TYPE nr_states; /* Make sure to set type per macro! */
+ USCXML_NR_TRANS_TYPE nr_transitions; /* Make sure to set type per macro! */
+ const char* name;
+ const char* datamodel;
+ const char* uuid; /* currently MD5 sum */
+ const uscxml_state* states;
+ const uscxml_transition* transitions;
+ const uscxml_machine* parent;
+ const uscxml_elem_donedata* donedata;
+ const exec_content_t script; /* Global script elements */
+};
+
+/**
+ * All information pertaining to a <data> element
+ * With late data binding, blocks of data elements are separated by NULL
+ * use USCXML_ELEM_DATA_IS_SET to test for end of a block.
+ */
+struct uscxml_elem_data {
+ const char* id;
+ const char* src;
+ const char* expr;
+ const char* content;
+};
+
+/**
+ * All information pertaining to an <assign> element
+ */
+struct uscxml_elem_assign {
+ const char* location;
+ const char* expr;
+ const char* content;
+};
+
+/**
+ * All information pertaining to any state element
+ */
+struct uscxml_state {
+ const char* name; /* eventual name */
+ const USCXML_NR_STATES_TYPE parent; /* parent */
+ const exec_content_t on_entry; /* on entry handlers */
+ const exec_content_t on_exit; /* on exit handlers */
+ const invoke_t invoke; /* invocations */
+ const unsigned char children[USCXML_MAX_NR_STATES_BYTES]; /* all children */
+ const unsigned char completion[USCXML_MAX_NR_STATES_BYTES]; /* default completion */
+ const unsigned char ancestors[USCXML_MAX_NR_STATES_BYTES]; /* all ancestors */
+ const uscxml_elem_data* data; /* data with late binding */
+ const unsigned char type; /* One of USCXML_STATE_* */
+};
+
+/**
+ * All information pertaining to a <transition> element
+ */
+struct uscxml_transition {
+ const USCXML_NR_STATES_TYPE source;
+ const unsigned char target[USCXML_MAX_NR_STATES_BYTES];
+ const char* event;
+ const char* condition;
+ const is_enabled_t is_enabled;
+ const exec_content_t on_transition;
+ const unsigned char type;
+ const unsigned char conflicts[USCXML_MAX_NR_TRANS_BYTES];
+ const unsigned char exit_set[USCXML_MAX_NR_STATES_BYTES];
+};
+
+/**
+ * All information pertaining to a <foreach> element
+ */
+struct uscxml_elem_foreach {
+ const char* array;
+ const char* item;
+ const char* index;
+};
+
+/**
+ * All information pertaining to a <param> element
+ * Blocks of params are separated by NULL params, use
+ * USCXML_ELEM_PARAM_IS_SET to test for end of a block.
+ */
+struct uscxml_elem_param {
+ const char* name;
+ const char* expr;
+ const char* location;
+};
+
+/**
+ * All information pertaining to a <donedata> element
+ */
+struct uscxml_elem_donedata {
+ const USCXML_NR_STATES_TYPE source;
+ const char* content;
+ const char* contentexpr;
+ const uscxml_elem_param* params;
+};
+
+/**
+ * All information pertaining to an <invoke> element
+ */
+struct uscxml_elem_invoke {
+ const uscxml_machine* machine;
+ const char* type;
+ const char* typeexpr;
+ const char* src;
+ const char* srcexpr;
+ const char* id;
+ const char* idlocation;
+ const char* sourcename;
+ const char* namelist;
+ const unsigned char autoforward;
+ const uscxml_elem_param* params;
+ exec_content_finalize_t finalize;
+ const char* content;
+ const char* contentexpr;
+};
+
+/**
+ * All information pertaining to a <send> element
+ */
+struct uscxml_elem_send {
+ const char* event;
+ const char* eventexpr;
+ const char* target;
+ const char* targetexpr;
+ const char* type;
+ const char* typeexpr;
+ const char* id;
+ const char* idlocation;
+ unsigned long delay;
+ const char* delayexpr;
+ const char* namelist; /* not space-separated, still as in attribute value */
+ const char* content;
+ const char* contentexpr;
+ const uscxml_elem_param* params;
+};
+
+/**
+ * Represents an instance of a state-chart at runtime/
+ */
+struct uscxml_ctx {
+ unsigned char flags;
+ const uscxml_machine* machine;
+
+ unsigned char config[USCXML_MAX_NR_STATES_BYTES]; /* Make sure these macros specify a sufficient size */
+ unsigned char history[USCXML_MAX_NR_STATES_BYTES];
+ unsigned char invocations[USCXML_MAX_NR_STATES_BYTES];
+ unsigned char initialized_data[USCXML_MAX_NR_STATES_BYTES];
+
+ void* user_data;
+ void* event;
+
+ dequeue_internal_t dequeue_internal;
+ dequeue_external_t dequeue_external;
+ is_matched_t is_matched;
+ is_true_t is_true;
+ raise_done_event_t raise_done_event;
+
+ exec_content_log_t exec_content_log;
+ exec_content_raise_t exec_content_raise;
+ exec_content_send_t exec_content_send;
+ exec_content_foreach_init_t exec_content_foreach_init;
+ exec_content_foreach_next_t exec_content_foreach_next;
+ exec_content_foreach_done_t exec_content_foreach_done;
+ exec_content_assign_t exec_content_assign;
+ exec_content_init_t exec_content_init;
+ exec_content_cancel_t exec_content_cancel;
+ exec_content_script_t exec_content_script;
+
+ invoke_t invoke;
+};
+
+#define USCXML_NO_GEN_C_TYPES
+#endif
+
+/* forward declare machines to allow references */
+extern const uscxml_machine _uscxml_4FC60039__machine;
+
+#ifndef USCXML_NO_ELEM_INFO
+
+static const uscxml_elem_send _uscxml_4FC60039__elem_sends[1] = {
+ {
+ /* event */ "idle",
+ /* eventexpr */ NULL,
+ /* target */ NULL,
+ /* targetexpr */ NULL,
+ /* type */ NULL,
+ /* typeexpr */ NULL,
+ /* id */ NULL,
+ /* idlocation */ NULL,
+ /* delay */ 8000,
+ /* delayexpr */ NULL,
+ /* namelist */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ /* params */ NULL
+ }
+};
+
+static const uscxml_elem_donedata _uscxml_4FC60039__elem_donedatas[1] = {
+ /* source, content, contentexpr, params */
+ { 0, NULL, NULL, NULL }
+};
+
+#endif
+
+#ifndef USCXML_NO_ELEM_INFO
+
+static const uscxml_elem_invoke _uscxml_4FC60039__elem_invokes[5] = {
+ {
+ /* machine */ NULL,
+ /* type */ "capsense",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "cap",
+ /* idlocation */ NULL,
+ /* sourcename */ "light",
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ },
+ {
+ /* machine */ NULL,
+ /* type */ "pump",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "1",
+ /* idlocation */ NULL,
+ /* sourcename */ "pump1",
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ },
+ {
+ /* machine */ NULL,
+ /* type */ "pump",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "2",
+ /* idlocation */ NULL,
+ /* sourcename */ "pump2",
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ },
+ {
+ /* machine */ NULL,
+ /* type */ "pump",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "3",
+ /* idlocation */ NULL,
+ /* sourcename */ "pump3",
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ },
+ {
+ /* machine */ NULL,
+ /* type */ "pump",
+ /* typeexpr */ NULL,
+ /* src */ NULL,
+ /* srcexpr */ NULL,
+ /* id */ "4",
+ /* idlocation */ NULL,
+ /* sourcename */ "pump4",
+ /* namelist */ NULL,
+ /* autoforward */ 0,
+ /* params */ NULL,
+ /* finalize */ NULL,
+ /* content */ NULL,
+ /* contentexpr */ NULL,
+ }
+};
+
+#endif
+
+#ifndef USCXML_NO_EXEC_CONTENT
+
+static int _uscxml_4FC60039__global_script_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) {
+ int err = USCXML_ERR_OK;
+
+ pinMode(LED, OUTPUT);
+ for (char i = 0; i < 4; ++i) {
+ pinMode(pump[i], OUTPUT);
+ digitalWrite(pump[i], PUMP_OFF);
+ bed[i].set_CS_AutocaL_Millis(0xFFFFFFFF);
+ }
+ return USCXML_ERR_OK;
+}
+static int _uscxml_4FC60039__global_script(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) {
+ _uscxml_4FC60039__global_script_0(ctx, state, event);
+ return USCXML_ERR_OK;
+}
+
+static int _uscxml_4FC60039__dark_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) {
+ int err = USCXML_ERR_OK;
+
+ for (char i = 0; i < 4; ++i) {
+ digitalWrite(pump[i], PUMP_OFF);
+ }
+ return USCXML_ERR_OK;
+}
+
+static int _uscxml_4FC60039__dark_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) {
+ _uscxml_4FC60039__dark_on_entry_0(ctx, state, event);
+ return USCXML_ERR_OK;
+}
+
+static int _uscxml_4FC60039__light_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) {
+ ctx->invoke(ctx, s, &_uscxml_4FC60039__elem_invokes[0], uninvoke);
+
+ return USCXML_ERR_OK;
+}
+static int _uscxml_4FC60039__pumping_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) {
+ int err = USCXML_ERR_OK;
+ if likely(ctx->exec_content_send != NULL) {
+ if ((ctx->exec_content_send(ctx, &_uscxml_4FC60039__elem_sends[0])) != USCXML_ERR_OK) return err;
+ } else {
+ return USCXML_ERR_MISSING_CALLBACK;
+ }
+ return USCXML_ERR_OK;
+}
+
+static int _uscxml_4FC60039__pumping_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) {
+ _uscxml_4FC60039__pumping_on_entry_0(ctx, state, event);
+ return USCXML_ERR_OK;
+}
+
+static int _uscxml_4FC60039__pump1_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) {
+ ctx->invoke(ctx, s, &_uscxml_4FC60039__elem_invokes[1], uninvoke);
+
+ return USCXML_ERR_OK;
+}
+static int _uscxml_4FC60039__pump2_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) {
+ ctx->invoke(ctx, s, &_uscxml_4FC60039__elem_invokes[2], uninvoke);
+
+ return USCXML_ERR_OK;
+}
+static int _uscxml_4FC60039__pump3_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) {
+ ctx->invoke(ctx, s, &_uscxml_4FC60039__elem_invokes[3], uninvoke);
+
+ return USCXML_ERR_OK;
+}
+static int _uscxml_4FC60039__pump4_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) {
+ ctx->invoke(ctx, s, &_uscxml_4FC60039__elem_invokes[4], uninvoke);
+
+ return USCXML_ERR_OK;
+}
+static int _uscxml_4FC60039__dark_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) {
+ return (_event->data.light > LIGHT_THRES);
+}
+static int _uscxml_4FC60039__idle_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) {
+ return (soil[0] < 0 && soil[0] <= soil[1]);
+}
+static int _uscxml_4FC60039__idle_transition1_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) {
+ return (soil[1] < 0 && soil[1] <= soil[0]);
+}
+static int _uscxml_4FC60039__light_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) {
+ return (_event->data.light < LIGHT_THRES);
+}
+#endif
+
+#ifndef USCXML_NO_ELEM_INFO
+
+static const uscxml_state _uscxml_4FC60039__states[9] = {
+ { /* state number 0 */
+ /* name */ NULL,
+ /* parent */ 0,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x06, 0x00 /* 011000000 */ },
+ /* completion */ { 0x02, 0x00 /* 010000000 */ },
+ /* ancestors */ { 0x00, 0x00 /* 000000000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_COMPOUND,
+ },
+ { /* state number 1 */
+ /* name */ "dark",
+ /* parent */ 0,
+ /* onentry */ _uscxml_4FC60039__dark_on_entry,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x00, 0x00 /* 000000000 */ },
+ /* completion */ { 0x00, 0x00 /* 000000000 */ },
+ /* ancestors */ { 0x01, 0x00 /* 100000000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_ATOMIC,
+ },
+ { /* state number 2 */
+ /* name */ "light",
+ /* parent */ 0,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ _uscxml_4FC60039__light_invoke,
+ /* children */ { 0x18, 0x00 /* 000110000 */ },
+ /* completion */ { 0x08, 0x00 /* 000100000 */ },
+ /* ancestors */ { 0x01, 0x00 /* 100000000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_COMPOUND,
+ },
+ { /* state number 3 */
+ /* name */ "idle",
+ /* parent */ 2,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0x00, 0x00 /* 000000000 */ },
+ /* completion */ { 0x00, 0x00 /* 000000000 */ },
+ /* ancestors */ { 0x05, 0x00 /* 101000000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_ATOMIC,
+ },
+ { /* state number 4 */
+ /* name */ "pumping",
+ /* parent */ 2,
+ /* onentry */ _uscxml_4FC60039__pumping_on_entry,
+ /* onexit */ NULL,
+ /* invoke */ NULL,
+ /* children */ { 0xe0, 0x01 /* 000001111 */ },
+ /* completion */ { 0x20, 0x00 /* 000001000 */ },
+ /* ancestors */ { 0x05, 0x00 /* 101000000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_COMPOUND,
+ },
+ { /* state number 5 */
+ /* name */ "pump1",
+ /* parent */ 4,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ _uscxml_4FC60039__pump1_invoke,
+ /* children */ { 0x00, 0x00 /* 000000000 */ },
+ /* completion */ { 0x00, 0x00 /* 000000000 */ },
+ /* ancestors */ { 0x15, 0x00 /* 101010000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_ATOMIC,
+ },
+ { /* state number 6 */
+ /* name */ "pump2",
+ /* parent */ 4,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ _uscxml_4FC60039__pump2_invoke,
+ /* children */ { 0x00, 0x00 /* 000000000 */ },
+ /* completion */ { 0x00, 0x00 /* 000000000 */ },
+ /* ancestors */ { 0x15, 0x00 /* 101010000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_ATOMIC,
+ },
+ { /* state number 7 */
+ /* name */ "pump3",
+ /* parent */ 4,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ _uscxml_4FC60039__pump3_invoke,
+ /* children */ { 0x00, 0x00 /* 000000000 */ },
+ /* completion */ { 0x00, 0x00 /* 000000000 */ },
+ /* ancestors */ { 0x15, 0x00 /* 101010000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_ATOMIC,
+ },
+ { /* state number 8 */
+ /* name */ "pump4",
+ /* parent */ 4,
+ /* onentry */ NULL,
+ /* onexit */ NULL,
+ /* invoke */ _uscxml_4FC60039__pump4_invoke,
+ /* children */ { 0x00, 0x00 /* 000000000 */ },
+ /* completion */ { 0x00, 0x00 /* 000000000 */ },
+ /* ancestors */ { 0x15, 0x00 /* 101010000 */ },
+ /* data */ NULL,
+ /* type */ USCXML_STATE_ATOMIC,
+ }
+};
+
+#endif
+
+#ifndef USCXML_NO_ELEM_INFO
+
+static const uscxml_transition _uscxml_4FC60039__transitions[5] = {
+ { /* transition number 0 with priority 0
+ target: light
+ */
+ /* source */ 1,
+ /* target */ { 0x04, 0x00 /* 001000000 */ },
+ /* event */ "light",
+ /* condition */ NULL,
+ /* is_enabled */ _uscxml_4FC60039__dark_transition0_is_enabled,
+ /* ontrans */ NULL,
+ /* type */ 0,
+ /* conflicts */ { 0x1f /* 11111 */ },
+ /* exit set */ { 0xfe, 0x01 /* 011111111 */ }
+ },
+ { /* transition number 2 with priority 1
+ target: pump1
+ */
+ /* source */ 3,
+ /* target */ { 0x20, 0x00 /* 000001000 */ },
+ /* event */ "pump",
+ /* condition */ NULL,
+ /* is_enabled */ _uscxml_4FC60039__idle_transition0_is_enabled,
+ /* ontrans */ NULL,
+ /* type */ 0,
+ /* conflicts */ { 0x1f /* 11111 */ },
+ /* exit set */ { 0xf8, 0x01 /* 000111111 */ }
+ },
+ { /* transition number 3 with priority 2
+ target: pump2
+ */
+ /* source */ 3,
+ /* target */ { 0x40, 0x00 /* 000000100 */ },
+ /* event */ "pump",
+ /* condition */ NULL,
+ /* is_enabled */ _uscxml_4FC60039__idle_transition1_is_enabled,
+ /* ontrans */ NULL,
+ /* type */ 0,
+ /* conflicts */ { 0x1f /* 11111 */ },
+ /* exit set */ { 0xf8, 0x01 /* 000111111 */ }
+ },
+ { /* transition number 4 with priority 3
+ target: idle
+ */
+ /* source */ 4,
+ /* target */ { 0x08, 0x00 /* 000100000 */ },
+ /* event */ "idle",
+ /* condition */ NULL,
+ /* is_enabled */ NULL,
+ /* ontrans */ NULL,
+ /* type */ 0,
+ /* conflicts */ { 0x1f /* 11111 */ },
+ /* exit set */ { 0xf8, 0x01 /* 000111111 */ }
+ },
+ { /* transition number 1 with priority 4
+ target: dark
+ */
+ /* source */ 2,
+ /* target */ { 0x02, 0x00 /* 010000000 */ },
+ /* event */ "light",
+ /* condition */ NULL,
+ /* is_enabled */ _uscxml_4FC60039__light_transition0_is_enabled,
+ /* ontrans */ NULL,
+ /* type */ 0,
+ /* conflicts */ { 0x1f /* 11111 */ },
+ /* exit set */ { 0xfe, 0x01 /* 011111111 */ }
+ }
+};
+
+#endif
+
+#ifndef USCXML_NO_ELEM_INFO
+
+#ifndef USCXML_MACHINE
+# define USCXML_MACHINE _uscxml_4FC60039__machine
+#endif
+#define USCXML_MACHINE_0 _uscxml_4FC60039__machine
+#define USCXML_MACHINE_WATERPUMP_SCXML _uscxml_4FC60039__machine
+
+const uscxml_machine _uscxml_4FC60039__machine = {
+ /* flags */ 0,
+ /* nr_states */ 9,
+ /* nr_transitions */ 5,
+ /* name */ "WaterPump.scxml",
+ /* datamodel */ "native",
+ /* uuid */ "4FC600390B3422E11879652D26725E30",
+ /* states */ &_uscxml_4FC60039__states[0],
+ /* transitions */ &_uscxml_4FC60039__transitions[0],
+ /* parent */ NULL,
+ /* donedata */ &_uscxml_4FC60039__elem_donedatas[0],
+ /* script */ _uscxml_4FC60039__global_script
+
+};
+
+#endif
+
+#ifdef USCXML_VERBOSE
+/**
+ * Print name of states contained in a (debugging).
+ */
+static void printStateNames(const uscxml_ctx* ctx, const unsigned char* a, size_t length) {
+ size_t i;
+ const char* seperator = "";
+ for (i = 0; i < length; i++) {
+ if (BIT_HAS(i, a)) {
+ printf("%s%s", seperator, (USCXML_GET_STATE(i).name != NULL ? USCXML_GET_STATE(i).name : "UNK"));
+ seperator = ", ";
+ }
+ }
+ printf("\n");
+}
+
+/**
+ * Print bits set in a in a binary representation (debugging).
+ */
+static void printBitsetIndices(const unsigned char* a, size_t length) {
+ size_t i;
+ const char* seperator = "";
+ for (i = 0; i < length; i++) {
+ if (BIT_HAS(i, a)) {
+ printf("%s%zu", seperator, i);
+ seperator = ", ";
+ }
+ }
+ printf("\n");
+}
+#endif
+
+#ifndef USCXML_NO_BIT_OPERATIONS
+/**
+ * Return true if there is a common bit in a and b.
+ */
+static int bit_has_and(const unsigned char* a, const unsigned char* b, size_t i) {
+ while(i--) {
+ if (a[i] & b[i])
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Set all bits to 0, this corresponds to memset(a, 0, i),
+ * but does not require string.h or cstring.
+ */
+static void bit_clear_all(unsigned char* a, size_t i) {
+ while(i--) {
+ a[i] = 0;
+ }
+}
+
+/**
+ * Return true if there is any bit set in a.
+ */
+static int bit_has_any(unsigned const char* a, size_t i) {
+ while(i--) {
+ if (a[i] > 0)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Set all bits from given mask in dest, this is |= for bit arrays.
+ */
+static void bit_or(unsigned char* dest, const unsigned char* mask, size_t i) {
+ while(i--) {
+ dest[i] |= mask[i];
+ }
+}
+
+/**
+ * Copy all bits from source to dest, this corresponds to memcpy(a, b, i),
+ * but does not require string.h or cstring.
+ */
+static void bit_copy(unsigned char* dest, const unsigned char* source, size_t i) {
+ while(i--) {
+ dest[i] = source[i];
+ }
+}
+
+/**
+ * Unset bits from mask in dest.
+ */
+static void bit_and_not(unsigned char* dest, const unsigned char* mask, size_t i) {
+ while(i--) {
+ dest[i] &= ~mask[i];
+ }
+}
+
+/**
+ * Set bits from mask in dest.
+ */
+static void bit_and(unsigned char* dest, const unsigned char* mask, size_t i) {
+ while(i--) {
+ dest[i] &= mask[i];
+ };
+}
+
+#define USCXML_NO_BIT_OPERATIONS
+#endif
+
+#ifndef USCXML_NO_STEP_FUNCTION
+int uscxml_step(uscxml_ctx* ctx) {
+
+ USCXML_NR_STATES_TYPE i, j, k;
+ USCXML_NR_STATES_TYPE nr_states_bytes = ((USCXML_NUMBER_STATES + 7) & ~7) >> 3;
+ USCXML_NR_TRANS_TYPE nr_trans_bytes = ((USCXML_NUMBER_TRANS + 7) & ~7) >> 3;
+ int err = USCXML_ERR_OK;
+ unsigned char conflicts [USCXML_MAX_NR_TRANS_BYTES];
+ unsigned char trans_set [USCXML_MAX_NR_TRANS_BYTES];
+ unsigned char target_set [USCXML_MAX_NR_STATES_BYTES];
+ unsigned char exit_set [USCXML_MAX_NR_STATES_BYTES];
+ unsigned char entry_set [USCXML_MAX_NR_STATES_BYTES];
+ unsigned char tmp_states [USCXML_MAX_NR_STATES_BYTES];
+
+#ifdef USCXML_VERBOSE
+ printf("Config: ");
+ printStateNames(ctx, ctx->config, USCXML_NUMBER_STATES);
+#endif
+
+ if (ctx->flags & USCXML_CTX_FINISHED)
+ return USCXML_ERR_DONE;
+
+ if (ctx->flags & USCXML_CTX_TOP_LEVEL_FINAL) {
+ /* exit all remaining states */
+ i = USCXML_NUMBER_STATES;
+ while(i-- > 0) {
+ if (BIT_HAS(i, ctx->config)) {
+ /* call all on exit handlers */
+ if (USCXML_GET_STATE(i).on_exit != NULL) {
+ if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)
+ return err;
+ }
+ }
+ if (BIT_HAS(i, ctx->invocations)) {
+ if (USCXML_GET_STATE(i).invoke != NULL)
+ USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1);
+ BIT_CLEAR(i, ctx->invocations);
+ }
+ }
+ ctx->flags |= USCXML_CTX_FINISHED;
+ return USCXML_ERR_DONE;
+ }
+
+ bit_clear_all(target_set, nr_states_bytes);
+ bit_clear_all(trans_set, nr_trans_bytes);
+ if unlikely(ctx->flags == USCXML_CTX_PRISTINE) {
+ if (ctx->machine->script != NULL)
+ ctx->machine->script(ctx, &ctx->machine->states[0], NULL);
+ bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes);
+ ctx->flags |= USCXML_CTX_SPONTANEOUS | USCXML_CTX_INITIALIZED;
+ goto ESTABLISH_ENTRY_SET;
+ }
+
+DEQUEUE_EVENT:
+ if (ctx->flags & USCXML_CTX_SPONTANEOUS) {
+ ctx->event = NULL;
+ goto SELECT_TRANSITIONS;
+ }
+ if (ctx->dequeue_internal != NULL && (ctx->event = ctx->dequeue_internal(ctx)) != NULL) {
+ goto SELECT_TRANSITIONS;
+ }
+
+ /* manage invocations */
+ for (i = 0; i < USCXML_NUMBER_STATES; i++) {
+ /* uninvoke */
+ if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) {
+ if (USCXML_GET_STATE(i).invoke != NULL)
+ USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1);
+ BIT_CLEAR(i, ctx->invocations)
+ }
+ /* invoke */
+ if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) {
+ if (USCXML_GET_STATE(i).invoke != NULL)
+ USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 0);
+ BIT_SET_AT(i, ctx->invocations)
+ }
+ }
+
+ if (ctx->dequeue_external != NULL && (ctx->event = ctx->dequeue_external(ctx)) != NULL) {
+ goto SELECT_TRANSITIONS;
+ }
+
+ if (ctx->dequeue_external == NULL) {
+ return USCXML_ERR_DONE;
+ }
+ return USCXML_ERR_IDLE;
+
+SELECT_TRANSITIONS:
+ bit_clear_all(conflicts, nr_trans_bytes);
+ bit_clear_all(exit_set, nr_states_bytes);
+ for (i = 0; i < USCXML_NUMBER_TRANS; i++) {
+ /* never select history or initial transitions automatically */
+ if unlikely(USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL))
+ continue;
+
+ /* is the transition active? */
+ if (BIT_HAS(USCXML_GET_TRANS(i).source, ctx->config)) {
+ /* is it non-conflicting? */
+ if (!BIT_HAS(i, conflicts)) {
+ /* is it spontaneous with an event or vice versa? */
+ if ((USCXML_GET_TRANS(i).event == NULL && ctx->event == NULL) ||
+ (USCXML_GET_TRANS(i).event != NULL && ctx->event != NULL)) {
+ /* is it enabled? */
+ if ((ctx->event == NULL || ctx->is_matched(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) &&
+ (USCXML_GET_TRANS(i).condition == NULL ||
+ USCXML_GET_TRANS(i).is_enabled(ctx, &USCXML_GET_TRANS(i)) > 0)) {
+ /* remember that we found a transition */
+ ctx->flags |= USCXML_CTX_TRANSITION_FOUND;
+
+ /* transitions that are pre-empted */
+ bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes);
+
+ /* states that are directly targeted (resolve as entry-set later) */
+ bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes);
+
+ /* states that will be left */
+ bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes);
+
+ BIT_SET_AT(i, trans_set);
+ }
+ }
+ }
+ }
+ }
+ bit_and(exit_set, ctx->config, nr_states_bytes);
+
+ if (ctx->flags & USCXML_CTX_TRANSITION_FOUND) {
+ ctx->flags |= USCXML_CTX_SPONTANEOUS;
+ ctx->flags &= ~USCXML_CTX_TRANSITION_FOUND;
+ } else {
+ ctx->flags &= ~USCXML_CTX_SPONTANEOUS;
+ goto DEQUEUE_EVENT;
+ }
+
+#ifdef USCXML_VERBOSE
+ printf("Targets: ");
+ printStateNames(ctx, target_set, USCXML_NUMBER_STATES);
+#endif
+
+#ifdef USCXML_VERBOSE
+ printf("Exiting: ");
+ printStateNames(ctx, exit_set, USCXML_NUMBER_STATES);
+#endif
+
+#ifdef USCXML_VERBOSE
+ printf("History: ");
+ printStateNames(ctx, ctx->history, USCXML_NUMBER_STATES);
+#endif
+
+/* REMEMBER_HISTORY: */
+ for (i = 0; i < USCXML_NUMBER_STATES; i++) {
+ if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW ||
+ USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP) {
+ /* a history state whose parent is about to be exited */
+ if unlikely(BIT_HAS(USCXML_GET_STATE(i).parent, exit_set)) {
+ bit_copy(tmp_states, USCXML_GET_STATE(i).completion, nr_states_bytes);
+
+ /* set those states who were enabled */
+ bit_and(tmp_states, ctx->config, nr_states_bytes);
+
+ /* clear current history with completion mask */
+ bit_and_not(ctx->history, USCXML_GET_STATE(i).completion, nr_states_bytes);
+
+ /* set history */
+ bit_or(ctx->history, tmp_states, nr_states_bytes);
+ }
+ }
+ }
+
+ESTABLISH_ENTRY_SET:
+ /* calculate new entry set */
+ bit_copy(entry_set, target_set, nr_states_bytes);
+
+ /* iterate for ancestors */
+ for (i = 0; i < USCXML_NUMBER_STATES; i++) {
+ if (BIT_HAS(i, entry_set)) {
+ bit_or(entry_set, USCXML_GET_STATE(i).ancestors, nr_states_bytes);
+ }
+ }
+
+ /* iterate for descendants */
+ for (i = 0; i < USCXML_NUMBER_STATES; i++) {
+ if (BIT_HAS(i, entry_set)) {
+ switch (USCXML_STATE_MASK(USCXML_GET_STATE(i).type)) {
+ case USCXML_STATE_PARALLEL: {
+ bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);
+ break;
+ }
+#ifndef USCXML_NO_HISTORY
+ case USCXML_STATE_HISTORY_SHALLOW:
+ case USCXML_STATE_HISTORY_DEEP: {
+ if (!bit_has_and(USCXML_GET_STATE(i).completion, ctx->history, nr_states_bytes) &&
+ !BIT_HAS(USCXML_GET_STATE(i).parent, ctx->config)) {
+ /* nothing set for history, look for a default transition */
+ for (j = 0; j < USCXML_NUMBER_TRANS; j++) {
+ if unlikely(ctx->machine->transitions[j].source == i) {
+ bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);
+ if(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP &&
+ !bit_has_and(ctx->machine->transitions[j].target, USCXML_GET_STATE(i).children, nr_states_bytes)) {
+ for (k = i + 1; k < USCXML_NUMBER_STATES; k++) {
+ if (BIT_HAS(k, ctx->machine->transitions[j].target)) {
+ bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);
+ break;
+ }
+ }
+ }
+ BIT_SET_AT(j, trans_set);
+ break;
+ }
+ /* Note: SCXML mandates every history to have a transition! */
+ }
+ } else {
+ bit_copy(tmp_states, USCXML_GET_STATE(i).completion, nr_states_bytes);
+ bit_and(tmp_states, ctx->history, nr_states_bytes);
+ bit_or(entry_set, tmp_states, nr_states_bytes);
+ if (USCXML_GET_STATE(i).type == (USCXML_STATE_HAS_HISTORY | USCXML_STATE_HISTORY_DEEP)) {
+ /* a deep history state with nested histories -> more completion */
+ for (j = i + 1; j < USCXML_NUMBER_STATES; j++) {
+ if (BIT_HAS(j, USCXML_GET_STATE(i).completion) &&
+ BIT_HAS(j, entry_set) &&
+ (ctx->machine->states[j].type & USCXML_STATE_HAS_HISTORY)) {
+ for (k = j + 1; k < USCXML_NUMBER_STATES; k++) {
+ /* add nested history to entry_set */
+ if ((USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_DEEP ||
+ USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_SHALLOW) &&
+ BIT_HAS(k, ctx->machine->states[j].children)) {
+ /* a nested history state */
+ BIT_SET_AT(k, entry_set);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+#endif
+ case USCXML_STATE_INITIAL: {
+ for (j = 0; j < USCXML_NUMBER_TRANS; j++) {
+ if (ctx->machine->transitions[j].source == i) {
+ BIT_SET_AT(j, trans_set);
+ BIT_CLEAR(i, entry_set);
+ bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);
+ for (k = i + 1; k < USCXML_NUMBER_STATES; k++) {
+ if (BIT_HAS(k, ctx->machine->transitions[j].target)) {
+ bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case USCXML_STATE_COMPOUND: { /* we need to check whether one child is already in entry_set */
+ if (!bit_has_and(entry_set, USCXML_GET_STATE(i).children, nr_states_bytes) &&
+ (!bit_has_and(ctx->config, USCXML_GET_STATE(i).children, nr_states_bytes) ||
+ bit_has_and(exit_set, USCXML_GET_STATE(i).children, nr_states_bytes)))
+ {
+ bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);
+ if (!bit_has_and(USCXML_GET_STATE(i).completion, USCXML_GET_STATE(i).children, nr_states_bytes)) {
+ /* deep completion */
+ for (j = i + 1; j < USCXML_NUMBER_STATES; j++) {
+ if (BIT_HAS(j, USCXML_GET_STATE(i).completion)) {
+ bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes);
+ break; /* completion of compound is single state */
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef USCXML_VERBOSE
+ printf("Transitions: ");
+ printBitsetIndices(trans_set, sizeof(char) * 8 * nr_trans_bytes);
+#endif
+
+/* EXIT_STATES: */
+ i = USCXML_NUMBER_STATES;
+ while(i-- > 0) {
+ if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) {
+ /* call all on exit handlers */
+ if (USCXML_GET_STATE(i).on_exit != NULL) {
+ if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)
+ return err;
+ }
+ BIT_CLEAR(i, ctx->config);
+ }
+ }
+
+/* TAKE_TRANSITIONS: */
+ for (i = 0; i < USCXML_NUMBER_TRANS; i++) {
+ if (BIT_HAS(i, trans_set) && (USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) == 0) {
+ /* call executable content in transition */
+ if (USCXML_GET_TRANS(i).on_transition != NULL) {
+ if unlikely((err = USCXML_GET_TRANS(i).on_transition(ctx,
+ &ctx->machine->states[USCXML_GET_TRANS(i).source],
+ ctx->event)) != USCXML_ERR_OK)
+ return err;
+ }
+ }
+ }
+
+#ifdef USCXML_VERBOSE
+ printf("Entering: ");
+ printStateNames(ctx, entry_set, USCXML_NUMBER_STATES);
+#endif
+
+/* ENTER_STATES: */
+ for (i = 0; i < USCXML_NUMBER_STATES; i++) {
+ if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) {
+ /* these are no proper states */
+ if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP ||
+ USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW ||
+ USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_INITIAL)
+ continue;
+
+ BIT_SET_AT(i, ctx->config);
+
+ /* initialize data */
+ if (!BIT_HAS(i, ctx->initialized_data)) {
+ if unlikely(USCXML_GET_STATE(i).data != NULL && ctx->exec_content_init != NULL) {
+ ctx->exec_content_init(ctx, USCXML_GET_STATE(i).data);
+ }
+ BIT_SET_AT(i, ctx->initialized_data);
+ }
+
+ if (USCXML_GET_STATE(i).on_entry != NULL) {
+ if unlikely((err = USCXML_GET_STATE(i).on_entry(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)
+ return err;
+ }
+
+ /* take history and initial transitions */
+ for (j = 0; j < USCXML_NUMBER_TRANS; j++) {
+ if unlikely(BIT_HAS(j, trans_set) &&
+ (ctx->machine->transitions[j].type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) &&
+ ctx->machine->states[ctx->machine->transitions[j].source].parent == i) {
+ /* call executable content in transition */
+ if (ctx->machine->transitions[j].on_transition != NULL) {
+ if unlikely((err = ctx->machine->transitions[j].on_transition(ctx,
+ &USCXML_GET_STATE(i),
+ ctx->event)) != USCXML_ERR_OK)
+ return err;
+ }
+ }
+ }
+
+ /* handle final states */
+ if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_FINAL) {
+ if unlikely(USCXML_GET_STATE(i).ancestors[0] == 0x01) {
+ ctx->flags |= USCXML_CTX_TOP_LEVEL_FINAL;
+ } else {
+ /* raise done event */
+ const uscxml_elem_donedata* donedata = &ctx->machine->donedata[0];
+ while(USCXML_ELEM_DONEDATA_IS_SET(donedata)) {
+ if unlikely(donedata->source == i)
+ break;
+ donedata++;
+ }
+ ctx->raise_done_event(ctx, &ctx->machine->states[USCXML_GET_STATE(i).parent], (USCXML_ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));
+ }
+
+ /**
+ * are we the last final state to leave a parallel state?:
+ * 1. Gather all parallel states in our ancestor chain
+ * 2. Find all states for which these parallels are ancestors
+ * 3. Iterate all active final states and remove their ancestors
+ * 4. If a state remains, not all children of a parallel are final
+ */
+ for (j = 0; j < USCXML_NUMBER_STATES; j++) {
+ if unlikely(USCXML_STATE_MASK(ctx->machine->states[j].type) == USCXML_STATE_PARALLEL &&
+ BIT_HAS(j, USCXML_GET_STATE(i).ancestors)) {
+ bit_clear_all(tmp_states, nr_states_bytes);
+ for (k = 0; k < USCXML_NUMBER_STATES; k++) {
+ if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {
+ if (USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_FINAL) {
+ bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes);
+ } else {
+ BIT_SET_AT(k, tmp_states);
+ }
+ }
+ }
+ if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) {
+ ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL);
+ }
+ }
+ }
+
+ }
+
+ }
+ }
+
+ return USCXML_ERR_OK;
+}
+
+#define USCXML_NO_STEP_FUNCTION
+#endif
+