From 6e1d8d25d4e7b65ca67b5d5c529ba0bedb81feb9 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sun, 30 Apr 2017 22:51:38 +0200 Subject: Optimized ANSI-C transformation --- apps/arduino/WaterPump.cxx | 170 +++ apps/arduino/WaterPump.scxml | 70 ++ apps/arduino/stateMachine.c | 1291 +++++++++++++++++++++++ contrib/src/uscxml/ExtendedLuaDataModel.cpp | 21 + contrib/src/uscxml/ExtendedLuaDataModel.h | 49 + docs/Doxyfile.in | 9 +- docs/SCXML_ON_ARUIDNO.md | 88 ++ src/uscxml/interpreter/BasicContentExecutor.cpp | 2 +- src/uscxml/transform/ChartToC.cpp | 105 +- src/uscxml/transform/ChartToC.h | 1 + src/uscxml/transform/ChartToPromela.cpp | 2 +- test/CMakeLists.txt | 4 +- test/ctest/CTestCustom.ctest.in | 3 + test/src/test-c-machine.scxml.c | 208 ++-- test/src/test-extensions.cpp | 24 +- test/src/test-gen-c.cpp | 35 +- 16 files changed, 1923 insertions(+), 159 deletions(-) create mode 100644 apps/arduino/WaterPump.cxx create mode 100644 apps/arduino/WaterPump.scxml create mode 100644 apps/arduino/stateMachine.c create mode 100644 contrib/src/uscxml/ExtendedLuaDataModel.cpp create mode 100644 contrib/src/uscxml/ExtendedLuaDataModel.h create mode 100644 docs/SCXML_ON_ARUIDNO.md 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 +#include + + +#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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 /* explicit types */ +#endif +#include /* 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 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 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 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 element + */ +struct uscxml_elem_foreach { + const char* array; + const char* item; + const char* index; +}; + +/** + * All information pertaining to a 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 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 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 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 + diff --git a/contrib/src/uscxml/ExtendedLuaDataModel.cpp b/contrib/src/uscxml/ExtendedLuaDataModel.cpp new file mode 100644 index 0000000..cb19743 --- /dev/null +++ b/contrib/src/uscxml/ExtendedLuaDataModel.cpp @@ -0,0 +1,21 @@ +/** + * @file + * @author 2017 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * 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. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see . + * @endcond + */ + +#include "ExtendedLuaDataModel.h" + diff --git a/contrib/src/uscxml/ExtendedLuaDataModel.h b/contrib/src/uscxml/ExtendedLuaDataModel.h new file mode 100644 index 0000000..652a2a0 --- /dev/null +++ b/contrib/src/uscxml/ExtendedLuaDataModel.h @@ -0,0 +1,49 @@ +/** + * @file + * @author 2017 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * 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. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see . + * @endcond + */ + +#ifndef EXTENDEDLUADATAMODEL_H_9ED3DCC6 +#define EXTENDEDLUADATAMODEL_H_9ED3DCC6 + +#include "uscxml/plugins/datamodel/lua/LuaDataModel.h" + +class ExtendedLuaDataModel : public uscxml::LuaDataModel { +public: + ExtendedLuaDataModel() {}; + + std::shared_ptr create(uscxml::DataModelCallbacks* callbacks) { + + std::shared_ptr dm(new ExtendedLuaDataModel()); +// dm->LuaDataModel::init(callbacks); + + lua_pushcfunction(dm->_luaState, GetSomeResult); + lua_setglobal(dm->_luaState, "GetSomeResult"); + + return dm; + } + + static int GetSomeResult(lua_State * L) { + LOGD(uscxml::USCXML_INFO) << "Calling GetSomeResult!" << std::endl; + lua_pushinteger(L, 55555); + return 1; + } +}; + + + +#endif /* end of include guard: EXTENDEDLUADATAMODEL_H_9ED3DCC6 */ diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 7a79a1d..0bc2865 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -771,7 +771,8 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = @PROJECT_SOURCE_DIR@/docs \ - @PROJECT_SOURCE_DIR@/src/uscxml + @PROJECT_SOURCE_DIR@/src/uscxml \ + @PROJECT_SOURCE_DIR@/apps # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -799,7 +800,8 @@ FILE_PATTERNS = *.c \ *.md \ *.mm \ *.dox \ - *.vhdl + *.vhdl \ + *.scxml # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -847,7 +849,8 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = @PROJECT_SOURCE_DIR@/test/src/ +EXAMPLE_PATH = @PROJECT_SOURCE_DIR@/test/src/ \ + @PROJECT_SOURCE_DIR@/apps/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and diff --git a/docs/SCXML_ON_ARUIDNO.md b/docs/SCXML_ON_ARUIDNO.md new file mode 100644 index 0000000..62b223f --- /dev/null +++ b/docs/SCXML_ON_ARUIDNO.md @@ -0,0 +1,88 @@ +# SCXML on an ATMega328 {#embedded} + + + +[TOC] + +This page describes how to use SCXML to model the control flow for an embedded micro-controller. We will transform an SCXML state-chart onto ANSI-C, provide some scaffolding and deploy it onto the Arduino Nano. Regardless of the target platform, the approach is the same if you like to use the ANSI-C transformation for just any other platform. + +\section platform Hardware Platform + +For a project of mine, I used a solar-powered Arduino Nano to control four aquarium pumps to water my balcony plants when their soil is dry. There are some peculiarities that justify to use a state-chart to model the controller's behavior, namely: + +1. There is only enough power for one pump at a time +2. Pumps should only run if there is sufficient sunlight +3. The pump related to the sensor with the driest soil below a given threshold should run +4. If a pump runs, it ought to run for a given minimum amount of time + +The whole system is powered via a 5W solar module, which is connected via a 12V DCDC converter to another 12V5V DCDC converter, allowing to operate the actuators with 12V and the Arduino with 5V. On the 12V potential, there are some gold caps worth ~150mF to stabilize the potential and provide some *kick-off* current for a pump to start. + +\subsection sensors Sensors + +In order to measure the soil's moisture, I originally bought those cheap moisture sensors that will measure conductivity between two zinc plated conductors. The problem with these is that they corrode pretty quickly. You can alleviate the problem somewhat by measuring only once every N minutes, but still I disliked the approach. + +That's why I went for capacitive sensors with some nice aluminum plates that I can either drop into the water reservoir of my balcony's flower beds or bury at the edge of a bed. Moist soil will cause a higher capacity and we can measure it very easily with two digital pins on the ATMega328: Just set the first pin to `HIGH` and measure the time it takes for a second pin, connected to the same potential to read `HIGH`. The longer it took to achieve the `HIGH` potential on the second pin, the higher the capacity, the more moist the soil. + +There is another sensor as a simple voltage divider with 1M Ohm and 100K Ohm to measure the voltage at the solar module. This will allow us only to water plants when the sun is actually shining and with sufficient strength. + +\subsection actuators Actuators + +I connected four 3W aquarium pumps via relais that I supply with 12V from the solar module and control via analog outputs from the Arduino as most digital outputs are taken by the capacitive sensors for the soil's moisture. The pumps are submerged in a 60l tank of water that I have to refill occasionally. + +\section control_logic Control Logic + +Initially, I developed the system as a pet project but soon realized that I could utilize a state-chart to, more formally, adhere to the requirements above. Here is the SCXML document I wrote: + +\includelineno apps/arduino/WaterPump.scxml + +There are a few noteworthy things in the SCXML document above: + +* Datamodel attribute is `native and no datamodel element is given + * This will cause the transpilation process to include all datamodel statements and expressions *as is* in the generated source, without passing them to a user-supplied callback for interpretation. + * Using this approach, it is no longer possible to interpret the document with the browser. +* We can use identifiers and functions available on the Arduino platform + * As all expressions and statements will be inserted verbatim into the generated ANSI-C file, and will merely compile it as any other file when we deploy on the Arduino. +* Content of script elements is in CDATA sections while expressions in conditions are escaped + * We are using the [DOMLSSerializer](https://github.com/tklab-tud/uscxml/blob/master/src/uscxml/util/DOM.cpp#L36) to create a textual representation of the XML DOM and I could not convince it to unescape XML entities when writing the stream. +* We assume a `pump` and a `capsense` invoker + * Indeed, we will not write proper invokers but just mock them in the scaffolding. The important thing is that we get the lifetime management from the SCXML semantics. + +When we transform this document via `uscxml-transform -tc -i WaterPump.scxml -o stateMachine.c` we will arrive at a [stateMachine.c file](https://github.com/tklab-tud/uscxml/tree/master/apps/arduino/stateMachine.c) which conforms to the control flow modeled in the SCXML file. Now, we will need to write the scaffolding that connects the callbacks and starts the machine. The complete scaffolding for the generated state machine is given below: + +\includelineno apps/arduino/WaterPump.cxx + +To integrate the scaffolding and the control logic from the state-chart, the generated `stateMachine.c` is merely included into the compilation unit. To compile it all, I am using [PlatformIO](http://platformio.org) IDE as it is more convenient to work with multifile projects as apposed to the [Arduino IDE](https://www.arduino.cc/en/Main/Software), but both will work. It is important, not to compile `stateMachine.c` as a distinct compilation unit, but only as part of the scaffolding. If you have any problems to exclude it from the build process, you may always rename it into something without a `.c` extension. + +The scaffolding is rather minimal and somewhat unorthodox as I tried to get away without using `malloc` for dynamic memory allocations, but keep everything on the stack. Let's walk through the individual lines: + +* First we include the header files for [LowPower](https://github.com/rocketscream/Low-Power) and [CapacitiveSensor](https://github.com/PaulStoffregen/CapacitiveSensor). With PlatformIO, you will have to copy them into your `lib` directory along with their respective implementations. +* Then we declare some macros that define constant values. Noteworthy is the `USCXML_NO_HISTORY` macro which causes the generated ANSI-C to drop a block of code for processing history elements, which we do not use. +* Afterwards, we declare and define variables. We could have them as part of a `datamodel` element in the original SCXML document, but in my opinion, defining them here makes their existence more explicit. +* It is noteworthy that we do enumerate all the events we are going to pass and will not implement an actual queue of events. A proper queue would require malloc and there will never be more than one event to consider per microstep. +* In line 62, we include the generated ANSI-C stateMachine and define a context, as it is required to represent the state of a state-chart. +* Then we define the callbacks that we later connect to the state-chart's context: + * `invoke` will be called whenever an invocation is to be started or stopped at the end of a macro-step. This is where we merely remember whether we are supposed to start a pump (type `pump`) or deliver sensor readings from the capacitive sensors (type `capsense`). + * `matched` is called to determine whether a given transition's event descriptor is matched by a given event and a concept explained in more detail in the SCXML recommendation. In this implementation, we ignore the finer points of event descriptor matching and only match, when the event's name is a literal match for the transition's event. attribute + * `send`: When we start a pump, we are sending a delayed event to ourselves which we will have to deliver back into the state-chart after the given time in milliseconds passed. We just remember the current delay in `pumpRemain` and, subsequently, decrease it until we reach the timeout and have to deliver it. + * `dequeueExternal`: Whenever the interpreter is in a stable configuration, it makes an attempt to dequeue an external event, which will cause this callback to be triggered. If we return an event, it will be processed by triggering transitions and a change in the configuration, if we return `NULL`, the state-chart will `IDLE`. + * `isInState` is not formally a callback to be registered by the context but very useful to dispatch upon the configuration of the state chart later. +* In `setup`, we initialize the state of the platform after the `reset` button is pressed or the power came back on. I.e. we connect the callbacks and initialize the state chart by proceeding to the first `IDLE` interpreter state. +* In `loop` we process one cycle of the controller. We turn the LED on to indicate that we are processing and read the capacitive sensors if the invoker is active. Then we read the amount of light that arrives at the solar module via the voltage divider connected to `LIGHT` and transition accordingly. Afterwards we check if it is time to send the eventual `idle` event to turn of the pumps or check if we ought to activate a pump. + +One thing that helped me when developing the scaffolding was to thing about the configuration the state chart would eventually be in and observe the various events it would react to. Then to make sure that these events would be delivered when they are relevant. + +\section resources Resources + +The resources required when deploying this program on the ATMega328 are given as follows: + + Program: 10534 bytes (32.1% Full) + (.text + .data + .bootloader) + + Data: 1636 bytes (79.9% Full) + (.data + .bss + .noinit) + +There are still quite some possibilities to reduce these resources some more if we are pressed on space: + +* Event and invoker names can be enumerated +* We can drop some unused callbacks from the `uscxm_ctx` struct +* We can remove most fields of the `uscxml_elem_send` struct diff --git a/src/uscxml/interpreter/BasicContentExecutor.cpp b/src/uscxml/interpreter/BasicContentExecutor.cpp index 3d58973..7ffda91 100644 --- a/src/uscxml/interpreter/BasicContentExecutor.cpp +++ b/src/uscxml/interpreter/BasicContentExecutor.cpp @@ -283,7 +283,7 @@ void BasicContentExecutor::processLog(XERCESC_NS::DOMElement* content) { _callbacks->getLogger().log(USCXML_LOG) << d << std::endl; #else // see issue113 - _callbacks->getLogger().log(USCXML_LOG) << (label.size() > 0 ? label + ":" : "") << d << std::endl; + _callbacks->getLogger().log(USCXML_LOG) << (label.size() > 0 ? label + ": " : "") << d << std::endl; #endif } diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp index 1494ec1..cd6ca75 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -51,6 +51,7 @@ ChartToC::ChartToC(const Interpreter& other) : TransformerImpl(other), _topMostM _md5 = md5(ss.str()); _prefix = "_uscxml_" + _md5.substr(0, 8) + "_"; _allMachines.push_back(this); + _hasNativeDataModel = HAS_ATTR(_scxml, kXMLCharDataModel) && ATTR(_scxml, kXMLCharDataModel) == "native"; prepare(); findNestedMachines(); @@ -746,7 +747,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to a element->" << std::endl; + stream << " * All information pertaining to a element" << std::endl; stream << " * With late data binding, blocks of data elements are separated by NULL" << std::endl; stream << " * use USCXML_ELEM_DATA_IS_SET to test for end of a block." << std::endl; stream << " */" << std::endl; @@ -759,7 +760,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to an element->" << std::endl; + stream << " * All information pertaining to an element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_elem_assign {" << std::endl; stream << " const char* location;" << std::endl; @@ -769,7 +770,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to any state element->" << std::endl; + stream << " * All information pertaining to any state element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_state {" << std::endl; stream << " const char* name; /* eventual name */" << std::endl; @@ -786,7 +787,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to a element->" << std::endl; + stream << " * All information pertaining to a element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_transition {" << std::endl; stream << " const USCXML_NR_STATES_TYPE source;" << std::endl; @@ -802,7 +803,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to a element->" << std::endl; + stream << " * All information pertaining to a element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_elem_foreach {" << std::endl; stream << " const char* array;" << std::endl; @@ -812,7 +813,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to a element->" << std::endl; + stream << " * All information pertaining to a element" << std::endl; stream << " * Blocks of params are separated by NULL params, use" << std::endl; stream << " * USCXML_ELEM_PARAM_IS_SET to test for end of a block." << std::endl; stream << " */" << std::endl; @@ -824,7 +825,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to a element->" << std::endl; + stream << " * All information pertaining to a element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_elem_donedata {" << std::endl; stream << " const USCXML_NR_STATES_TYPE source;" << std::endl; @@ -835,7 +836,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to an element->" << std::endl; + stream << " * All information pertaining to an element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_elem_invoke {" << std::endl; stream << " const uscxml_machine* machine;" << std::endl; @@ -856,7 +857,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << std::endl; stream << "/**" << std::endl; - stream << " * All information pertaining to a element->" << std::endl; + stream << " * All information pertaining to a element" << std::endl; stream << " */" << std::endl; stream << "struct uscxml_elem_send {" << std::endl; stream << " const char* event;" << std::endl; @@ -867,7 +868,7 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << " const char* typeexpr;" << std::endl; stream << " const char* id;" << std::endl; stream << " const char* idlocation;" << std::endl; - stream << " const char* delay;" << std::endl; + stream << " unsigned long delay;" << std::endl; stream << " const char* delayexpr;" << std::endl; stream << " const char* namelist; /* not space-separated, still as in attribute value */" << std::endl; stream << " const char* content;" << std::endl; @@ -1171,7 +1172,7 @@ void ChartToC::writeExecContent(std::ostream& stream) { if (HAS_ATTR(transition, kXMLCharCond)) { stream << "static int " << _prefix << "_" << DOMUtils::idForNode(transition) << "_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) {" << std::endl; - if (HAS_ATTR(_scxml, kXMLCharDataModel) && ATTR(_scxml, kXMLCharDataModel) == "native") { + if (_hasNativeDataModel) { stream << " return (" << ATTR(transition, kXMLCharCond) << ");" << std::endl; } else { stream << " if likely(ctx->is_true != NULL) {" << std::endl; @@ -1204,10 +1205,18 @@ void ChartToC::writeExecContent(std::ostream& stream, const DOMNode* node, size_ if (!node) return; - if (node->getNodeType() == DOMNode::TEXT_NODE) { - if (boost::trim_copy(X(node->getNodeValue()).str()).length() > 0) { - if (HAS_ATTR(_scxml, kXMLCharDataModel) && ATTR(_scxml, kXMLCharDataModel) == "native") { - stream << node->getNodeValue(); + if (node->getNodeType() == DOMNode::TEXT_NODE || node->getNodeType() == DOMNode::CDATA_SECTION_NODE) { + X data; + if (node->getNodeType() == DOMNode::TEXT_NODE) { + data = node->getNodeValue(); + } else { + const DOMCharacterData* cdata = (const DOMCharacterData*)node; + data = cdata->getTextContent(); +// LOGD(USCXML_FATAL) << data; + } + if (boost::trim_copy(data.str()).length() > 0) { + if (_hasNativeDataModel) { + stream << data.str(); } else { std::string escaped = escape(X(node->getNodeValue()).str()); stream << escaped; @@ -1240,25 +1249,43 @@ void ChartToC::writeExecContent(std::ostream& stream, const DOMNode* node, size_ } } else if(TAGNAME(elem) == XML_PREFIX(elem).str() + "script") { stream << padding; - stream << "if likely(ctx->exec_content_script != NULL) {" << std::endl; - stream << padding; - stream << " if unlikely((err = ctx->exec_content_script(ctx, "; - stream << (HAS_ATTR(elem, kXMLCharSource) ? "\"" + escape(ATTR(elem, kXMLCharSource)) + "\"" : "NULL") << ", "; std::list scriptTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, elem); - if (scriptTexts.size() > 0) { - stream << "\""; - writeExecContent(stream, scriptTexts.front(), 0); - stream << "\""; + scriptTexts.splice(scriptTexts.end(), DOMUtils::filterChildType(DOMNode::CDATA_SECTION_NODE, elem)); + + if (_hasNativeDataModel) { + if (HAS_ATTR(elem, kXMLCharSource)) { + URL srcURL(ATTR(elem, kXMLCharSource)); + if (!srcURL.isAbsolute()) { + srcURL = URL::resolve(srcURL, _baseURL); + } + stream << (std::string)srcURL; + + } else if (scriptTexts.size() > 0) { + for (DOMNode* text : scriptTexts) + writeExecContent(stream, text, 0); + } } else { - stream << "NULL"; - } - stream << ")) != USCXML_ERR_OK) return err;" << std::endl; - stream << padding << "} else {" << std::endl; - stream << padding << " return USCXML_ERR_MISSING_CALLBACK;" << std::endl; - stream << padding << "}" << std::endl; + stream << "if likely(ctx->exec_content_script != NULL) {" << std::endl; + stream << padding; + stream << " if unlikely((err = ctx->exec_content_script(ctx, "; + stream << (HAS_ATTR(elem, kXMLCharSource) ? "\"" + escape(ATTR(elem, kXMLCharSource)) + "\"" : "NULL") << ", "; + std::list scriptTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, elem); + if (scriptTexts.size() > 0) { + stream << "\""; + writeExecContent(stream, scriptTexts.front(), 0); + stream << "\""; + } else { + stream << "NULL"; + } + + stream << ")) != USCXML_ERR_OK) return err;" << std::endl; + stream << padding << "} else {" << std::endl; + stream << padding << " return USCXML_ERR_MISSING_CALLBACK;" << std::endl; + stream << padding << "}" << std::endl; + } } else if(TAGNAME(elem) == XML_PREFIX(elem).str() + "log") { stream << padding; stream << "if likely(ctx->exec_content_log != NULL) {" << std::endl; @@ -1680,7 +1707,21 @@ void ChartToC::writeElementInfo(std::ostream& stream) { stream << std::endl << " /* idlocation */ "; stream << (HAS_ATTR(send, kXMLCharIdLocation) ? "\"" + escape(ATTR(send, kXMLCharIdLocation)) + "\"" : "NULL") << ", "; stream << std::endl << " /* delay */ "; - stream << (HAS_ATTR(send, kXMLCharDelay) ? "\"" + escape(ATTR(send, kXMLCharDelay)) + "\"" : "NULL") << ", "; + if (HAS_ATTR(send, kXMLCharDelay)) { + NumAttr delay(ATTR(send, kXMLCharDelay)); + if (delay.unit == "ms") { + stream << strTo(delay.value); + } else if (delay.unit == "s") { + stream << (strTo(delay.value) * 1000); + } else { + // no unit given, assume ms + stream << strTo(delay.value); + } + } else { + stream << "0"; + } + stream << ", "; + stream << std::endl << " /* delayexpr */ "; stream << (HAS_ATTR(send, kXMLCharDelayExpr) ? "\"" + escape(ATTR(send, kXMLCharDelayExpr)) + "\"" : "NULL") << ", "; stream << std::endl << " /* namelist */ "; @@ -2014,7 +2055,7 @@ void ChartToC::writeTransitions(std::ostream& stream) { stream << "," << std::endl; stream << " /* condition */ "; - stream << (HAS_ATTR(transition, kXMLCharCond) ? "\"" + escape(ATTR(transition, kXMLCharCond)) + "\"" : "NULL"); + stream << (HAS_ATTR(transition, kXMLCharCond) && !_hasNativeDataModel ? "\"" + escape(ATTR(transition, kXMLCharCond)) + "\"" : "NULL"); stream << "," << std::endl; @@ -2340,6 +2381,7 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; stream << " break;" << std::endl; stream << " }" << std::endl; + stream << "#ifndef USCXML_NO_HISTORY" << std::endl; stream << " case USCXML_STATE_HISTORY_SHALLOW:" << std::endl; stream << " case USCXML_STATE_HISTORY_DEEP: {" << std::endl; stream << " if (!bit_has_and(USCXML_GET_STATE(i).completion, ctx->history, nr_states_bytes) &&" << std::endl; @@ -2387,6 +2429,7 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " }" << std::endl; stream << " break;" << std::endl; stream << " }" << std::endl; + stream << "#endif" << std::endl; stream << " case USCXML_STATE_INITIAL: {" << std::endl; stream << " for (j = 0; j < USCXML_NUMBER_TRANS; j++) {" << std::endl; stream << " if (ctx->machine->transitions[j].source == i) {" << std::endl; diff --git a/src/uscxml/transform/ChartToC.h b/src/uscxml/transform/ChartToC.h index 9fe6a9f..bfe0e99 100644 --- a/src/uscxml/transform/ChartToC.h +++ b/src/uscxml/transform/ChartToC.h @@ -90,6 +90,7 @@ protected: std::list _allMachines; std::list* _prefixes; + bool _hasNativeDataModel; }; } diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp index 2c73e60..2fa335d 100644 --- a/src/uscxml/transform/ChartToPromela.cpp +++ b/src/uscxml/transform/ChartToPromela.cpp @@ -694,7 +694,7 @@ void ChartToPromela::writeVariables(std::ostream& stream) { if (allTypes.types.find(identifier) != allTypes.types.end()) { type = allTypes.types[identifier].name; } else { - LOGD(USCXML_ERROR) << "Automatic or no type for '" << identifier << "' but no type resolved"; + LOGD(USCXML_ERROR) << "Automatic or no type for '" << identifier << "' but no type resolved" << std::endl; continue; } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bc105cf..772c636 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,7 +46,9 @@ endfunction() # simple one file tests USCXML_TEST_COMPILE(NAME test-utils LABEL general/test-utils FILES src/test-utils.cpp) -USCXML_TEST_COMPILE(NAME test-extensions LABEL general/test-extensions FILES src/test-extensions.cpp ../contrib/src/uscxml/PausableDelayedEventQueue.cpp) +if(WITH_DM_LUA) + USCXML_TEST_COMPILE(NAME test-extensions LABEL general/test-extensions FILES src/test-extensions.cpp ../contrib/src/uscxml/PausableDelayedEventQueue.cpp ../contrib/src/uscxml/ExtendedLuaDataModel.cpp) +endif() USCXML_TEST_COMPILE(NAME test-url LABEL general/test-url FILES src/test-url.cpp) USCXML_TEST_COMPILE(NAME test-lifecycle LABEL general/test-lifecycle FILES src/test-lifecycle.cpp) USCXML_TEST_COMPILE(NAME test-validating LABEL general/test-validating FILES src/test-validating.cpp) diff --git a/test/ctest/CTestCustom.ctest.in b/test/ctest/CTestCustom.ctest.in index 8f30989..6d4fa56 100644 --- a/test/ctest/CTestCustom.ctest.in +++ b/test/ctest/CTestCustom.ctest.in @@ -175,6 +175,8 @@ set(CTEST_CUSTOM_TESTS_IGNORE # we do not support io processors yet "w3c/gen/c/ecma/test201.scxml" # basichttp "w3c/gen/c/ecma/test453.scxml" # functions as first-class objects + "w3c/gen/c/ecma/test446.scxml" # No URLs at runtime anymore + "w3c/gen/c/ecma/test552.scxml" # No URLs at runtime anymore "w3c/gen/c/ecma/test500.scxml" # _ioprocessors "w3c/gen/c/ecma/test501.scxml" # _ioprocessors "w3c/gen/c/ecma/test509.scxml" # _ioprocessors / basichttp @@ -222,6 +224,7 @@ set(CTEST_CUSTOM_TESTS_IGNORE "w3c/gen/c/lua/test532.scxml" # _ioprocessors / basichttp "w3c/gen/c/lua/test534.scxml" # _ioprocessors / basichttp "w3c/gen/c/lua/test558.scxml" # content per url + "w3c/gen/c/lua/test552.scxml" # content per url "w3c/gen/c/lua/test567.scxml" # _ioprocessors / basichttp "w3c/gen/c/lua/test569.scxml" # _ioprocessors "w3c/gen/c/lua/test577.scxml" # basichttp diff --git a/test/src/test-c-machine.scxml.c b/test/src/test-c-machine.scxml.c index 586a286..f39e5dc 100644 --- a/test/src/test-c-machine.scxml.c +++ b/test/src/test-c-machine.scxml.c @@ -1,6 +1,6 @@ /** Generated from source: - file:///Users/sradomski/Documents/TK/Code/uscxml2/test/w3c/lua/test240.scxml + file:///Users/sradomski/Documents/TK/Code/uscxml/test/w3c/lua/test240.scxml */ #ifndef USCXML_NO_STDTYPES_H @@ -208,7 +208,7 @@ struct uscxml_machine { }; /** - * All information pertaining to a element-> + * All information pertaining to a 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. */ @@ -220,7 +220,7 @@ struct uscxml_elem_data { }; /** - * All information pertaining to an element-> + * All information pertaining to an element */ struct uscxml_elem_assign { const char* location; @@ -229,7 +229,7 @@ struct uscxml_elem_assign { }; /** - * All information pertaining to any state element-> + * All information pertaining to any state element */ struct uscxml_state { const char* name; /* eventual name */ @@ -245,7 +245,7 @@ struct uscxml_state { }; /** - * All information pertaining to a element-> + * All information pertaining to a element */ struct uscxml_transition { const USCXML_NR_STATES_TYPE source; @@ -260,7 +260,7 @@ struct uscxml_transition { }; /** - * All information pertaining to a element-> + * All information pertaining to a element */ struct uscxml_elem_foreach { const char* array; @@ -269,7 +269,7 @@ struct uscxml_elem_foreach { }; /** - * All information pertaining to a element-> + * All information pertaining to a element * Blocks of params are separated by NULL params, use * USCXML_ELEM_PARAM_IS_SET to test for end of a block. */ @@ -280,7 +280,7 @@ struct uscxml_elem_param { }; /** - * All information pertaining to a element-> + * All information pertaining to a element */ struct uscxml_elem_donedata { const USCXML_NR_STATES_TYPE source; @@ -290,7 +290,7 @@ struct uscxml_elem_donedata { }; /** - * All information pertaining to an element-> + * All information pertaining to an element */ struct uscxml_elem_invoke { const uscxml_machine* machine; @@ -310,7 +310,7 @@ struct uscxml_elem_invoke { }; /** - * All information pertaining to a element-> + * All information pertaining to a element */ struct uscxml_elem_send { const char* event; @@ -321,7 +321,7 @@ struct uscxml_elem_send { const char* typeexpr; const char* id; const char* idlocation; - const char* delay; + unsigned long delay; const char* delayexpr; const char* namelist; /* not space-separated, still as in attribute value */ const char* content; @@ -368,25 +368,25 @@ struct uscxml_ctx { #endif /* forward declare machines to allow references */ -extern const uscxml_machine _uscxml_F2DFDF85_machine; -extern const uscxml_machine _uscxml_88325DE6_machine; -extern const uscxml_machine _uscxml_8B0504D7_machine; +extern const uscxml_machine _uscxml_ED395C23__machine; +extern const uscxml_machine _uscxml_7847B274__machine; +extern const uscxml_machine _uscxml_DB2A83B0__machine; #ifndef USCXML_NO_ELEM_INFO -static const uscxml_elem_data _uscxml_F2DFDF85_elem_datas[2] = { +static const uscxml_elem_data _uscxml_ED395C23__elem_datas[2] = { /* id, src, expr, content */ { "Var1", NULL, "1", NULL }, { NULL, NULL, NULL, NULL } }; -static const uscxml_elem_param _uscxml_F2DFDF85_elem_params[2] = { +static const uscxml_elem_param _uscxml_ED395C23__elem_params[2] = { /* name, expr, location */ { "Var1", "1", NULL }, { NULL, NULL, NULL } }; -static const uscxml_elem_send _uscxml_F2DFDF85_elem_sends[1] = { +static const uscxml_elem_send _uscxml_ED395C23__elem_sends[1] = { { /* event */ "timeout", /* eventexpr */ NULL, @@ -396,7 +396,7 @@ static const uscxml_elem_send _uscxml_F2DFDF85_elem_sends[1] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ "2000", + /* delay */ 2000, /* delayexpr */ NULL, /* namelist */ NULL, /* content */ NULL, @@ -405,7 +405,7 @@ static const uscxml_elem_send _uscxml_F2DFDF85_elem_sends[1] = { } }; -static const uscxml_elem_donedata _uscxml_F2DFDF85_elem_donedatas[1] = { +static const uscxml_elem_donedata _uscxml_ED395C23__elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; @@ -414,9 +414,9 @@ static const uscxml_elem_donedata _uscxml_F2DFDF85_elem_donedatas[1] = { #ifndef USCXML_NO_ELEM_INFO -static const uscxml_elem_invoke _uscxml_F2DFDF85_elem_invokes[2] = { +static const uscxml_elem_invoke _uscxml_ED395C23__elem_invokes[2] = { { - /* machine */ &_uscxml_88325DE6_machine, + /* machine */ &_uscxml_7847B274__machine, /* type */ "http://www.w3.org/TR/scxml/", /* typeexpr */ NULL, /* src */ NULL, @@ -432,7 +432,7 @@ static const uscxml_elem_invoke _uscxml_F2DFDF85_elem_invokes[2] = { /* contentexpr */ NULL, }, { - /* machine */ &_uscxml_8B0504D7_machine, + /* machine */ &_uscxml_DB2A83B0__machine, /* type */ "http://www.w3.org/TR/scxml/", /* typeexpr */ NULL, /* src */ NULL, @@ -442,7 +442,7 @@ static const uscxml_elem_invoke _uscxml_F2DFDF85_elem_invokes[2] = { /* sourcename */ "s02", /* namelist */ NULL, /* autoforward */ 0, - /* params */ &_uscxml_F2DFDF85_elem_params[0], + /* params */ &_uscxml_ED395C23__elem_params[0], /* finalize */ NULL, /* content */ NULL, /* contentexpr */ NULL, @@ -453,32 +453,32 @@ static const uscxml_elem_invoke _uscxml_F2DFDF85_elem_invokes[2] = { #ifndef USCXML_NO_EXEC_CONTENT -static int _uscxml_F2DFDF85_s0_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_ED395C23__s0_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_F2DFDF85_elem_sends[0])) != USCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_uscxml_ED395C23__elem_sends[0])) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_s0_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { - _uscxml_F2DFDF85_s0_on_entry_0(ctx, state, event); +static int _uscxml_ED395C23__s0_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_ED395C23__s0_on_entry_0(ctx, state, event); return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_s01_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) { - ctx->invoke(ctx, s, &_uscxml_F2DFDF85_elem_invokes[0], uninvoke); +static int _uscxml_ED395C23__s01_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) { + ctx->invoke(ctx, s, &_uscxml_ED395C23__elem_invokes[0], uninvoke); return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_s02_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) { - ctx->invoke(ctx, s, &_uscxml_F2DFDF85_elem_invokes[1], uninvoke); +static int _uscxml_ED395C23__s02_invoke(const uscxml_ctx* ctx, const uscxml_state* s, const uscxml_elem_invoke* invocation, unsigned char uninvoke) { + ctx->invoke(ctx, s, &_uscxml_ED395C23__elem_invokes[1], uninvoke); return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_pass_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_ED395C23__pass_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { int err = USCXML_ERR_OK; if likely(ctx->exec_content_log != NULL) { if unlikely((ctx->exec_content_log(ctx, "Outcome", "'pass'")) != USCXML_ERR_OK) return err; @@ -488,12 +488,12 @@ static int _uscxml_F2DFDF85_pass_on_entry_0(const uscxml_ctx* ctx, const uscxml_ return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_pass_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { - _uscxml_F2DFDF85_pass_on_entry_0(ctx, state, event); +static int _uscxml_ED395C23__pass_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_ED395C23__pass_on_entry_0(ctx, state, event); return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_fail_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_ED395C23__fail_on_entry_0(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { int err = USCXML_ERR_OK; if likely(ctx->exec_content_log != NULL) { if unlikely((ctx->exec_content_log(ctx, "Outcome", "'fail'")) != USCXML_ERR_OK) return err; @@ -503,8 +503,8 @@ static int _uscxml_F2DFDF85_fail_on_entry_0(const uscxml_ctx* ctx, const uscxml_ return USCXML_ERR_OK; } -static int _uscxml_F2DFDF85_fail_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { - _uscxml_F2DFDF85_fail_on_entry_0(ctx, state, event); +static int _uscxml_ED395C23__fail_on_entry(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { + _uscxml_ED395C23__fail_on_entry_0(ctx, state, event); return USCXML_ERR_OK; } @@ -512,7 +512,7 @@ static int _uscxml_F2DFDF85_fail_on_entry(const uscxml_ctx* ctx, const uscxml_st #ifndef USCXML_NO_ELEM_INFO -static const uscxml_state _uscxml_F2DFDF85_states[6] = { +static const uscxml_state _uscxml_ED395C23__states[6] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, @@ -522,13 +522,13 @@ static const uscxml_state _uscxml_F2DFDF85_states[6] = { /* children */ { 0x32 /* 010011 */ }, /* completion */ { 0x02 /* 010000 */ }, /* ancestors */ { 0x00 /* 000000 */ }, - /* data */ &_uscxml_F2DFDF85_elem_datas[0], + /* data */ &_uscxml_ED395C23__elem_datas[0], /* type */ USCXML_STATE_COMPOUND, }, { /* state number 1 */ /* name */ "s0", /* parent */ 0, - /* onentry */ _uscxml_F2DFDF85_s0_on_entry, + /* onentry */ _uscxml_ED395C23__s0_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x0c /* 001100 */ }, @@ -542,7 +542,7 @@ static const uscxml_state _uscxml_F2DFDF85_states[6] = { /* parent */ 1, /* onentry */ NULL, /* onexit */ NULL, - /* invoke */ _uscxml_F2DFDF85_s01_invoke, + /* invoke */ _uscxml_ED395C23__s01_invoke, /* children */ { 0x00 /* 000000 */ }, /* completion */ { 0x00 /* 000000 */ }, /* ancestors */ { 0x03 /* 110000 */ }, @@ -554,7 +554,7 @@ static const uscxml_state _uscxml_F2DFDF85_states[6] = { /* parent */ 1, /* onentry */ NULL, /* onexit */ NULL, - /* invoke */ _uscxml_F2DFDF85_s02_invoke, + /* invoke */ _uscxml_ED395C23__s02_invoke, /* children */ { 0x00 /* 000000 */ }, /* completion */ { 0x00 /* 000000 */ }, /* ancestors */ { 0x03 /* 110000 */ }, @@ -564,7 +564,7 @@ static const uscxml_state _uscxml_F2DFDF85_states[6] = { { /* state number 4 */ /* name */ "pass", /* parent */ 0, - /* onentry */ _uscxml_F2DFDF85_pass_on_entry, + /* onentry */ _uscxml_ED395C23__pass_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -576,7 +576,7 @@ static const uscxml_state _uscxml_F2DFDF85_states[6] = { { /* state number 5 */ /* name */ "fail", /* parent */ 0, - /* onentry */ _uscxml_F2DFDF85_fail_on_entry, + /* onentry */ _uscxml_ED395C23__fail_on_entry, /* onexit */ NULL, /* invoke */ NULL, /* children */ { 0x00 /* 000000 */ }, @@ -591,7 +591,7 @@ static const uscxml_state _uscxml_F2DFDF85_states[6] = { #ifndef USCXML_NO_ELEM_INFO -static const uscxml_transition _uscxml_F2DFDF85_transitions[5] = { +static const uscxml_transition _uscxml_ED395C23__transitions[5] = { { /* transition number 1 with priority 0 target: s02 */ @@ -664,22 +664,22 @@ static const uscxml_transition _uscxml_F2DFDF85_transitions[5] = { #ifndef USCXML_NO_ELEM_INFO #ifndef USCXML_MACHINE -# define USCXML_MACHINE _uscxml_F2DFDF85_machine +# define USCXML_MACHINE _uscxml_ED395C23__machine #endif -#define USCXML_MACHINE_0 _uscxml_F2DFDF85_machine -#define USCXML_MACHINE_TEST240_SCXML _uscxml_F2DFDF85_machine +#define USCXML_MACHINE_0 _uscxml_ED395C23__machine +#define USCXML_MACHINE_TEST240_SCXML _uscxml_ED395C23__machine -const uscxml_machine _uscxml_F2DFDF85_machine = { +const uscxml_machine _uscxml_ED395C23__machine = { /* flags */ 0, /* nr_states */ 6, /* nr_transitions */ 5, /* name */ "test240.scxml", /* datamodel */ "lua", - /* uuid */ "F2DFDF85E1407B6D03CC162B96F43FC7", - /* states */ &_uscxml_F2DFDF85_states[0], - /* transitions */ &_uscxml_F2DFDF85_transitions[0], + /* uuid */ "ED395C2320352170727CA99C3797822B", + /* states */ &_uscxml_ED395C23__states[0], + /* transitions */ &_uscxml_ED395C23__transitions[0], /* parent */ NULL, - /* donedata */ &_uscxml_F2DFDF85_elem_donedatas[0], + /* donedata */ &_uscxml_ED395C23__elem_donedatas[0], /* script */ NULL }; @@ -687,13 +687,13 @@ const uscxml_machine _uscxml_F2DFDF85_machine = { #ifndef USCXML_NO_ELEM_INFO -static const uscxml_elem_data _uscxml_88325DE6_elem_datas[2] = { +static const uscxml_elem_data _uscxml_7847B274__elem_datas[2] = { /* id, src, expr, content */ { "Var1", NULL, "0", NULL }, { NULL, NULL, NULL, NULL } }; -static const uscxml_elem_send _uscxml_88325DE6_elem_sends[2] = { +static const uscxml_elem_send _uscxml_7847B274__elem_sends[2] = { { /* event */ "success", /* eventexpr */ NULL, @@ -703,7 +703,7 @@ static const uscxml_elem_send _uscxml_88325DE6_elem_sends[2] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ NULL, + /* delay */ 0, /* delayexpr */ NULL, /* namelist */ NULL, /* content */ NULL, @@ -719,7 +719,7 @@ static const uscxml_elem_send _uscxml_88325DE6_elem_sends[2] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ NULL, + /* delay */ 0, /* delayexpr */ NULL, /* namelist */ NULL, /* content */ NULL, @@ -728,7 +728,7 @@ static const uscxml_elem_send _uscxml_88325DE6_elem_sends[2] = { } }; -static const uscxml_elem_donedata _uscxml_88325DE6_elem_donedatas[1] = { +static const uscxml_elem_donedata _uscxml_7847B274__elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; @@ -741,26 +741,26 @@ static const uscxml_elem_donedata _uscxml_88325DE6_elem_donedatas[1] = { #ifndef USCXML_NO_EXEC_CONTENT -static int _uscxml_88325DE6_sub01_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) { +static int _uscxml_7847B274__sub01_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) { if likely(ctx->is_true != NULL) { return (ctx->is_true(ctx, "Var1==1")); } return USCXML_ERR_MISSING_CALLBACK; } -static int _uscxml_88325DE6_sub01_transition0_on_trans(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_7847B274__sub01_transition0_on_trans(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_88325DE6_elem_sends[0])) != USCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_uscxml_7847B274__elem_sends[0])) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } return USCXML_ERR_OK; } -static int _uscxml_88325DE6_sub01_transition1_on_trans(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_7847B274__sub01_transition1_on_trans(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_88325DE6_elem_sends[1])) != USCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_uscxml_7847B274__elem_sends[1])) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } @@ -771,7 +771,7 @@ static int _uscxml_88325DE6_sub01_transition1_on_trans(const uscxml_ctx* ctx, co #ifndef USCXML_NO_ELEM_INFO -static const uscxml_state _uscxml_88325DE6_states[3] = { +static const uscxml_state _uscxml_7847B274__states[3] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, @@ -781,7 +781,7 @@ static const uscxml_state _uscxml_88325DE6_states[3] = { /* children */ { 0x06 /* 011 */ }, /* completion */ { 0x02 /* 010 */ }, /* ancestors */ { 0x00 /* 000 */ }, - /* data */ &_uscxml_88325DE6_elem_datas[0], + /* data */ &_uscxml_7847B274__elem_datas[0], /* type */ USCXML_STATE_COMPOUND, }, { /* state number 1 */ @@ -814,7 +814,7 @@ static const uscxml_state _uscxml_88325DE6_states[3] = { #ifndef USCXML_NO_ELEM_INFO -static const uscxml_transition _uscxml_88325DE6_transitions[2] = { +static const uscxml_transition _uscxml_7847B274__transitions[2] = { { /* transition number 0 with priority 0 target: subFinal1 */ @@ -822,8 +822,8 @@ static const uscxml_transition _uscxml_88325DE6_transitions[2] = { /* target */ { 0x04 /* 001 */ }, /* event */ NULL, /* condition */ "Var1==1", - /* is_enabled */ _uscxml_88325DE6_sub01_transition0_is_enabled, - /* ontrans */ _uscxml_88325DE6_sub01_transition0_on_trans, + /* is_enabled */ _uscxml_7847B274__sub01_transition0_is_enabled, + /* ontrans */ _uscxml_7847B274__sub01_transition0_on_trans, /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x03 /* 11 */ }, /* exit set */ { 0x06 /* 011 */ } @@ -836,7 +836,7 @@ static const uscxml_transition _uscxml_88325DE6_transitions[2] = { /* event */ NULL, /* condition */ NULL, /* is_enabled */ NULL, - /* ontrans */ _uscxml_88325DE6_sub01_transition1_on_trans, + /* ontrans */ _uscxml_7847B274__sub01_transition1_on_trans, /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x03 /* 11 */ }, /* exit set */ { 0x06 /* 011 */ } @@ -848,22 +848,22 @@ static const uscxml_transition _uscxml_88325DE6_transitions[2] = { #ifndef USCXML_NO_ELEM_INFO #ifndef USCXML_MACHINE -# define USCXML_MACHINE _uscxml_88325DE6_machine +# define USCXML_MACHINE _uscxml_7847B274__machine #endif -#define USCXML_MACHINE_1 _uscxml_88325DE6_machine -#define USCXML_MACHINE_TEST240_SCXML_S01_INVOKE0_CONTENT0_SCXML0 _uscxml_88325DE6_machine +#define USCXML_MACHINE_1 _uscxml_7847B274__machine +#define USCXML_MACHINE_TEST240_SCXML_S01_INVOKE0_CONTENT0_SCXML0 _uscxml_7847B274__machine -const uscxml_machine _uscxml_88325DE6_machine = { +const uscxml_machine _uscxml_7847B274__machine = { /* flags */ 0, /* nr_states */ 3, /* nr_transitions */ 2, /* name */ "test240.scxml.s01_invoke0_content0_scxml0", /* datamodel */ "lua", - /* uuid */ "88325DE699193976BBBCF380C181A014", - /* states */ &_uscxml_88325DE6_states[0], - /* transitions */ &_uscxml_88325DE6_transitions[0], - /* parent */ &_uscxml_F2DFDF85_machine, - /* donedata */ &_uscxml_88325DE6_elem_donedatas[0], + /* uuid */ "7847B274CA8610349BFA9F21A78B590E", + /* states */ &_uscxml_7847B274__states[0], + /* transitions */ &_uscxml_7847B274__transitions[0], + /* parent */ &_uscxml_ED395C23__machine, + /* donedata */ &_uscxml_7847B274__elem_donedatas[0], /* script */ NULL }; @@ -871,13 +871,13 @@ const uscxml_machine _uscxml_88325DE6_machine = { #ifndef USCXML_NO_ELEM_INFO -static const uscxml_elem_data _uscxml_8B0504D7_elem_datas[2] = { +static const uscxml_elem_data _uscxml_DB2A83B0__elem_datas[2] = { /* id, src, expr, content */ { "Var1", NULL, "0", NULL }, { NULL, NULL, NULL, NULL } }; -static const uscxml_elem_send _uscxml_8B0504D7_elem_sends[2] = { +static const uscxml_elem_send _uscxml_DB2A83B0__elem_sends[2] = { { /* event */ "success", /* eventexpr */ NULL, @@ -887,7 +887,7 @@ static const uscxml_elem_send _uscxml_8B0504D7_elem_sends[2] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ NULL, + /* delay */ 0, /* delayexpr */ NULL, /* namelist */ NULL, /* content */ NULL, @@ -903,7 +903,7 @@ static const uscxml_elem_send _uscxml_8B0504D7_elem_sends[2] = { /* typeexpr */ NULL, /* id */ NULL, /* idlocation */ NULL, - /* delay */ NULL, + /* delay */ 0, /* delayexpr */ NULL, /* namelist */ NULL, /* content */ NULL, @@ -912,7 +912,7 @@ static const uscxml_elem_send _uscxml_8B0504D7_elem_sends[2] = { } }; -static const uscxml_elem_donedata _uscxml_8B0504D7_elem_donedatas[1] = { +static const uscxml_elem_donedata _uscxml_DB2A83B0__elem_donedatas[1] = { /* source, content, contentexpr, params */ { 0, NULL, NULL, NULL } }; @@ -925,26 +925,26 @@ static const uscxml_elem_donedata _uscxml_8B0504D7_elem_donedatas[1] = { #ifndef USCXML_NO_EXEC_CONTENT -static int _uscxml_8B0504D7_sub02_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) { +static int _uscxml_DB2A83B0__sub02_transition0_is_enabled(const uscxml_ctx* ctx, const uscxml_transition* transition) { if likely(ctx->is_true != NULL) { return (ctx->is_true(ctx, "Var1==1")); } return USCXML_ERR_MISSING_CALLBACK; } -static int _uscxml_8B0504D7_sub02_transition0_on_trans(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_DB2A83B0__sub02_transition0_on_trans(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_8B0504D7_elem_sends[0])) != USCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_uscxml_DB2A83B0__elem_sends[0])) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } return USCXML_ERR_OK; } -static int _uscxml_8B0504D7_sub02_transition1_on_trans(const uscxml_ctx* ctx, const uscxml_state* state, const void* event) { +static int _uscxml_DB2A83B0__sub02_transition1_on_trans(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_8B0504D7_elem_sends[1])) != USCXML_ERR_OK) return err; + if ((ctx->exec_content_send(ctx, &_uscxml_DB2A83B0__elem_sends[1])) != USCXML_ERR_OK) return err; } else { return USCXML_ERR_MISSING_CALLBACK; } @@ -955,7 +955,7 @@ static int _uscxml_8B0504D7_sub02_transition1_on_trans(const uscxml_ctx* ctx, co #ifndef USCXML_NO_ELEM_INFO -static const uscxml_state _uscxml_8B0504D7_states[3] = { +static const uscxml_state _uscxml_DB2A83B0__states[3] = { { /* state number 0 */ /* name */ NULL, /* parent */ 0, @@ -965,7 +965,7 @@ static const uscxml_state _uscxml_8B0504D7_states[3] = { /* children */ { 0x06 /* 011 */ }, /* completion */ { 0x02 /* 010 */ }, /* ancestors */ { 0x00 /* 000 */ }, - /* data */ &_uscxml_8B0504D7_elem_datas[0], + /* data */ &_uscxml_DB2A83B0__elem_datas[0], /* type */ USCXML_STATE_COMPOUND, }, { /* state number 1 */ @@ -998,7 +998,7 @@ static const uscxml_state _uscxml_8B0504D7_states[3] = { #ifndef USCXML_NO_ELEM_INFO -static const uscxml_transition _uscxml_8B0504D7_transitions[2] = { +static const uscxml_transition _uscxml_DB2A83B0__transitions[2] = { { /* transition number 0 with priority 0 target: subFinal2 */ @@ -1006,8 +1006,8 @@ static const uscxml_transition _uscxml_8B0504D7_transitions[2] = { /* target */ { 0x04 /* 001 */ }, /* event */ NULL, /* condition */ "Var1==1", - /* is_enabled */ _uscxml_8B0504D7_sub02_transition0_is_enabled, - /* ontrans */ _uscxml_8B0504D7_sub02_transition0_on_trans, + /* is_enabled */ _uscxml_DB2A83B0__sub02_transition0_is_enabled, + /* ontrans */ _uscxml_DB2A83B0__sub02_transition0_on_trans, /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x03 /* 11 */ }, /* exit set */ { 0x06 /* 011 */ } @@ -1020,7 +1020,7 @@ static const uscxml_transition _uscxml_8B0504D7_transitions[2] = { /* event */ NULL, /* condition */ NULL, /* is_enabled */ NULL, - /* ontrans */ _uscxml_8B0504D7_sub02_transition1_on_trans, + /* ontrans */ _uscxml_DB2A83B0__sub02_transition1_on_trans, /* type */ USCXML_TRANS_SPONTANEOUS, /* conflicts */ { 0x03 /* 11 */ }, /* exit set */ { 0x06 /* 011 */ } @@ -1032,22 +1032,22 @@ static const uscxml_transition _uscxml_8B0504D7_transitions[2] = { #ifndef USCXML_NO_ELEM_INFO #ifndef USCXML_MACHINE -# define USCXML_MACHINE _uscxml_8B0504D7_machine +# define USCXML_MACHINE _uscxml_DB2A83B0__machine #endif -#define USCXML_MACHINE_2 _uscxml_8B0504D7_machine -#define USCXML_MACHINE_TEST240_SCXML_S02_INVOKE0_CONTENT0_SCXML0 _uscxml_8B0504D7_machine +#define USCXML_MACHINE_2 _uscxml_DB2A83B0__machine +#define USCXML_MACHINE_TEST240_SCXML_S02_INVOKE0_CONTENT0_SCXML0 _uscxml_DB2A83B0__machine -const uscxml_machine _uscxml_8B0504D7_machine = { +const uscxml_machine _uscxml_DB2A83B0__machine = { /* flags */ 0, /* nr_states */ 3, /* nr_transitions */ 2, /* name */ "test240.scxml.s02_invoke0_content0_scxml0", /* datamodel */ "lua", - /* uuid */ "8B0504D789C25925F9E8A0C290F83773", - /* states */ &_uscxml_8B0504D7_states[0], - /* transitions */ &_uscxml_8B0504D7_transitions[0], - /* parent */ &_uscxml_F2DFDF85_machine, - /* donedata */ &_uscxml_8B0504D7_elem_donedatas[0], + /* uuid */ "DB2A83B067CD692F49AB0A6A6F13C5D0", + /* states */ &_uscxml_DB2A83B0__states[0], + /* transitions */ &_uscxml_DB2A83B0__transitions[0], + /* parent */ &_uscxml_ED395C23__machine, + /* donedata */ &_uscxml_DB2A83B0__elem_donedatas[0], /* script */ NULL }; @@ -1346,6 +1346,7 @@ ESTABLISH_ENTRY_SET: 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) && @@ -1393,6 +1394,7 @@ ESTABLISH_ENTRY_SET: } break; } +#endif case USCXML_STATE_INITIAL: { for (j = 0; j < USCXML_NUMBER_TRANS; j++) { if (ctx->machine->transitions[j].source == i) { diff --git a/test/src/test-extensions.cpp b/test/src/test-extensions.cpp index 7024689..626f8e5 100644 --- a/test/src/test-extensions.cpp +++ b/test/src/test-extensions.cpp @@ -4,6 +4,7 @@ #include "uscxml/interpreter/BasicEventQueue.h" #include "uscxml/interpreter/BasicDelayedEventQueue.h" #include "uscxml/PausableDelayedEventQueue.h" +#include "uscxml/ExtendedLuaDataModel.h" #include // for evutil_socket_t @@ -107,6 +108,27 @@ bool testPausableEventQueue() { } + +static const char *customLuaExtension = + "" + " " + " " + "" + ; + +bool testLuaExtension() { + Factory::getInstance()->registerDataModel(new ExtendedLuaDataModel()); + Interpreter exLua = Interpreter::fromXML(customLuaExtension, ""); + InterpreterState state; + + while ((state = exLua.step(0)) != USCXML_IDLE) {} + + return true; +} + int main(int argc, char** argv) { - testPausableEventQueue(); + testLuaExtension(); +// testPausableEventQueue(); } diff --git a/test/src/test-gen-c.cpp b/test/src/test-gen-c.cpp index e184c10..b7cee32 100644 --- a/test/src/test-gen-c.cpp +++ b/test/src/test-gen-c.cpp @@ -21,7 +21,7 @@ #ifndef AUTOINCLUDE_TEST #include "test-c-machine.scxml.c" -//#include "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/test/gen/c/ecma/test446.scxml.machine.c" +//#include "/Users/sradomski/Documents/TK/Code/uscxml/build/cli/test/gen/c/lua/test192.scxml.machine.c" #endif //#include "uscxml/util/URL.h" @@ -546,25 +546,24 @@ public: } size_t delayMs = 0; - std::string delay; if (send->delayexpr != NULL) { - delay = USER_DATA(ctx)->dataModel.evalAsData(send->delayexpr).atom; - } else if (send->delay != NULL) { - delay = send->delay; - } - if (delay.size() > 0) { - boost::trim(delay); - - NumAttr delayAttr(delay); - if (iequals(delayAttr.unit, "ms")) { - delayMs = strTo(delayAttr.value); - } else if (iequals(delayAttr.unit, "s")) { - delayMs = strTo(delayAttr.value) * 1000; - } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds - delayMs = strTo(delayAttr.value); - } else { - std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'"; + std::string delay = USER_DATA(ctx)->dataModel.evalAsData(send->delayexpr).atom; + if (delay.size() > 0) { + boost::trim(delay); + + NumAttr delayAttr(delay); + if (iequals(delayAttr.unit, "ms")) { + delayMs = strTo(delayAttr.value); + } else if (iequals(delayAttr.unit, "s")) { + delayMs = strTo(delayAttr.value) * 1000; + } else if (delayAttr.unit.length() == 0) { // unit less delay is interpreted as milliseconds + delayMs = strTo(delayAttr.value); + } else { + std::cerr << "Cannot make sense of delay value " << delay << ": does not end in 's' or 'ms'"; + } } + } else if (send->delay > 0) { + delayMs = send->delay; } if (USER_DATA(ctx)->invokeId.size() > 0) { -- cgit v0.12