diff --git a/data_svelte/scenario.txt b/data_svelte/scenario.txt new file mode 100644 index 00000000..e69de29b diff --git a/include/Const.h b/include/Const.h index b8be0285..dad350c6 100644 --- a/include/Const.h +++ b/include/Const.h @@ -3,9 +3,6 @@ //Версия прошивки #define FIRMWARE_VERSION 413 -//Поблочная загрузка сценариев =1 грузим блоками, =0 грузим и держим в памяти весь сценарий -#define SCENARIO_BLOCK_LOAD 1 - #ifdef esp8266_4mb #define FIRMWARE_NAME "esp8266_4mb" #endif diff --git a/include/classes/IoTScenario.h b/include/classes/IoTScenario.h index 22aab25a..b717c0e7 100644 --- a/include/classes/IoTScenario.h +++ b/include/classes/IoTScenario.h @@ -18,7 +18,7 @@ class IoTScenario { String IdentifierStr; // Заполняется, если tok_identifier float NumVal; // Заполняется, если tok_number - char LastChar = ' '; + int LastChar; /// gettok - Возвращает следующий токен из стандартного потока ввода. int gettok(); @@ -32,6 +32,7 @@ class IoTScenario { /// лексического анализатора и обновляет CurTok. int CurTok; int getNextToken(); + String IDNames; // накопитель встречающихся идентификаторов в условии /// BinopPrecedence - Содержит приоритеты для бинарных операторов std::map BinopPrecedence; @@ -77,17 +78,12 @@ class IoTScenario { /// ExprAST *ParseExpression(String *IDNames); - std::vector ScenarioElements; // корневые элементы дерава - - String strFromFile; - char getLastChar(); - int strIterator = 0; - - void clearScenarioElements(); + int getLastChar(); + fs::File file; public: - void loadScenario(String fileName, String eventIdName); - void execScenario(String eventIdName); + void loadScenario(String fileName); + void exec(String eventIdName); IoTScenario(); ~IoTScenario(); diff --git a/src/EventsAndOrders.cpp b/src/EventsAndOrders.cpp index b63a461d..bffbbc4c 100644 --- a/src/EventsAndOrders.cpp +++ b/src/EventsAndOrders.cpp @@ -52,9 +52,7 @@ void handleEvent() { //здесь нужно пропускать данное событие через условия сценариев //и если оно есть в условии сценария и совподает - String tmpStr = selectToMarker(event, " "); - if (SCENARIO_BLOCK_LOAD) iotScen.loadScenario("/scenario.json", tmpStr); - else iotScen.execScenario(tmpStr); + iotScen.exec(selectToMarker(event, " ")); eventBuf = deleteBeforeDelimiter(eventBuf, ","); } diff --git a/src/Main.cpp b/src/Main.cpp index b8e82403..102995e1 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -62,10 +62,10 @@ void setup() { //запуск работы udp asyncUdpInit(); - - //загрузка сценария - if (!SCENARIO_BLOCK_LOAD) iotScen.loadScenario("/scenario.json", ""); + //подготавливаем сценарии + iotScen.loadScenario("/scenario.txt"); + // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке IoTItems.push_back((IoTItem *)new externalVariable("{\"id\":\"onStart\",\"val\":1,\"int\":60}")); generateEvent("onStart", ""); diff --git a/src/WsServer.cpp b/src/WsServer.cpp index cc9a6c2b..40ba0d07 100644 --- a/src/WsServer.cpp +++ b/src/WsServer.cpp @@ -75,9 +75,24 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) } if (headerStr == "/oiranecs|") { writeFileUint8tByFrames("scenario.json", payload, length, headerLenth, 256); + + String strFromFile; + File myfile = seekFile("/scenario.json"); + if (myfile.available()) { + strFromFile = myfile.readString(); + + strFromFile.replace("{\"scen\":\"", ""); + strFromFile.replace("\\n", "\n"); + strFromFile.replace("\\\"", "\""); + strFromFile.remove(strFromFile.length() - 2, 2); + } + myfile.close(); + + writeFile("/scenario.txt", strFromFile); + clearConfigure(); configure("/config.json"); - if (!SCENARIO_BLOCK_LOAD) iotScen.loadScenario("/scenario.json", ""); + iotScen.loadScenario("/scenario.txt"); // создаем событие завершения конфигурирования для возможности выполнения блока кода при загрузке IoTItems.push_back((IoTItem*)new externalVariable("{\"id\":\"onStart\",\"val\":1,\"int\":60}")); generateEvent("onStart", ""); diff --git a/src/classes/IoTScenario.cpp b/src/classes/IoTScenario.cpp index 04527a3f..4ae13341 100644 --- a/src/classes/IoTScenario.cpp +++ b/src/classes/IoTScenario.cpp @@ -1,5 +1,3 @@ -#include - #pragma once #include "Global.h" #include "classes/IoTItem.h" @@ -7,6 +5,7 @@ #include "utils/FileUtils.h" #include "NTP.h" + bool isIotScenException; // признак исключения и попытки прекратить выполнение сценария заранее // Лексический анализатор возвращает токены [0-255], если это неизвестны, @@ -586,11 +585,9 @@ class BracketsExprAST : public ExprAST { // Lexer (Лексический анализатор) //===----------------------------------------------------------------------===// -char IoTScenario::getLastChar() { - if (strIterator == strFromFile.length()) return 0; - char tmpCh = strFromFile.charAt(strIterator); - strIterator++; - return tmpCh; +int IoTScenario::getLastChar() { + if (file) return file.read(); + else return EOF; } /// gettok - Возвращает следующий токен из стандартного потока ввода. @@ -600,9 +597,9 @@ int IoTScenario::gettok() { LastChar = getLastChar(); if (isalpha(LastChar) || LastChar == '_') { // идентификатор: [a-zA-Z][a-zA-Z0-9]* - IdentifierStr = LastChar; + IdentifierStr = (char)LastChar; while (isalnum((LastChar = getLastChar())) || LastChar == '_') { - IdentifierStr += LastChar; + IdentifierStr += (char)LastChar; } // Serial.printf("%s ", IdentifierStr.c_str()); @@ -616,7 +613,7 @@ int IoTScenario::gettok() { if (isdigit(LastChar)) { // Число: [0-9.]+ String NumStr; do { - NumStr += LastChar; + NumStr += (char)LastChar; LastChar = getLastChar(); } while (isdigit(LastChar) || LastChar == '.'); @@ -627,7 +624,7 @@ int IoTScenario::gettok() { if (LastChar == '#') { // Комментарий до конца строки do LastChar = getLastChar(); - while (LastChar != 0 && LastChar != '\n' && LastChar != '\r'); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); if (LastChar != EOF) return gettok(); @@ -636,8 +633,8 @@ int IoTScenario::gettok() { if (LastChar == '"') { // "строка" IdentifierStr = ""; LastChar = getLastChar(); - while (LastChar != '"' && LastChar != 0) { - IdentifierStr += LastChar; + while (LastChar != '"' && LastChar != EOF) { + IdentifierStr += (char)LastChar; LastChar = getLastChar(); } LastChar = getLastChar(); @@ -646,8 +643,8 @@ int IoTScenario::gettok() { } // Проверка конца файла. - // if (LastChar == EOF) - // return tok_eof; + if (LastChar == EOF) + return tok_eof; if (LastChar == '=') { LastChar = getLastChar(); @@ -684,7 +681,7 @@ int IoTScenario::gettok() { } else return '>'; } - + // В противном случае просто возвращаем символ как значение ASCII int ThisChar = LastChar; LastChar = getLastChar(); @@ -919,78 +916,37 @@ ExprAST *IoTScenario::ParseExpression(String *IDNames) { return ParseBinOpRHS(0, LHS, IDNames); } -void IoTScenario::clearScenarioElements() { // удаляем все корневые элементы дерева AST - for (unsigned int i = 0; i < ScenarioElements.size(); i++) { - if (ScenarioElements[i]) delete ScenarioElements[i]; - } - ScenarioElements.clear(); + +void IoTScenario::loadScenario(String fileName) { // подготавливаем контекст для чтения и интерпретации файла + if (file) file.close(); + file = FileFS.open(fileName, "r"); } -void IoTScenario::loadScenario(String fileName, String eventIdName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST - if (!SCENARIO_BLOCK_LOAD) clearScenarioElements(); // удаляем все корневые элементы перед загрузкой новых. - LastChar = ' '; - - File myfile = seekFile(fileName); - if (myfile.available()) { - //strFromFile = new String(""); - - strFromFile = myfile.readString(); - //Serial.println(strFromF); - //jsonRead(strFromF, "scen", *strFromFile, true); - myfile.close(); - - strFromFile.replace("{\"scen\":\"", ""); - strFromFile.replace("\\n\"}", ""); - strFromFile.replace("\\n", "\n"); - strFromFile.replace("\\\"", "\""); - //Serial.println(strFromFile); - - if (strFromFile.length()) { - - while (strIterator < strFromFile.length()) { - // Serial.printf("-%c", LastChar); - getNextToken(); - switch (CurTok) { - // case tok_eof: break; - case tok_if: { - String IDNames = ""; // накопитель встречающихся идентификаторов в условии - ExprAST *tmpAST = ParseIfExpr(&IDNames); - if (!tmpAST) break; - - if (SCENARIO_BLOCK_LOAD) { - if (tmpAST->hasEventIdName(eventIdName)) { - tmpAST->exec(); - Serial.println("Exec from loadIF"); - } - delete tmpAST; - } else ScenarioElements.push_back(tmpAST); - break; - } - - default: - - break; - } - } - } - - //delete strFromFile; - strIterator = 0; - } else { +void IoTScenario::exec(String eventIdName) { // посимвольно считываем и сразу интерпретируем сценарий в дерево AST + if (!file) { Error("Open file scenario error"); + return; + } + LastChar = 0; + CurTok = 0; + file.seek(0); + + while ((getNextToken()) != EOF) { + switch (CurTok) { + case tok_if: { + IDNames = ""; // сбрасываем накопитель встречающихся идентификаторов в условии + ExprAST *tmpAST = ParseIfExpr(&IDNames); + if (!tmpAST) break; + + if (tmpAST->hasEventIdName(eventIdName)) { + tmpAST->exec(); + } + delete tmpAST; + break;} + } } } -void IoTScenario::execScenario(String eventIdName) { // запускаем поочереди все корневые элементы выражений в сценарии, ожидаемо - это IFы - // eventIdName - ID элемента для которого выполняем сценарий, т.е. игнорируем любые проверки, если нет такого ID в условиях - isIotScenException = false; - //Serial.printf("Count root elements in scenario: %d\n", ScenarioElements.size()); - for (unsigned int i = 0; i < ScenarioElements.size(); i++) { - if (ScenarioElements[i] && ScenarioElements[i]->hasEventIdName(eventIdName)) ScenarioElements[i]->exec(); - // else Serial.printf("Call from ExecScenario: Skip ifexec because %s not found\n", eventIdName.c_str()); - if (isIotScenException) return; - } -} IoTScenario::IoTScenario() { // Задаём стандартные бинарные операторы. @@ -1010,4 +966,6 @@ IoTScenario::IoTScenario() { BinopPrecedence['*'] = 28; // highest. } -IoTScenario::~IoTScenario() {} +IoTScenario::~IoTScenario() { + if (file) file.close(); +}