diff --git a/openBeken_win32_mvsc2017.vcxproj b/openBeken_win32_mvsc2017.vcxproj index 4f6cfb17f..4b616f94e 100644 --- a/openBeken_win32_mvsc2017.vcxproj +++ b/openBeken_win32_mvsc2017.vcxproj @@ -831,6 +831,7 @@ + diff --git a/openBeken_win32_mvsc2017.vcxproj.filters b/openBeken_win32_mvsc2017.vcxproj.filters index 4b25b3d02..fb9edd272 100644 --- a/openBeken_win32_mvsc2017.vcxproj.filters +++ b/openBeken_win32_mvsc2017.vcxproj.filters @@ -833,6 +833,9 @@ Drv + + SelfTest + diff --git a/src/cmnds/cmd_eventHandlers.c b/src/cmnds/cmd_eventHandlers.c index f8a3e5bd4..da24cf79a 100644 --- a/src/cmnds/cmd_eventHandlers.c +++ b/src/cmnds/cmd_eventHandlers.c @@ -123,7 +123,7 @@ static int EVENT_ParseRelation(const char *s) { return EVENT_DEFAULT; } -static int EVENT_ParseEventName(const char *s) { +int EVENT_ParseEventName(const char *s) { if(!wal_strnicmp(s,"channel",7)) { return CMD_EVENT_CHANGE_CHANNEL0 + atoi(s+7); } @@ -364,6 +364,8 @@ void EventHandlers_FireEvent(byte eventCode, int argument) { } ev = ev->next; } + + CMD_Script_ProcessWaitersForEvent(eventCode, argument); } void EventHandlers_FireEvent_String(byte eventCode, const char *argument) { struct eventHandler_s *ev; @@ -435,7 +437,7 @@ static commandResult_t CMD_AddEventHandler(const void *context, const char *cmd, eventCode = EVENT_ParseEventName(eventName); if(eventCode == CMD_EVENT_NONE) { - ADDLOG_ERROR(LOG_FEATURE_EVENT, "CMD_AddEventHandler: %s is not a valid event",eventName); + ADDLOG_ERROR(LOG_FEATURE_EVENT, "%s is not a valid event",eventName); return CMD_RES_BAD_ARGUMENT; } diff --git a/src/cmnds/cmd_public.h b/src/cmnds/cmd_public.h index c5472bd32..5610938c8 100644 --- a/src/cmnds/cmd_public.h +++ b/src/cmnds/cmd_public.h @@ -122,6 +122,7 @@ enum EventCode { CMD_EVENT_MAX_TYPES }; +int EVENT_ParseEventName(const char *s); // the slider control in the UI emits values //in the range from 154-500 (defined diff --git a/src/cmnds/cmd_script.c b/src/cmnds/cmd_script.c index 677fa1889..a40eb52b6 100644 --- a/src/cmnds/cmd_script.c +++ b/src/cmnds/cmd_script.c @@ -238,6 +238,9 @@ typedef struct scriptInstance_s { const char *curLine; int currentDelayMS; + int waitingForEvent; + int waitingForArgument; + struct scriptInstance_s *next; } scriptInstance_t; @@ -361,6 +364,10 @@ void SVM_RunThread(scriptInstance_t *t) { while(1) { loop++; + // check if "waitFor" was executed last frame + if (t->waitingForEvent) { + return; + } if(t->curLine == 0) { t->curLine = 0; t->curFile = 0; @@ -423,22 +430,45 @@ void SVM_RunThreads(int deltaMS) { g_activeThread = g_scriptThreads; while(g_activeThread) { - if(g_activeThread->currentDelayMS > 0) { - g_activeThread->currentDelayMS -= deltaMS; - // the following block is needed to handle with long freezes on simulator - if (g_activeThread->currentDelayMS < 0) { - g_activeThread->currentDelayMS = 0; - } + if (g_activeThread->waitingForEvent) { + // do nothing c_sleep++; - } else { - SVM_RunThread(g_activeThread); - c_run++; + } + else { + if (g_activeThread->currentDelayMS > 0) { + g_activeThread->currentDelayMS -= deltaMS; + // the following block is needed to handle with long freezes on simulator + if (g_activeThread->currentDelayMS < 0) { + g_activeThread->currentDelayMS = 0; + } + c_sleep++; + } + else { + SVM_RunThread(g_activeThread); + c_run++; + } } g_activeThread = g_activeThread->next; } //ADDLOG_INFO(LOG_FEATURE_CMD, "SCR sleep %i, ran %i",c_sleep,c_run); } +void CMD_Script_ProcessWaitersForEvent(byte eventCode, int argument) { + scriptInstance_t *t; + + t = g_scriptThreads; + + while (t) { + if (t->waitingForEvent == eventCode) { + if (t->waitingForArgument == argument) { + // unlock! + t->waitingForArgument = 0; + t->waitingForEvent = 0; + } + } + t = t->next; + } +} void SVM_GoTo(scriptInstance_t *th, const char *fname, const char *label) { scriptFile_t *f; @@ -741,6 +771,37 @@ commandResult_t CMD_resetSVM(const void *context, const char *cmd, const char *a return CMD_RES_OK; } +commandResult_t CMD_waitFor(const void *context, const char *cmd, const char *args, int cmdFlags) { + const char *eventName; + int reqArg, eventCode; + + if (g_activeThread == 0) { + ADDLOG_INFO(LOG_FEATURE_CMD, "CMD_waitFor: this can be only used from a script"); + return CMD_RES_ERROR; + } + + Tokenizer_TokenizeString(args, 0); + // following check must be done after 'Tokenizer_TokenizeString', + // so we know arguments count in Tokenizer. 'cmd' argument is + // only for warning display + if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 2)) { + return CMD_RES_NOT_ENOUGH_ARGUMENTS; + } + eventName = Tokenizer_GetArg(0); + + eventCode = EVENT_ParseEventName(eventName); + if (eventCode == CMD_EVENT_NONE) { + ADDLOG_ERROR(LOG_FEATURE_EVENT, "%s is not a valid event", eventName); + return CMD_RES_BAD_ARGUMENT; + } + + reqArg = Tokenizer_GetArgInteger(1); + + g_activeThread->waitingForEvent = eventCode; + g_activeThread->waitingForArgument = reqArg; + + return CMD_RES_OK; +} void CMD_InitScripting(){ //cmddetail:{"name":"startScript","args":"[FileName][Label][UniqueID]", //cmddetail:"descr":"Starts a script thread from given file, at given label - can be * for whole file, with given unique ID", @@ -787,6 +848,11 @@ void CMD_InitScripting(){ //cmddetail:"fn":"CMD_resetSVM","file":"cmnds/cmd_script.c","requires":"", //cmddetail:"examples":""} CMD_RegisterCommand("resetSVM", CMD_resetSVM, NULL); + //cmddetail:{"name":"waitFor","args":"[EventName] [Argument]", + //cmddetail:"descr":"Wait forever for event.", + //cmddetail:"fn":"CMD_waitFor","file":"cmnds/cmd_script.c","requires":"", + //cmddetail:"examples":""} + CMD_RegisterCommand("waitFor", CMD_waitFor, NULL); } diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index 2f27c36ef..98e41a1d5 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -2184,7 +2184,7 @@ const char* g_obk_flagNames[] = { "[LED] Use old linear brightness mode, ignore gamma ramp", "[MQTT] Apply channel type multiplier on (if any) on channel value before publishing it", "[MQTT] In HA discovery, add relays as lights", - "[HASS] Deactivate avty_t flag for sensor when publishing to HASS (permit to keep value)", + "[HASS] Deactivate avty_t flag for sensor when publishing to HASS (permit to keep value). You must restart HASS discovery for change to take effect.", "[DRV] Deactivate Autostart of all drivers", "[WiFi] Quick connect to WiFi on reboot (TODO: check if it works for you and report on github)", "[Power] Set power and current to zero if all relays are open", diff --git a/src/selftest/selftest_local.h b/src/selftest/selftest_local.h index d9568cf80..a64f9466c 100644 --- a/src/selftest/selftest_local.h +++ b/src/selftest/selftest_local.h @@ -98,6 +98,7 @@ void Test_CFG_Via_HTTP(); void Test_Demo_ButtonScrollingChannelValues(); void Test_Demo_ButtonToggleGroup(); void Test_Role_ToggleAll_2(); +void Test_WaitFor(); void Test_GetJSONValue_Setup(const char *text); void Test_FakeHTTPClientPacket_GET(const char *tg); diff --git a/src/selftest/selftest_waitFor.c b/src/selftest/selftest_waitFor.c new file mode 100644 index 000000000..36b4fcce3 --- /dev/null +++ b/src/selftest/selftest_waitFor.c @@ -0,0 +1,59 @@ +#ifdef WINDOWS + +#include "selftest_local.h". + +/* +Example autoexec.bat usage: + +// do anything on startup +startDriver NTP +startDriver SSDP + +// now wait for MQTT +waitFor MQTTState 1 +// extra delay, to be sure +delay_s 1 +publish myVariable 2022 + + +*/ +void Test_WaitFor() { + int i; + char buffer[64]; + + // reset whole device + SIM_ClearOBK(0); + + // send file content as POST to REST interface + Test_FakeHTTPClientPacket_POST("api/lfs/testScript.txt", + "setChannel 1 50\n" + "setChannel 2 75\n" + "waitFor MQTTState 1\n" + "setChannel 1 123\n" + "setChannel 2 234\n"); + + CMD_ExecuteCommand("setChannel 1 0", 0); + CMD_ExecuteCommand("setChannel 2 0", 0); + + SELFTEST_ASSERT_CHANNEL(1, 0); + SELFTEST_ASSERT_CHANNEL(2, 0); + + CMD_ExecuteCommand("startScript testScript.txt", 0); + + for (i = 0; i < 10; i++) { + SVM_RunThreads(5); + } + SELFTEST_ASSERT_CHANNEL(1, 50); + SELFTEST_ASSERT_CHANNEL(2, 75); + + CMD_Script_ProcessWaitersForEvent(CMD_EVENT_MQTT_STATE,1); + + for (i = 0; i < 10; i++) { + SVM_RunThreads(5); + } + SELFTEST_ASSERT_CHANNEL(1, 123); + SELFTEST_ASSERT_CHANNEL(2, 234); + +} + +#endif diff --git a/src/win_main.c b/src/win_main.c index 7e45a7e6d..f48cc8a64 100644 --- a/src/win_main.c +++ b/src/win_main.c @@ -127,6 +127,7 @@ void SIM_ClearOBK(const char *flashPath) { Main_Init(); } void Win_DoUnitTests() { + Test_WaitFor(); Test_TwoPWMsOneChannel(); Test_ClockEvents(); Test_HassDiscovery();