diff --git a/FeatureRequest.md b/FeatureRequest.md index 5521641e..c28745b5 100644 --- a/FeatureRequest.md +++ b/FeatureRequest.md @@ -11,6 +11,22 @@ ____ +#### #8 MQTT configurable readout intervall + +Make the readout intervall configurable via MQTT. + +* Change the mqtt part to receive and process input and not only sending + +#### #7 Extended Error Handling + +Check different types of error (e.g. tflite not availabe) and generate an error on the html page. + +To do: + +* Make a list of "important" errors +* Implement a checking algo +* Extend the firmware and html page for the error handling + #### #6 Check for double ROI names Check during configuration, that ROI names are unique. diff --git a/README.md b/README.md index 5f22a630..99d11ea1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ respectively ESP32-Cam housing only: https://www.thingiverse.com/thing:4571627 + + @@ -45,16 +47,27 @@ In other cases you can contact the developer via email: **ATTENTION: the configuration and prevalue files are modified automatically and will not be backward compatible!** + + ##### 7.1.2 MQTT-Update - (2021-06-17) -* NEW: 7.1.2: bug fix setting hostname, Flash-LED not off during reboot -* NEW: 7.1.1: bug fix wlan password with "=" (again) +* NEW: 7.1.2: bug fix setting hostname, Flash-LED not off during rebootNEW: 7.1.1: bug fix wlan password with "=" (again) * MQTT error message: changes "no error", send retain flag * Update wlan handling to esp-idf 4.1 * Upgrade digital CNN to v8.7.0 (added new images) * Bug fix: MQTT, WLAN, LED-Controll, GPIO usage, fixed IP, calculation flow rate + ##### 7.0.1 MQTT-Update - (2021-05-13) diff --git a/code/.helper/copy.bat b/code/.helper/copy.bat index fdd8c7dd..9f8312f6 100644 --- a/code/.helper/copy.bat +++ b/code/.helper/copy.bat @@ -1,3 +1,3 @@ -copy "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\code\.pio\build\esp32cam\firmware.bin" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\firmware.bin" -copy "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\code\.pio\build\esp32cam\bootloader.bin" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\bootloader.bin" -copy "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\code\.pio\build\esp32cam\partitions.bin" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\partitions.bin" \ No newline at end of file +copy "..\..\code\.pio\build\esp32cam\firmware.bin" "..\..\firmware\firmware.bin" +copy "..\..\code\.pio\build\esp32cam\bootloader.bin" "..\..\firmware\bootloader.bin" +copy "..\..\code\.pio\build\esp32cam\partitions.bin" "..\..\firmware\partitions.bin" \ No newline at end of file diff --git a/code/.helper/makezip.bat b/code/.helper/makezip.bat index 05664841..0fe9c3ef 100644 --- a/code/.helper/makezip.bat +++ b/code/.helper/makezip.bat @@ -1 +1 @@ -powershell Compress-Archive "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\sd-card\html\*.*" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\html.zip" \ No newline at end of file +powershell Compress-Archive "..\..\sd-card\html\*.*" "..\..\firmware\html.zip" \ No newline at end of file diff --git a/code/components/connect_wlan.zip b/code/components/connect_wlan.zip deleted file mode 100644 index 31ab9b29..00000000 Binary files a/code/components/connect_wlan.zip and /dev/null differ diff --git a/code/components/esp32-camera-master/examples/take_picture.c b/code/components/esp32-camera-master/examples/take_picture.c index 96b224fd..8a22e8c3 100644 --- a/code/components/esp32-camera-master/examples/take_picture.c +++ b/code/components/esp32-camera-master/examples/take_picture.c @@ -29,7 +29,7 @@ // ================================ CODE ====================================== -#include +#include #include #include #include diff --git a/code/components/jomjol_configfile/CMakeLists.txt b/code/components/jomjol_configfile/CMakeLists.txt new file mode 100644 index 00000000..dc5e71d5 --- /dev/null +++ b/code/components/jomjol_configfile/CMakeLists.txt @@ -0,0 +1,7 @@ +FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*) + +idf_component_register(SRCS ${app_sources} + INCLUDE_DIRS "." + REQUIRES jomjol_logfile) + + diff --git a/code/components/jomjol_configfile/configFile.cpp b/code/components/jomjol_configfile/configFile.cpp new file mode 100644 index 00000000..f8c9aa02 --- /dev/null +++ b/code/components/jomjol_configfile/configFile.cpp @@ -0,0 +1,96 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "Helper.h" +#include "configFile.h" + +//static const char *TAGCONFIGFILE = "configFile"; + +ConfigFile::ConfigFile(std::string filePath) +{ + std::string config = FormatFileName(filePath); + pFile = OpenFileAndWait(config.c_str(), "r"); +} + +ConfigFile::~ConfigFile() +{ + fclose(pFile); +} + +bool ConfigFile::isNewParagraph(std::string input) +{ + if ((input[0] == '[') || ((input[0] == ';') && (input[1] == '['))) + { + return true; + } + return false; +} + +bool ConfigFile::GetNextParagraph(std::string& aktparamgraph, bool &disabled, bool &eof) +{ + while (getNextLine(&aktparamgraph, disabled, eof) && !isNewParagraph(aktparamgraph)); + + if (isNewParagraph(aktparamgraph)) + return true; + return false; +} + +bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof) +{ + eof = false; + char zw[1024]; + if (pFile == NULL) + { + *rt = ""; + return false; + } + fgets(zw, 1024, pFile); + printf("%s", zw); + if ((strlen(zw) == 0) && feof(pFile)) + { + *rt = ""; + eof = true; + return false; + } + *rt = zw; + *rt = trim(*rt); + while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '[')) // Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph + { + fgets(zw, 1024, pFile); + printf("%s", zw); + if (feof(pFile)) + { + *rt = ""; + eof = true; + return false; + } + *rt = zw; + *rt = trim(*rt); + } + + disabled = ((*rt)[0] == ';'); + return true; +} + +std::vector ConfigFile::ZerlegeZeile(std::string input, std::string delimiter) +{ + std::vector Output; +// std::string delimiter = " =,"; + + input = trim(input, delimiter); + size_t pos = findDelimiterPos(input, delimiter); + std::string token; + while (pos != std::string::npos) { + token = input.substr(0, pos); + token = trim(token, delimiter); + Output.push_back(token); + input.erase(0, pos + 1); + input = trim(input, delimiter); + pos = findDelimiterPos(input, delimiter); + } + Output.push_back(input); + + return Output; + +} diff --git a/code/components/jomjol_configfile/configFile.h b/code/components/jomjol_configfile/configFile.h new file mode 100644 index 00000000..65b0143c --- /dev/null +++ b/code/components/jomjol_configfile/configFile.h @@ -0,0 +1,16 @@ +#include +#include + +class ConfigFile { +public: + ConfigFile(std::string filePath); + ~ConfigFile(); + + bool isNewParagraph(std::string input); + bool GetNextParagraph(std::string& aktparamgraph, bool &disabled, bool &eof); + bool getNextLine(std::string* rt, bool &disabled, bool &eof); + std::vector ZerlegeZeile(std::string input, std::string delimiter = " =, \t"); + +private: + FILE* pFile; +}; \ No newline at end of file diff --git a/code/components/jomjol_controlGPIO/CMakeLists.txt b/code/components/jomjol_controlGPIO/CMakeLists.txt index c5ad1e71..b287de81 100644 --- a/code/components/jomjol_controlGPIO/CMakeLists.txt +++ b/code/components/jomjol_controlGPIO/CMakeLists.txt @@ -3,7 +3,7 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*) list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) idf_component_register(SRCS ${app_sources} - INCLUDE_DIRS "." - REQUIRES esp_http_server jomjol_logfile) + INCLUDE_DIRS "." "../../include" + REQUIRES esp_http_server jomjol_logfile jomjol_configfile jomjol_mqtt jomjol_flowcontroll) diff --git a/code/components/jomjol_controlGPIO/server_GPIO.cpp b/code/components/jomjol_controlGPIO/server_GPIO.cpp index fb06e694..c54d66ec 100644 --- a/code/components/jomjol_controlGPIO/server_GPIO.cpp +++ b/code/components/jomjol_controlGPIO/server_GPIO.cpp @@ -1,4 +1,5 @@ #include +#include #include "string.h" #include @@ -6,22 +7,384 @@ #include "freertos/task.h" #include "esp_system.h" #include "esp_event.h" + +//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include "esp_log.h" -#include "driver/gpio.h" //#include "errno.h" #include +#include +//#include + +#include "defines.h" #include "server_GPIO.h" #include "ClassLogFile.h" - +#include "configFile.h" #include "Helper.h" +#include "interface_mqtt.h" -// #define DEBUG_DETAIL_ON +static const char *TAG_SERVERGPIO = "server_GPIO"; +QueueHandle_t gpio_queue_handle = NULL; -esp_err_t handler_switch_GPIO(httpd_req_t *req) +#define DEBUG_DETAIL_ON + +GpioPin::GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_int_type_t interruptType, uint8_t dutyResolution, std::string mqttTopic, bool httpEnable) { + _gpio = gpio; + _name = name; + _mode = mode; + _interruptType = interruptType; + _mqttTopic = mqttTopic; +} + +GpioPin::~GpioPin() +{ + ESP_LOGD(TAG_SERVERGPIO,"reset GPIO pin %d", _gpio); + if (_interruptType != GPIO_INTR_DISABLE) { + //hook isr handler for specific gpio pin + gpio_isr_handler_remove(_gpio); + } + gpio_reset_pin(_gpio); +} + +static void IRAM_ATTR gpio_isr_handler(void* arg) +{ + GpioResult gpioResult; + gpioResult.gpio = *(gpio_num_t*) arg; + gpioResult.value = gpio_get_level(gpioResult.gpio); + BaseType_t ContextSwitchRequest = pdFALSE; + + xQueueSendToBackFromISR(gpio_queue_handle,(void*)&gpioResult,&ContextSwitchRequest); + + if(ContextSwitchRequest){ + taskYIELD(); + } +} + +static void gpioHandlerTask(void *arg) { + ESP_LOGD(TAG_SERVERGPIO,"start interrupt task"); + while(1){ + if(uxQueueMessagesWaiting(gpio_queue_handle)){ + while(uxQueueMessagesWaiting(gpio_queue_handle)){ + GpioResult gpioResult; + xQueueReceive(gpio_queue_handle,(void*)&gpioResult,10); + ESP_LOGD(TAG_SERVERGPIO,"gpio: %d state: %d", gpioResult.gpio, gpioResult.value); + ((GpioHandler*)arg)->gpioInterrupt(&gpioResult); + } + } + + ((GpioHandler*)arg)->taskHandler(); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +void GpioPin::gpioInterrupt(int value) { + if (_mqttTopic != "") { + ESP_LOGD(TAG_SERVERGPIO, "gpioInterrupt %s %d", _mqttTopic.c_str(), value); + + MQTTPublish(_mqttTopic, value ? "true" : "false"); + currentState = value; + } +} + +void GpioPin::init() +{ + gpio_config_t io_conf; + //set interrupt + io_conf.intr_type = _interruptType; + //set as output mode + io_conf.mode = (_mode == GPIO_PIN_MODE_OUTPUT) || (_mode == GPIO_PIN_MODE_BUILT_IN_FLASH_LED) ? gpio_mode_t::GPIO_MODE_OUTPUT : gpio_mode_t::GPIO_MODE_INPUT; + //bit mask of the pins that you want to set,e.g.GPIO18/19 + io_conf.pin_bit_mask = (1ULL << _gpio); + //set pull-down mode + io_conf.pull_down_en = _mode == GPIO_PIN_MODE_INPUT_PULLDOWN ? gpio_pulldown_t::GPIO_PULLDOWN_ENABLE : gpio_pulldown_t::GPIO_PULLDOWN_DISABLE; + //set pull-up mode + io_conf.pull_up_en = _mode == GPIO_PIN_MODE_INPUT_PULLDOWN ? gpio_pullup_t::GPIO_PULLUP_ENABLE : gpio_pullup_t::GPIO_PULLUP_DISABLE; + //configure GPIO with the given settings + gpio_config(&io_conf); + + if (_interruptType != GPIO_INTR_DISABLE) { + //hook isr handler for specific gpio pin + ESP_LOGD(TAG_SERVERGPIO, "GpioPin::init add isr handler for GPIO %d\r\n", _gpio); + gpio_isr_handler_add(_gpio, gpio_isr_handler, (void*)&_gpio); + } + + if ((_mqttTopic != "") && ((_mode == GPIO_PIN_MODE_OUTPUT) || (_mode == GPIO_PIN_MODE_OUTPUT_PWM) || (_mode == GPIO_PIN_MODE_BUILT_IN_FLASH_LED))) { + std::function f = std::bind(&GpioPin::handleMQTT, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + MQTTregisterSubscribeFunction(_mqttTopic, f); + } +} + +bool GpioPin::getValue(std::string* errorText) +{ + if ((_mode != GPIO_PIN_MODE_INPUT) && (_mode != GPIO_PIN_MODE_INPUT_PULLUP) && (_mode != GPIO_PIN_MODE_INPUT_PULLDOWN)) { + (*errorText) = "GPIO is not in input mode"; + } + + return gpio_get_level(_gpio) == 1; +} + +void GpioPin::setValue(bool value, gpio_set_source setSource, std::string* errorText) +{ + ESP_LOGD(TAG_SERVERGPIO, "GpioPin::setValue %d\r\n", value); + + if ((_mode != GPIO_PIN_MODE_OUTPUT) && (_mode != GPIO_PIN_MODE_OUTPUT_PWM) && (_mode != GPIO_PIN_MODE_BUILT_IN_FLASH_LED)) { + (*errorText) = "GPIO is not in output mode"; + } else { + gpio_set_level(_gpio, value); + + if ((_mqttTopic != "") && (setSource != GPIO_SET_SOURCE_MQTT)) { + MQTTPublish(_mqttTopic, value ? "true" : "false"); + } + } +} + +void GpioPin::publishState() { + int newState = gpio_get_level(_gpio); + if (newState != currentState) { + ESP_LOGD(TAG_SERVERGPIO,"publish state of GPIO %d new state %d", _gpio, newState); + MQTTPublish(_mqttTopic, newState ? "true" : "false"); + currentState = newState; + } +} + +bool GpioPin::handleMQTT(std::string, char* data, int data_len) { + ESP_LOGD(TAG_SERVERGPIO, "GpioPin::handleMQTT data %.*s\r\n", data_len, data); + + std::string dataStr(data, data_len); + dataStr = toLower(dataStr); + std::string errorText = ""; + if ((dataStr == "true") || (dataStr == "1")) { + setValue(true, GPIO_SET_SOURCE_MQTT, &errorText); + } else if ((dataStr == "false") || (dataStr == "0")) { + setValue(false, GPIO_SET_SOURCE_MQTT, &errorText); + } else { + errorText = "wrong value "; + errorText.append(data, data_len); + } + + if (errorText != "") { + ESP_LOGE(TAG_SERVERGPIO, "%s", errorText.c_str()); + } + + return (errorText == ""); +} + + +esp_err_t callHandleHttpRequest(httpd_req_t *req) +{ + ESP_LOGD(TAG_SERVERGPIO,"callHandleHttpRequest"); + + GpioHandler *gpioHandler = (GpioHandler*)req->user_ctx; + return gpioHandler->handleHttpRequest(req); +} + +void taskGpioHandler(void *pvParameter) +{ + ESP_LOGD(TAG_SERVERGPIO,"taskGpioHandler"); + ((GpioHandler*)pvParameter)->init(); +} + +GpioHandler::GpioHandler(std::string configFile, httpd_handle_t httpServer) +{ + ESP_LOGI(TAG_SERVERGPIO,"start GpioHandler"); + _configFile = configFile; + _httpServer = httpServer; + + ESP_LOGI(TAG_SERVERGPIO, "register GPIO Uri"); + registerGpioUri(); +} + +GpioHandler::~GpioHandler() { + if (gpioMap != NULL) { + clear(); + delete gpioMap; + } +} + +void GpioHandler::init() +{ + // TickType_t xDelay = 60000 / portTICK_PERIOD_MS; + // printf("wait before start %ldms\r\n", (long) xDelay); + // vTaskDelay( xDelay ); + + if (gpioMap == NULL) { + gpioMap = new std::map(); + } else { + clear(); + } + + ESP_LOGI(TAG_SERVERGPIO, "read GPIO config and init GPIO"); + if (!readConfig()) { + clear(); + delete gpioMap; + gpioMap = NULL; + ESP_LOGI(TAG_SERVERGPIO, "GPIO init comleted, handler is disabled"); + return; + } + + for(std::map::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) { + it->second->init(); + } + + std::function f = std::bind(&GpioHandler::handleMQTTconnect, this); + MQTTregisterConnectFunction("gpio-handler", f); + + if (xHandleTaskGpio == NULL) { + gpio_queue_handle = xQueueCreate(10,sizeof(GpioResult)); + BaseType_t xReturned = xTaskCreate(&gpioHandlerTask, "gpio_int", configMINIMAL_STACK_SIZE * 8, (void *)this, tskIDLE_PRIORITY + 2, &xHandleTaskGpio); + if(xReturned == pdPASS ) { + ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler started"); + } else { + ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler not started %d ", (int)xHandleTaskGpio); + } + } + + ESP_LOGI(TAG_SERVERGPIO, "GPIO init comleted, is enabled"); +} + +void GpioHandler::taskHandler() { + if (gpioMap != NULL) { + for(std::map::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) { + if ((it->second->getInterruptType() == GPIO_INTR_DISABLE)) + it->second->publishState(); + } + } +} + + +void GpioHandler::handleMQTTconnect() +{ + if (gpioMap != NULL) { + for(std::map::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) { + if ((it->second->getMode() == GPIO_PIN_MODE_INPUT) || (it->second->getMode() == GPIO_PIN_MODE_INPUT_PULLDOWN) || (it->second->getMode() == GPIO_PIN_MODE_INPUT_PULLUP)) + it->second->publishState(); + } + } +} + +void GpioHandler::deinit() { + MQTTunregisterConnectFunction("gpio-handler"); + clear(); + if (xHandleTaskGpio != NULL) { + vTaskDelete(xHandleTaskGpio); + xHandleTaskGpio = NULL; + } +} + +void GpioHandler::gpioInterrupt(GpioResult* gpioResult) { + if ((gpioMap != NULL) && (gpioMap->find(gpioResult->gpio) != gpioMap->end())) { + (*gpioMap)[gpioResult->gpio]->gpioInterrupt(gpioResult->value); + } +} + +bool GpioHandler::readConfig() +{ + if (!gpioMap->empty()) + clear(); + + ConfigFile configFile = ConfigFile(_configFile); + + std::vector zerlegt; + std::string line = ""; + bool disabledLine = false; + bool eof = false; + + while ((!configFile.GetNextParagraph(line, disabledLine, eof) || (line.compare("[GPIO]") != 0)) && !disabledLine && !eof) {} + if (eof) + return false; + + _isEnabled = !disabledLine; + + if (!_isEnabled) + return false; + + std::string mainTopicMQTT = ""; + bool registerISR = false; + while (configFile.getNextLine(&line, disabledLine, eof) && !configFile.isNewParagraph(line)) + { + zerlegt = configFile.ZerlegeZeile(line); + // const std::regex pieces_regex("IO([0-9]{1,2})"); + // std::smatch pieces_match; + // if (std::regex_match(zerlegt[0], pieces_match, pieces_regex) && (pieces_match.size() == 2)) + // { + // std::string gpioStr = pieces_match[1]; + ESP_LOGD(TAG_SERVERGPIO, "conf param %s\r\n", toUpper(zerlegt[0]).c_str()); + if (toUpper(zerlegt[0]) == "MAINTOPICMQTT") { + ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n"); + mainTopicMQTT = zerlegt[1]; + } else if ((zerlegt[0].rfind("IO", 0) == 0) && (zerlegt.size() >= 6)) + { + ESP_LOGI(TAG_SERVERGPIO,"Enable GP%s in %s mode", zerlegt[0].c_str(), zerlegt[1].c_str()); + std::string gpioStr = zerlegt[0].substr(2, 2); + gpio_num_t gpioNr = (gpio_num_t)atoi(gpioStr.c_str()); + gpio_pin_mode_t pinMode = resolvePinMode(toLower(zerlegt[1])); + gpio_int_type_t intType = resolveIntType(toLower(zerlegt[2])); + uint16_t dutyResolution = (uint8_t)atoi(zerlegt[3].c_str()); + bool mqttEnabled = toLower(zerlegt[4]) == "true"; + bool httpEnabled = toLower(zerlegt[5]) == "true"; + char gpioName[100]; + if (zerlegt.size() >= 7) { + strcpy(gpioName, trim(zerlegt[6]).c_str()); + } else { + sprintf(gpioName, "GPIO%d", gpioNr); + } + std::string mqttTopic = mqttEnabled ? (mainTopicMQTT + "/" + gpioName) : ""; + GpioPin* gpioPin = new GpioPin(gpioNr, gpioName, pinMode, intType,dutyResolution, mqttTopic, httpEnabled); + (*gpioMap)[gpioNr] = gpioPin; + + if (intType != GPIO_INTR_DISABLE) { + registerISR = true; + } + } + } + + if (registerISR) { + //install gpio isr service + gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM); + } + + return true; +} + +void GpioHandler::clear() +{ + ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear\r\n"); + + if (gpioMap != NULL) { + for(std::map::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) { + delete it->second; + } + gpioMap->clear(); + } + + // gpio_uninstall_isr_service(); can't uninstall, isr service is used by camera +} + +void GpioHandler::registerGpioUri() +{ + ESP_LOGI(TAG_SERVERGPIO, "server_GPIO - Registering URI handlers"); + + httpd_uri_t camuri = { }; + camuri.method = HTTP_GET; + camuri.uri = "/GPIO"; + camuri.handler = callHandleHttpRequest; + camuri.user_ctx = (void*)this; + httpd_register_uri_handler(_httpServer, &camuri); +} + +esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req) +{ + ESP_LOGD(TAG_SERVERGPIO, "handleHttpRequest"); + + if (gpioMap == NULL) { + std::string resp_str = "GPIO handler not initialized"; + httpd_resp_send(req, resp_str.c_str(), resp_str.length()); + return ESP_OK; + } + #ifdef DEBUG_DETAIL_ON LogFile.WriteHeapInfo("handler_switch_GPIO - Start"); #endif @@ -30,95 +393,183 @@ esp_err_t handler_switch_GPIO(httpd_req_t *req) char _query[200]; char _valueGPIO[30]; char _valueStatus[30]; - std::string gpio, status, zw; - int gpionum = 0; - gpio_num_t gpio_num; + std::string gpio, status; - if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) - { - printf("Query: "); printf(_query); printf("\n"); + if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) { + ESP_LOGD(TAG_SERVERGPIO, "Query: %s", _query); if (httpd_query_key_value(_query, "GPIO", _valueGPIO, 30) == ESP_OK) { - printf("GPIO is found"); printf(_valueGPIO); printf("\n"); + ESP_LOGD(TAG_SERVERGPIO, "GPIO is found %s", _valueGPIO); gpio = std::string(_valueGPIO); + } else { + std::string resp_str = "GPIO No is not defined"; + httpd_resp_send(req, resp_str.c_str(), resp_str.length()); + return ESP_OK; } if (httpd_query_key_value(_query, "Status", _valueStatus, 30) == ESP_OK) { - printf("Status is found"); printf(_valueStatus); printf("\n"); + ESP_LOGD(TAG_SERVERGPIO, "Status is found %s", _valueStatus); status = std::string(_valueStatus); } - }; + } else { + const char* resp_str = "Error in call. Use /GPIO?GPIO=12&Status=high"; + httpd_resp_send(req, resp_str, strlen(resp_str)); + return ESP_OK; + } status = toUpper(status); - if (!(status == "HIGH") && !(status == "LOW")) + if ((status != "HIGH") && (status != "LOW") && (status != "TRUE") && (status != "FALSE") && (status != "0") && (status != "1") && (status != "")) { - zw = "Status not valid: " + status;; + std::string zw = "Status not valid: " + status; httpd_resp_sendstr_chunk(req, zw.c_str()); httpd_resp_sendstr_chunk(req, NULL); return ESP_OK; } - gpionum = stoi(gpio); - - // frei: 16; 12-15; 2; 4 // nur 12 und 13 funktionieren 2: reboot, 4: BlitzLED, 14/15: DMA für SDKarte ??? + int gpionum = stoi(gpio); - switch (gpionum) { - case 12: - gpio_num = GPIO_NUM_12; - break; - case 13: - gpio_num = GPIO_NUM_13; - break; - default: - zw = "GPIO" + std::to_string(gpionum) + " not support - only 12 & 13 free"; + // frei: 16; 12-15; 2; 4 // nur 12 und 13 funktionieren 2: reboot, 4: BlitzLED, 15: PSRAM, 14/15: DMA für SDKarte ??? + gpio_num_t gpio_num = resolvePinNr(gpionum); + if (gpio_num == GPIO_NUM_NC) + { + std::string zw = "GPIO" + std::to_string(gpionum) + " not support - only 12 & 13 free"; httpd_resp_sendstr_chunk(req, zw.c_str()); httpd_resp_sendstr_chunk(req, NULL); - return ESP_OK; + return ESP_OK; } - if (status == "HIGH") - gpio_set_level(gpio_num, 1); + if (gpioMap->count(gpio_num) == 0) { + char resp_str [30]; + sprintf(resp_str, "GPIO%d is not registred", gpio_num); + httpd_resp_send(req, resp_str, strlen(resp_str)); + return ESP_OK; + } + + if (status == "") + { + std::string resp_str = ""; + status = (*gpioMap)[gpio_num]->getValue(&resp_str) ? "HIGH" : "LOW"; + if (resp_str == "") { + resp_str = status; + } + httpd_resp_sendstr_chunk(req, resp_str.c_str()); + httpd_resp_sendstr_chunk(req, NULL); + } else - gpio_set_level(gpio_num, 0); - - - zw = "GPIO" + std::to_string(gpionum) + " switched to " + status; - httpd_resp_sendstr_chunk(req, zw.c_str()); - httpd_resp_sendstr_chunk(req, NULL); + { + std::string resp_str = ""; + (*gpioMap)[gpio_num]->setValue((status == "HIGH") || (status == "TRUE") || (status == "1"), GPIO_SET_SOURCE_HTTP, &resp_str); + if (resp_str == "") { + resp_str = "GPIO" + std::to_string(gpionum) + " switched to " + status; + } + httpd_resp_sendstr_chunk(req, resp_str.c_str()); + httpd_resp_sendstr_chunk(req, NULL); + } + return ESP_OK; }; -void initGPIO() +void GpioHandler::flashLightEnable(bool value) { - gpio_config_t io_conf; - //disable interrupt - io_conf.intr_type = GPIO_INTR_DISABLE; - //set as output mode - io_conf.mode = GPIO_MODE_OUTPUT; - //bit mask of the pins that you want to set,e.g.GPIO18/19 -// io_conf.pin_bit_mask = ((1ULL<::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) + { + if (it->second->getMode() == GPIO_PIN_MODE_BUILT_IN_FLASH_LED) //|| (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_PWM) || (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)) + { + std::string resp_str = ""; + it->second->setValue(value, GPIO_SET_SOURCE_INTERNAL, &resp_str); + + if (resp_str == "") { + ESP_LOGD(TAG_SERVERGPIO, "Flash light pin GPIO %d switched to %s\r\n", (int)it->first, (value ? "on" : "off")); + } else { + ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d. Error: %s\r\n", (int)it->first, resp_str.c_str()); + } + } + } + } } - -void register_server_GPIO_uri(httpd_handle_t server) +gpio_num_t GpioHandler::resolvePinNr(uint8_t pinNr) { - ESP_LOGI(TAGPARTGPIO, "server_GPIO - Registering URI handlers"); - - httpd_uri_t camuri = { }; - camuri.method = HTTP_GET; - camuri.uri = "/GPIO"; - camuri.handler = handler_switch_GPIO; - camuri.user_ctx = (void*) "switch GPIO"; - httpd_register_uri_handler(server, &camuri); - - initGPIO(); + switch(pinNr) { + case 0: + return GPIO_NUM_0; + case 1: + return GPIO_NUM_1; + case 3: + return GPIO_NUM_3; + case 4: + return GPIO_NUM_4; + case 12: + return GPIO_NUM_12; + case 13: + return GPIO_NUM_13; + default: + return GPIO_NUM_NC; + } +} + +gpio_pin_mode_t GpioHandler::resolvePinMode(std::string input) +{ + if( input == "disabled" ) return GPIO_PIN_MODE_DISABLED; + if( input == "input" ) return GPIO_PIN_MODE_INPUT; + if( input == "input-pullup" ) return GPIO_PIN_MODE_INPUT_PULLUP; + if( input == "input-pulldown" ) return GPIO_PIN_MODE_INPUT_PULLDOWN; + if( input == "output" ) return GPIO_PIN_MODE_OUTPUT; + if( input == "built-in-led" ) return GPIO_PIN_MODE_BUILT_IN_FLASH_LED; + if( input == "output-pwm" ) return GPIO_PIN_MODE_OUTPUT_PWM; + if( input == "external-flash-pwm" ) return GPIO_PIN_MODE_EXTERNAL_FLASH_PWM; + if( input == "external-flash-ws281x" ) return GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X; + + return GPIO_PIN_MODE_DISABLED; +} + +gpio_int_type_t GpioHandler::resolveIntType(std::string input) +{ + if( input == "disabled" ) return GPIO_INTR_DISABLE; + if( input == "rising-edge" ) return GPIO_INTR_POSEDGE; + if( input == "falling-edge" ) return GPIO_INTR_NEGEDGE; + if( input == "rising-and-falling" ) return GPIO_INTR_ANYEDGE ; + if( input == "low-level-trigger" ) return GPIO_INTR_LOW_LEVEL; + if( input == "high-level-trigger" ) return GPIO_INTR_HIGH_LEVEL; + + + return GPIO_INTR_DISABLE; +} + +static GpioHandler *gpioHandler = NULL; + +void gpio_handler_create(httpd_handle_t server) +{ + if (gpioHandler == NULL) + gpioHandler = new GpioHandler(CONFIG_FILE, server); +} + +void gpio_handler_init() +{ + if (gpioHandler != NULL) { + gpioHandler->init(); + } +} + +void gpio_handler_deinit() { + if (gpioHandler != NULL) { + gpioHandler->deinit(); + } +} + +void gpio_handler_destroy() +{ + if (gpioHandler != NULL) { + delete gpioHandler; + gpioHandler = NULL; + } +} + +GpioHandler* gpio_handler_get() +{ + return gpioHandler; } diff --git a/code/components/jomjol_controlGPIO/server_GPIO.h b/code/components/jomjol_controlGPIO/server_GPIO.h index f91e24c2..14d88412 100644 --- a/code/components/jomjol_controlGPIO/server_GPIO.h +++ b/code/components/jomjol_controlGPIO/server_GPIO.h @@ -1,10 +1,99 @@ +#ifndef SERVER_GPIO_H +#define SERVER_GPIO_H + #include #include +#include +#include "driver/gpio.h" //#include "ClassControllCamera.h" -static const char *TAGPARTGPIO = "server_GPIO"; +typedef enum { + GPIO_PIN_MODE_DISABLED = 0x0, + GPIO_PIN_MODE_INPUT = 0x1, + GPIO_PIN_MODE_INPUT_PULLUP = 0x2, + GPIO_PIN_MODE_INPUT_PULLDOWN = 0x3, + GPIO_PIN_MODE_OUTPUT = 0x4, + GPIO_PIN_MODE_BUILT_IN_FLASH_LED = 0x5, + GPIO_PIN_MODE_OUTPUT_PWM = 0x6, + GPIO_PIN_MODE_EXTERNAL_FLASH_PWM = 0x7, + GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X = 0x8, +} gpio_pin_mode_t; -void register_server_GPIO_uri(httpd_handle_t server); +struct GpioResult { + gpio_num_t gpio; + int value; +}; +typedef enum { + GPIO_SET_SOURCE_INTERNAL = 0, + GPIO_SET_SOURCE_MQTT = 1, + GPIO_SET_SOURCE_HTTP = 2, +} gpio_set_source; + +class GpioPin { +public: + GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_int_type_t interruptType, uint8_t dutyResolution, std::string mqttTopic, bool httpEnable); + ~GpioPin(); + + void init(); + bool getValue(std::string* errorText); + void setValue(bool value, gpio_set_source setSource, std::string* errorText); + bool handleMQTT(std::string, char* data, int data_len); + void publishState(); + void gpioInterrupt(int value); + gpio_int_type_t getInterruptType() { return _interruptType; } + gpio_pin_mode_t getMode() { return _mode; } + +private: + gpio_num_t _gpio; + const char* _name; + gpio_pin_mode_t _mode; + gpio_int_type_t _interruptType; + std::string _mqttTopic; + int currentState = -1; +}; + +esp_err_t callHandleHttpRequest(httpd_req_t *req); +void taskGpioHandler(void *pvParameter); + +class GpioHandler { +public: + GpioHandler(std::string configFile, httpd_handle_t httpServer); + ~GpioHandler(); + + void init(); + void deinit(); + void registerGpioUri(); + esp_err_t handleHttpRequest(httpd_req_t *req); + void taskHandler(); + void gpioInterrupt(GpioResult* gpioResult); + void flashLightEnable(bool value); + bool isEnabled() { return _isEnabled; } + void handleMQTTconnect(); + +private: + std::string _configFile; + httpd_handle_t _httpServer; + std::map *gpioMap = NULL; + TaskHandle_t xHandleTaskGpio = NULL; + bool _isEnabled = false; + + bool readConfig(); + void clear(); + + gpio_num_t resolvePinNr(uint8_t pinNr); + gpio_pin_mode_t resolvePinMode(std::string input); + gpio_int_type_t resolveIntType(std::string input); +}; + +void gpio_handler_create(httpd_handle_t server); +void gpio_handler_init(); +void gpio_handler_deinit(); +void gpio_handler_destroy(); +GpioHandler* gpio_handler_get(); + + + +#endif //SERVER_GPIO_H \ No newline at end of file diff --git a/code/components/jomjol_controlcamera/CMakeLists.txt b/code/components/jomjol_controlcamera/CMakeLists.txt index f006f013..ec401f60 100644 --- a/code/components/jomjol_controlcamera/CMakeLists.txt +++ b/code/components/jomjol_controlcamera/CMakeLists.txt @@ -4,6 +4,6 @@ list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/proto idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "." - REQUIRES esp32-camera-master esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota) + REQUIRES esp32-camera-master esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota jomjol_controlGPIO) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index b7f80d38..defa7777 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -10,12 +10,13 @@ #include "CImageBasis.h" #include "server_ota.h" +#include "server_GPIO.h" #define BOARD_ESP32CAM_AITHINKER -#include +#include #include #include #include @@ -50,7 +51,7 @@ #define CAM_PIN_HREF 23 #define CAM_PIN_PCLK 22 -static const char *TAG = "example:take_picture"; +static const char *TAGCAMERACLASS = "server_part_camera"; static camera_config_t camera_config = { .pin_pwdn = CAM_PIN_PWDN, @@ -275,7 +276,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { - ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed"); + ESP_LOGE(TAGCAMERACLASS, "CaptureToBasisImage: Camera Capture Failed"); LEDOnOff(false); LightOnOff(false); doReboot(); @@ -362,8 +363,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay) camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { - ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed"); - ESP_LOGE(TAGCAMERACLASS, "Reboot ?????"); + ESP_LOGE(TAGCAMERACLASS, "CaptureToFile: Camera Capture Failed"); LEDOnOff(false); LightOnOff(false); doReboot(); @@ -497,15 +497,20 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) void CCamera::LightOnOff(bool status) { - // Init the GPIO - gpio_pad_select_gpio(FLASH_GPIO); - /* Set the GPIO as a push/pull output */ - gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); + GpioHandler* gpioHandler = gpio_handler_get(); + if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) { + gpioHandler->flashLightEnable(status); + } else { + // Init the GPIO + gpio_pad_select_gpio(FLASH_GPIO); + /* Set the GPIO as a push/pull output */ + gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); - if (status) - gpio_set_level(FLASH_GPIO, 1); - else - gpio_set_level(FLASH_GPIO, 0); + if (status) + gpio_set_level(FLASH_GPIO, 1); + else + gpio_set_level(FLASH_GPIO, 0); + } } void CCamera::LEDOnOff(bool status) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index b4389b8a..796a298e 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -16,9 +16,6 @@ #define CAMERA_MODEL_AI_THINKER -static const char *TAGCAMERACLASS = "server_part_camera"; - - class CCamera { protected: int ActualQuality; diff --git a/code/components/jomjol_controlcamera/server_camera.cpp b/code/components/jomjol_controlcamera/server_camera.cpp index d318a736..09cef729 100644 --- a/code/components/jomjol_controlcamera/server_camera.cpp +++ b/code/components/jomjol_controlcamera/server_camera.cpp @@ -12,14 +12,17 @@ char scratch2[SCRATCH_BUFSIZE2]; //#define DEBUG_DETAIL_ON - +static const char *TAGPARTCAMERA = "server_camera"; void PowerResetCamera(){ ESP_LOGD(TAGPARTCAMERA, "Resetting camera by power down line"); - gpio_config_t conf = { 0 }; + gpio_config_t conf; + conf.intr_type = GPIO_INTR_DISABLE; conf.pin_bit_mask = 1LL << GPIO_NUM_32; conf.mode = GPIO_MODE_OUTPUT; + conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + conf.pull_up_en = GPIO_PULLUP_DISABLE; gpio_config(&conf); // carefull, logic is inverted compared to reset pin diff --git a/code/components/jomjol_controlcamera/server_camera.h b/code/components/jomjol_controlcamera/server_camera.h index b3f1fe19..ac58ca78 100644 --- a/code/components/jomjol_controlcamera/server_camera.h +++ b/code/components/jomjol_controlcamera/server_camera.h @@ -7,8 +7,6 @@ //#include "ClassControllCamera.h" -static const char *TAGPARTCAMERA = "server_camera"; - void register_server_camera_uri(httpd_handle_t server); void PowerResetCamera(); diff --git a/code/components/jomjol_fileserver_ota/CMakeLists.txt b/code/components/jomjol_fileserver_ota/CMakeLists.txt index 752bc5d1..58355dfe 100644 --- a/code/components/jomjol_fileserver_ota/CMakeLists.txt +++ b/code/components/jomjol_fileserver_ota/CMakeLists.txt @@ -1,7 +1,7 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*) idf_component_register(SRCS ${app_sources} - INCLUDE_DIRS "." - REQUIRES tfmicro esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper) + INCLUDE_DIRS "." "../../include" + REQUIRES tfmicro esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO) diff --git a/code/components/jomjol_fileserver_ota/server_file.cpp b/code/components/jomjol_fileserver_ota/server_file.cpp index 26bf32b0..289d7bb6 100644 --- a/code/components/jomjol_fileserver_ota/server_file.cpp +++ b/code/components/jomjol_fileserver_ota/server_file.cpp @@ -26,9 +26,12 @@ #include #include "esp_http_server.h" +#include "defines.h" #include "ClassLogFile.h" #include "server_help.h" +#include "interface_mqtt.h" +#include "server_GPIO.h" #include "Helper.h" #include "miniz.h" @@ -53,17 +56,17 @@ struct file_server_data { char scratch[SCRATCH_BUFSIZE]; }; -static const char *TAG = "file_server"; +static const char *TAG_FILESERVER = "file_server"; /* Handler to redirect incoming GET request for /index.html to / * This can be overridden by uploading file with same name */ -static esp_err_t index_html_get_handler(httpd_req_t *req) -{ - httpd_resp_set_status(req, "307 Temporary Redirect"); - httpd_resp_set_hdr(req, "Location", "/"); - httpd_resp_send(req, NULL, 0); // Response body can be empty - return ESP_OK; -} +// static esp_err_t index_html_get_handler(httpd_req_t *req) +// { +// httpd_resp_set_status(req, "307 Temporary Redirect"); +// httpd_resp_set_hdr(req, "Location", "/"); +// httpd_resp_send(req, NULL, 0); // Response body can be empty +// return ESP_OK; +// } /* Send HTTP response with a run-time generated html consisting of * a list of all files and folders under the requested path. @@ -95,7 +98,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const printf("entrypath: <%s>\n", entrypath); if (!dir) { - ESP_LOGE(TAG, "Failed to stat dir : %s", dirpath); + ESP_LOGE(TAG_FILESERVER, "Failed to stat dir : %s", dirpath); /* Respond with 404 Not Found */ httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Directory does not exist"); return ESP_FAIL; @@ -115,7 +118,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const if (chunksize > 0){ if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) { fclose(fd); - ESP_LOGE(TAG, "File sending failed!"); + ESP_LOGE(TAG_FILESERVER, "File sending failed!"); return ESP_FAIL; } } @@ -154,11 +157,11 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len); printf("Entrypath: %s\n", entrypath); if (stat(entrypath, &entry_stat) == -1) { - ESP_LOGE(TAG, "Failed to stat %s : %s", entrytype, entry->d_name); + ESP_LOGE(TAG_FILESERVER, "Failed to stat %s : %s", entrytype, entry->d_name); continue; } sprintf(entrysize, "%ld", entry_stat.st_size); - ESP_LOGI(TAG, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize); + ESP_LOGI(TAG_FILESERVER, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize); /* Send chunk of HTML file containing table entries with file name and size */ httpd_resp_sendstr_chunk(req, "uri); - const char filename = 'log_current.txt'; + const char* filename = "log_current.txt"; - printf("uri: %s, filename: %s, filepath: %s\n", req->uri, &filename, filepath); + printf("uri: %s, filename: %s, filepath: %s\n", req->uri, filename, filepath); std::string currentfilename = LogFile.GetCurrentFileName(); fd = OpenFileAndWait(currentfilename.c_str(), "r"); if (!fd) { - ESP_LOGE(TAG, "Failed to read existing file : %s", filepath); + ESP_LOGE(TAG_FILESERVER, "Failed to read existing file : %s", filepath); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file"); return ESP_FAIL; @@ -226,8 +229,8 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req) httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); -// ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size); - set_content_type_from_file(req, &filename); +// ESP_LOGI(TAG_FILESERVER, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size); + set_content_type_from_file(req, filename); /* Retrieve the pointer to scratch buffer for temporary storage */ char *chunk = ((struct file_server_data *)req->user_ctx)->scratch; @@ -239,7 +242,7 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req) /* Send the buffer contents as HTTP response chunk */ if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) { fclose(fd); - ESP_LOGE(TAG, "File sending failed!"); + ESP_LOGE(TAG_FILESERVER, "File sending failed!"); /* Abort sending file */ httpd_resp_sendstr_chunk(req, NULL); /* Respond with 500 Internal Server Error */ @@ -252,7 +255,7 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req) /* Close file after sending complete */ fclose(fd); - ESP_LOGI(TAG, "File sending complete"); + ESP_LOGI(TAG_FILESERVER, "File sending complete"); /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); @@ -284,7 +287,7 @@ static esp_err_t download_get_handler(httpd_req_t *req) if (!filename) { - ESP_LOGE(TAG, "Filename is too long"); + ESP_LOGE(TAG_FILESERVER, "Filename is too long"); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); return ESP_FAIL; @@ -297,11 +300,11 @@ static esp_err_t download_get_handler(httpd_req_t *req) if (buf_len > 1) { char buf[buf_len]; if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { - ESP_LOGI(TAG, "Found URL query => %s", buf); + ESP_LOGI(TAG_FILESERVER, "Found URL query => %s", buf); char param[32]; /* Get value of expected key from query string */ if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) { - ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param); + ESP_LOGI(TAG_FILESERVER, "Found URL query parameter => readonly=%s", param); readonly = param && strcmp(param,"true")==0; } } @@ -316,7 +319,7 @@ static esp_err_t download_get_handler(httpd_req_t *req) /* If file not present on SPIFFS check if URI * corresponds to one of the hardcoded paths */ - ESP_LOGE(TAG, "Failed to stat file : %s", filepath); + ESP_LOGE(TAG_FILESERVER, "Failed to stat file : %s", filepath); /* Respond with 404 Not Found */ httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist"); return ESP_FAIL; @@ -324,7 +327,7 @@ static esp_err_t download_get_handler(httpd_req_t *req) fd = OpenFileAndWait(filepath, "r"); if (!fd) { - ESP_LOGE(TAG, "Failed to read existing file : %s", filepath); + ESP_LOGE(TAG_FILESERVER, "Failed to read existing file : %s", filepath); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file"); return ESP_FAIL; @@ -332,7 +335,7 @@ static esp_err_t download_get_handler(httpd_req_t *req) httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size); + ESP_LOGI(TAG_FILESERVER, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size); set_content_type_from_file(req, filename); /* Retrieve the pointer to scratch buffer for temporary storage */ @@ -345,7 +348,7 @@ static esp_err_t download_get_handler(httpd_req_t *req) /* Send the buffer contents as HTTP response chunk */ if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) { fclose(fd); - ESP_LOGE(TAG, "File sending failed!"); + ESP_LOGE(TAG_FILESERVER, "File sending failed!"); /* Abort sending file */ httpd_resp_sendstr_chunk(req, NULL); /* Respond with 500 Internal Server Error */ @@ -358,7 +361,7 @@ static esp_err_t download_get_handler(httpd_req_t *req) /* Close file after sending complete */ fclose(fd); - ESP_LOGI(TAG, "File sending complete"); + ESP_LOGI(TAG_FILESERVER, "File sending complete"); /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); @@ -385,13 +388,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req) /* Filename cannot have a trailing '/' */ if (filename[strlen(filename) - 1] == '/') { - ESP_LOGE(TAG, "Invalid filename : %s", filename); + ESP_LOGE(TAG_FILESERVER, "Invalid filename : %s", filename); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Invalid filename"); return ESP_FAIL; } if (stat(filepath, &file_stat) == 0) { - ESP_LOGE(TAG, "File already exists : %s", filepath); + ESP_LOGE(TAG_FILESERVER, "File already exists : %s", filepath); /* Respond with 400 Bad Request */ httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File already exists"); return ESP_FAIL; @@ -399,7 +402,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req) /* File cannot be larger than a limit */ if (req->content_len > MAX_FILE_SIZE) { - ESP_LOGE(TAG, "File too large : %d bytes", req->content_len); + ESP_LOGE(TAG_FILESERVER, "File too large : %d bytes", req->content_len); /* Respond with 400 Bad Request */ httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File size must be less than " @@ -411,13 +414,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req) fd = OpenFileAndWait(filepath, "w"); if (!fd) { - ESP_LOGE(TAG, "Failed to create file : %s", filepath); + ESP_LOGE(TAG_FILESERVER, "Failed to create file : %s", filepath); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to create file"); return ESP_FAIL; } - ESP_LOGI(TAG, "Receiving file : %s...", filename); + ESP_LOGI(TAG_FILESERVER, "Receiving file : %s...", filename); /* Retrieve the pointer to scratch buffer for temporary storage */ char *buf = ((struct file_server_data *)req->user_ctx)->scratch; @@ -429,7 +432,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req) while (remaining > 0) { - ESP_LOGI(TAG, "Remaining size : %d", remaining); + ESP_LOGI(TAG_FILESERVER, "Remaining size : %d", remaining); /* Receive the file part by part into a buffer */ if ((received = httpd_req_recv(req, buf, MIN(remaining, SCRATCH_BUFSIZE))) <= 0) { if (received == HTTPD_SOCK_ERR_TIMEOUT) { @@ -442,7 +445,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req) fclose(fd); unlink(filepath); - ESP_LOGE(TAG, "File reception failed!"); + ESP_LOGE(TAG_FILESERVER, "File reception failed!"); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file"); return ESP_FAIL; @@ -455,7 +458,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req) fclose(fd); unlink(filepath); - ESP_LOGE(TAG, "File write failed!"); + ESP_LOGE(TAG_FILESERVER, "File write failed!"); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to write file to storage"); return ESP_FAIL; @@ -468,7 +471,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req) /* Close file upon upload completion */ fclose(fd); - ESP_LOGI(TAG, "File reception complete"); + ESP_LOGI(TAG_FILESERVER, "File reception complete"); std::string directory = std::string(filepath); size_t zw = directory.find("/"); @@ -496,6 +499,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req) httpd_resp_set_status(req, "303 See Other"); httpd_resp_set_hdr(req, "Location", directory.c_str()); httpd_resp_sendstr(req, "File uploaded successfully"); + + if (strcmp(filepath, CONFIG_FILE) == 0) { + printf("New config foung. Reload handler."); + gpio_handler_deinit(); + MQTTdestroy(); + } + return ESP_OK; } @@ -567,19 +577,19 @@ static esp_err_t delete_post_handler(httpd_req_t *req) /* Filename cannot have a trailing '/' */ if (filename[strlen(filename) - 1] == '/') { - ESP_LOGE(TAG, "Invalid filename : %s", filename); + ESP_LOGE(TAG_FILESERVER, "Invalid filename : %s", filename); httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Invalid filename"); return ESP_FAIL; } if (stat(filepath, &file_stat) == -1) { - ESP_LOGE(TAG, "File does not exist : %s", filename); + ESP_LOGE(TAG_FILESERVER, "File does not exist : %s", filename); /* Respond with 400 Bad Request */ httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist"); return ESP_FAIL; } - ESP_LOGI(TAG, "Deleting file : %s", filename); + ESP_LOGI(TAG_FILESERVER, "Deleting file : %s", filename); /* Delete file */ unlink(filepath); @@ -623,7 +633,7 @@ void delete_all_in_directory(std::string _directory) std::string filename; if (!dir) { - ESP_LOGE(TAG, "Failed to stat dir : %s", _directory.c_str()); + ESP_LOGE(TAG_FILESERVER, "Failed to stat dir : %s", _directory.c_str()); return; } @@ -632,7 +642,7 @@ void delete_all_in_directory(std::string _directory) if (!(entry->d_type == DT_DIR)){ if (strcmp("wlan.ini", entry->d_name) != 0){ // auf wlan.ini soll nicht zugegriffen werden !!! filename = _directory + "/" + std::string(entry->d_name); - ESP_LOGI(TAG, "Deleting file : %s", filename.c_str()); + ESP_LOGI(TAG_FILESERVER, "Deleting file : %s", filename.c_str()); /* Delete file */ unlink(filename.c_str()); } @@ -722,19 +732,19 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path) /* Validate file storage base path */ if (!base_path) { // if (!base_path || strcmp(base_path, "/spiffs") != 0) { - ESP_LOGE(TAG, "File server base_path not set"); + ESP_LOGE(TAG_FILESERVER, "File server base_path not set"); // return ESP_ERR_INVALID_ARG; } if (server_data) { - ESP_LOGE(TAG, "File server already started"); + ESP_LOGE(TAG_FILESERVER, "File server already started"); // return ESP_ERR_INVALID_STATE; } /* Allocate memory for server data */ server_data = (file_server_data *) calloc(1, sizeof(struct file_server_data)); if (!server_data) { - ESP_LOGE(TAG, "Failed to allocate memory for server data"); + ESP_LOGE(TAG_FILESERVER, "Failed to allocate memory for server data"); // return ESP_ERR_NO_MEM; } strlcpy(server_data->base_path, base_path, diff --git a/code/components/jomjol_fileserver_ota/server_ota.cpp b/code/components/jomjol_fileserver_ota/server_ota.cpp index 6c69ae1e..39f4d7e9 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.cpp +++ b/code/components/jomjol_fileserver_ota/server_ota.cpp @@ -12,7 +12,7 @@ #include "freertos/task.h" #include "esp_system.h" #include "esp_event.h" -#include "esp_event_loop.h" +#include "esp_event.h" #include "esp_log.h" #include #include "esp_http_client.h" @@ -28,6 +28,7 @@ #include "server_tflite.h" #include "server_file.h" +#include "server_GPIO.h" #include "ClassLogFile.h" @@ -46,6 +47,7 @@ static char ota_write_data[BUFFSIZE + 1] = { 0 }; #define OTA_URL_SIZE 256 +static const char *TAGPARTOTA = "server_ota"; static void infinite_loop(void) @@ -60,14 +62,14 @@ static void infinite_loop(void) -static bool ota_example_task(std::string fn) +static bool ota_update_task(std::string fn) { esp_err_t err; /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */ esp_ota_handle_t update_handle = 0 ; const esp_partition_t *update_partition = NULL; - ESP_LOGI(TAGPARTOTA, "Starting OTA example"); + ESP_LOGI(TAGPARTOTA, "Starting OTA update"); const esp_partition_t *configured = esp_ota_get_boot_partition(); const esp_partition_t *running = esp_ota_get_running_partition(); @@ -374,7 +376,9 @@ esp_err_t handler_ota_update(httpd_req_t *req) const char* resp_str; - if (ota_example_task(fn)) + KillTFliteTasks(); + gpio_handler_deinit(); + if (ota_update_task(fn)) { resp_str = "Firmware Update Successfull!

You can restart now."; } @@ -400,8 +404,6 @@ void hard_restart() { void task_reboot(void *pvParameter) { - - while(1) { vTaskDelay(5000 / portTICK_PERIOD_MS); @@ -413,12 +415,14 @@ void task_reboot(void *pvParameter) } void doReboot(){ - LogFile.WriteToFile("Reboot - now"); - KillTFliteTasks(); + ESP_LOGI(TAGPARTOTA, "Reboot in 5sec"); + LogFile.WriteToFile("Reboot in 5sec"); xTaskCreate(&task_reboot, "reboot", configMINIMAL_STACK_SIZE * 64, NULL, 10, NULL); + // KillTFliteTasks(); // kills itself + gpio_handler_destroy(); vTaskDelay(5000 / portTICK_PERIOD_MS); esp_restart(); - hard_restart(); + hard_restart(); } diff --git a/code/components/jomjol_fileserver_ota/server_ota.h b/code/components/jomjol_fileserver_ota/server_ota.h index e227d146..415e5fd9 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.h +++ b/code/components/jomjol_fileserver_ota/server_ota.h @@ -4,8 +4,6 @@ //#include "ClassControllCamera.h" -static const char *TAGPARTOTA = "server_ota"; - void register_server_ota_sdcard_uri(httpd_handle_t server); void CheckOTAUpdate(); void doReboot(); diff --git a/code/components/jomjol_flowcontroll/ClassFlow.cpp b/code/components/jomjol_flowcontroll/ClassFlow.cpp index 3ee76cfb..ab03d72c 100644 --- a/code/components/jomjol_flowcontroll/ClassFlow.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlow.cpp @@ -94,6 +94,23 @@ string ClassFlow::getReadout() return string(); } +std::string ClassFlow::GetParameterName(std::string _input) +{ + string _param; + int _pospunkt = _input.find_first_of("."); + if (_pospunkt > -1) + { + _param = _input.substr(_pospunkt+1, _input.length() - _pospunkt - 1); + } + else + { + _param = _input; + } +// printf("Parameter: %s, Pospunkt: %d\n", _param.c_str(), _pospunkt); + return _param; +} + + bool ClassFlow::getNextLine(FILE* pfile, string *rt) { char zw[1024]; @@ -102,24 +119,23 @@ bool ClassFlow::getNextLine(FILE* pfile, string *rt) *rt = ""; return false; } - fgets(zw, 1024, pfile); - printf("%s", zw); - if ((strlen(zw) == 0) && feof(pfile)) + if (!fgets(zw, 1024, pfile)) { *rt = ""; + printf("END OF FILE\n"); return false; } + printf("%s", zw); *rt = zw; *rt = trim(*rt); while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '[')) // Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph { - fgets(zw, 1024, pfile); - printf("%s", zw); - if (feof(pfile)) + if (!fgets(zw, 1024, pfile)) { *rt = ""; return false; } + printf("%s", zw); *rt = zw; *rt = trim(*rt); } diff --git a/code/components/jomjol_flowcontroll/ClassFlow.h b/code/components/jomjol_flowcontroll/ClassFlow.h index bcad7b4f..4df4777c 100644 --- a/code/components/jomjol_flowcontroll/ClassFlow.h +++ b/code/components/jomjol_flowcontroll/ClassFlow.h @@ -37,6 +37,8 @@ protected: virtual void SetInitialParameter(void); + std::string GetParameterName(std::string _input); + bool disabled; public: diff --git a/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp b/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp index a23d8b42..91cf5fc6 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp @@ -1,7 +1,7 @@ #include "ClassFlowAnalog.h" #include -#include +#include #include #include // std::stringstream @@ -46,9 +46,9 @@ ClassFlowAnalog::ClassFlowAnalog(std::vector* lfc) : ClassFlowImage( } -int ClassFlowAnalog::AnzahlROIs() +int ClassFlowAnalog::AnzahlROIs(int _analog = 0) { - int zw = ROI.size(); + int zw = ANALOG[_analog]->ROI.size(); if (extendedResolution) zw++; @@ -56,27 +56,27 @@ int ClassFlowAnalog::AnzahlROIs() } -string ClassFlowAnalog::getReadout() +string ClassFlowAnalog::getReadout(int _analog = 0) { string result = ""; - if (ROI.size() == 0) + if (ANALOG[_analog]->ROI.size() == 0) return result; - float zahl = ROI[ROI.size() - 1]->result; + float zahl = ANALOG[_analog]->ROI[ANALOG[_analog]->ROI.size() - 1]->result; int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10; int prev = -1; - prev = ZeigerEval(ROI[ROI.size() - 1]->result, prev); + prev = ZeigerEval(ANALOG[_analog]->ROI[ANALOG[_analog]->ROI.size() - 1]->result, prev); result = std::to_string(prev); if (extendedResolution) result = result + std::to_string(ergebnis_nachkomma); - for (int i = ROI.size() - 2; i >= 0; --i) + for (int i = ANALOG[_analog]->ROI.size() - 2; i >= 0; --i) { - prev = ZeigerEval(ROI[i]->result, prev); + prev = ZeigerEval(ANALOG[_analog]->ROI[i]->result, prev); result = std::to_string(prev) + result; } @@ -153,8 +153,8 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph) } if (zerlegt.size() >= 5) { - roianalog* neuroi = new roianalog; - neuroi->name = zerlegt[0]; + analog* _analog = GetANALOG(zerlegt[0], true); + roianalog* neuroi = _analog->ROI[_analog->ROI.size()-1]; neuroi->posx = std::stoi(zerlegt[1]); neuroi->posy = std::stoi(zerlegt[2]); neuroi->deltax = std::stoi(zerlegt[3]); @@ -162,7 +162,7 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph) neuroi->result = -1; neuroi->image = NULL; neuroi->image_org = NULL; - ROI.push_back(neuroi); +// ROI.push_back(neuroi); } if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1)) @@ -178,15 +178,76 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph) } } - for (int i = 0; i < ROI.size(); ++i) - { - ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3); - ROI[i]->image_org = new CImageBasis(ROI[i]->deltax, ROI[i]->deltay, 3); - } + for (int _ana = 0; _ana < ANALOG.size(); ++_ana) + for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i) + { + ANALOG[_ana]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3); + ANALOG[_ana]->ROI[i]->image_org = new CImageBasis(ANALOG[_ana]->ROI[i]->deltax, ANALOG[_ana]->ROI[i]->deltay, 3); + } return true; } +analog* ClassFlowAnalog::FindANALOG(string _name_number) +{ + analog *_ret = NULL; + + for (int i = 0; i < ANALOG.size(); ++i) + { + if (ANALOG[i]->name == _name_number) + return ANALOG[i]; + } + + return NULL; +} + + + +analog* ClassFlowAnalog::GetANALOG(string _name, bool _create = true) +{ + string _analog, _roi; + int _pospunkt = _name.find_first_of("."); +// printf("Name: %s, Pospunkt: %d\n", _name.c_str(), _pospunkt); + if (_pospunkt > -1) + { + _analog = _name.substr(0, _pospunkt); + _roi = _name.substr(_pospunkt+1, _name.length() - _pospunkt - 1); + } + else + { + _analog = "default"; + _roi = _name; + } + + analog *_ret = NULL; + + for (int i = 0; i < ANALOG.size(); ++i) + { + if (ANALOG[i]->name == _analog) + _ret = ANALOG[i]; + } + + if (!_create) // nicht gefunden und soll auch nicht erzeugt werden + return _ret; + + + if (_ret == NULL) + { + _ret = new analog; + _ret->name = _analog; + ANALOG.push_back(_ret); + } + + roianalog* neuroi = new roianalog; + neuroi->name = _roi; + _ret->ROI.push_back(neuroi); + + printf("GetANALOG - ANALOG %s - roi %s\n", _analog.c_str(), _roi.c_str()); + + return _ret; +} + + string ClassFlowAnalog::getHTMLSingleStep(string host) { @@ -238,16 +299,29 @@ bool ClassFlowAnalog::doAlignAndCut(string time) CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage(); - for (int i = 0; i < ROI.size(); ++i) - { - printf("Analog %d - Align&Cut\n", i); - - caic->CutAndSave(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, ROI[i]->image_org); - if (SaveAllFiles) ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".jpg")); + for (int _ana = 0; _ana < ANALOG.size(); ++_ana) + for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i) + { + printf("Analog %d - Align&Cut\n", i); + + caic->CutAndSave(ANALOG[_ana]->ROI[i]->posx, ANALOG[_ana]->ROI[i]->posy, ANALOG[_ana]->ROI[i]->deltax, ANALOG[_ana]->ROI[i]->deltay, ANALOG[_ana]->ROI[i]->image_org); + if (SaveAllFiles) + { + if (ANALOG[_ana]->name == "default") + ANALOG[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->ROI[i]->name + ".jpg")); + else + ANALOG[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".jpg")); + } - ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image); - if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp")); - } + ANALOG[_ana]->ROI[i]->image_org->Resize(modelxsize, modelysize, ANALOG[_ana]->ROI[i]->image); + if (SaveAllFiles) + { + if (ANALOG[_ana]->name == "default") + ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->ROI[i]->name + ".bmp")); + else + ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".bmp")); + } + } return true; } @@ -258,13 +332,14 @@ void ClassFlowAnalog::DrawROI(CImageBasis *_zw) int g = 255; int b = 0; - for (int i = 0; i < ROI.size(); ++i) - { - _zw->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, r, g, b, 1); - _zw->drawCircle((int) (ROI[i]->posx + ROI[i]->deltax/2), (int) (ROI[i]->posy + ROI[i]->deltay/2), (int) (ROI[i]->deltax/2), r, g, b, 2); - _zw->drawLine((int) (ROI[i]->posx + ROI[i]->deltax/2), (int) ROI[i]->posy, (int) (ROI[i]->posx + ROI[i]->deltax/2), (int) (ROI[i]->posy + ROI[i]->deltay), r, g, b, 2); - _zw->drawLine((int) ROI[i]->posx, (int) (ROI[i]->posy + ROI[i]->deltay/2), (int) ROI[i]->posx + ROI[i]->deltax, (int) (ROI[i]->posy + ROI[i]->deltay/2), r, g, b, 2); - } + for (int _ana = 0; _ana < ANALOG.size(); ++_ana) + for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i) + { + _zw->drawRect(ANALOG[_ana]->ROI[i]->posx, ANALOG[_ana]->ROI[i]->posy, ANALOG[_ana]->ROI[i]->deltax, ANALOG[_ana]->ROI[i]->deltay, r, g, b, 1); + _zw->drawCircle((int) (ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax/2), (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay/2), (int) (ANALOG[_ana]->ROI[i]->deltax/2), r, g, b, 2); + _zw->drawLine((int) (ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax/2), (int) ANALOG[_ana]->ROI[i]->posy, (int) (ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax/2), (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay), r, g, b, 2); + _zw->drawLine((int) ANALOG[_ana]->ROI[i]->posx, (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay/2), (int) ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax, (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay/2), r, g, b, 2); + } } bool ClassFlowAnalog::doNeuralNetwork(string time) @@ -284,43 +359,46 @@ bool ClassFlowAnalog::doNeuralNetwork(string time) string zwcnn = "/sdcard" + cnnmodelfile; zwcnn = FormatFileName(zwcnn); printf(zwcnn.c_str());printf("\n"); - tflite->LoadModel(zwcnn); + if (!tflite->LoadModel(zwcnn)) { + printf("Can't read model file /sdcard%s\n", cnnmodelfile.c_str()); + delete tflite; + return false; + } tflite->MakeAllocate(); #endif - for (int i = 0; i < ROI.size(); ++i) + for (int _ana = 0; _ana < ANALOG.size(); ++_ana) { - printf("Analog %d - TfLite\n", i); - ioresize = "/sdcard/img_tmp/ra" + std::to_string(i) + ".bmp"; - ioresize = FormatFileName(ioresize); - - - float f1, f2; - f1 = 0; f2 = 0; - -#ifndef OHNETFLITE -// LogFile.WriteToFile("ClassFlowAnalog::doNeuralNetwork vor CNN tflite->LoadInputImage(ioresize)"); -// tflite->LoadInputImage(ioresize); - tflite->LoadInputImageBasis(ROI[i]->image); - tflite->Invoke(); - if (debugdetailanalog) LogFile.WriteToFile("Nach Invoke"); - - - f1 = tflite->GetOutputValue(0); - f2 = tflite->GetOutputValue(1); -#endif - - float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1); -// printf("Result sin, cos, ziffer: %f, %f, %f\n", f1, f2, result); - ROI[i]->result = result * 10; - - printf("Result Analog%i: %f\n", i, ROI[i]->result); - - if (isLogImage) + for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i) { - LogImage(logPath, ROI[i]->name, &ROI[i]->result, NULL, time, ROI[i]->image_org); + printf("Analog %d - TfLite\n", i); + + float f1, f2; + f1 = 0; f2 = 0; + + #ifndef OHNETFLITE + tflite->LoadInputImageBasis(ANALOG[_ana]->ROI[i]->image); + tflite->Invoke(); + if (debugdetailanalog) LogFile.WriteToFile("Nach Invoke"); + + + f1 = tflite->GetOutputValue(0); + f2 = tflite->GetOutputValue(1); + #endif + + float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1); + // printf("Result sin, cos, ziffer: %f, %f, %f\n", f1, f2, result); + ANALOG[_ana]->ROI[i]->result = result * 10; + + printf("Result Analog%i: %f\n", i, ANALOG[_ana]->ROI[i]->result); + + if (isLogImage) + { + LogImage(logPath, ANALOG[_ana]->ROI[i]->name, &ANALOG[_ana]->ROI[i]->result, NULL, time, ANALOG[_ana]->ROI[i]->image_org); + } } } + #ifndef OHNETFLITE delete tflite; #endif @@ -333,18 +411,78 @@ std::vector ClassFlowAnalog::GetHTMLInfo() { std::vector result; - for (int i = 0; i < ROI.size(); ++i) - { - HTMLInfo *zw = new HTMLInfo; - zw->filename = ROI[i]->name + ".bmp"; - zw->filename_org = ROI[i]->name + ".jpg"; - zw->val = ROI[i]->result; - zw->image = ROI[i]->image; - zw->image_org = ROI[i]->image_org; - result.push_back(zw); - } + for (int _ana = 0; _ana < ANALOG.size(); ++_ana) + for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i) + { + if (ANALOG[_ana]->name == "default") + ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->ROI[i]->name + ".bmp")); + else + ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".bmp")); + + + HTMLInfo *zw = new HTMLInfo; + if (ANALOG[_ana]->name == "default") + { + zw->filename = ANALOG[_ana]->ROI[i]->name + ".bmp"; + zw->filename_org = ANALOG[_ana]->ROI[i]->name + ".jpg"; + } + else + { + zw->filename = ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".bmp"; + zw->filename_org = ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".jpg"; + } + + zw->val = ANALOG[_ana]->ROI[i]->result; + zw->image = ANALOG[_ana]->ROI[i]->image; + zw->image_org = ANALOG[_ana]->ROI[i]->image_org; + + result.push_back(zw); + } return result; } + +int ClassFlowAnalog::getAnzahlANALOG() +{ + return ANALOG.size(); +} + +string ClassFlowAnalog::getNameANALOG(int _analog) +{ + if (_analog < ANALOG.size()) + return ANALOG[_analog]->name; + + return "ANALOG DOES NOT EXIST"; +} + +analog* ClassFlowAnalog::GetANALOG(int _analog) +{ + if (_analog < ANALOG.size()) + return ANALOG[_analog]; + + return NULL; +} + + + +void ClassFlowAnalog::UpdateNameNumbers(std::vector *_name_numbers) +{ + for (int _dig = 0; _dig < ANALOG.size(); _dig++) + { + std::string _name = ANALOG[_dig]->name; + bool found = false; + for (int i = 0; i < (*_name_numbers).size(); ++i) + { + if ((*_name_numbers)[i] == _name) + found = true; + } + if (!found) + (*_name_numbers).push_back(_name); + } +} + + + + diff --git a/code/components/jomjol_flowcontroll/ClassFlowAnalog.h b/code/components/jomjol_flowcontroll/ClassFlowAnalog.h index 08a29be7..bd9af089 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAnalog.h +++ b/code/components/jomjol_flowcontroll/ClassFlowAnalog.h @@ -10,12 +10,19 @@ struct roianalog { string name; }; +struct analog { + string name; + std::vector ROI; +}; + class ClassFlowAnalog : public ClassFlowImage { protected: - std::vector ROI; +// std::vector ROI; + std::vector ANALOG; + string cnnmodelfile; int modelxsize, modelysize; int ZeigerEval(float zahl, int ziffer_vorgaenger); @@ -24,7 +31,8 @@ protected: ClassFlowAlignment* flowpostalignment; - void SetInitialParameter(void); + void SetInitialParameter(void); + public: bool extendedResolution; @@ -34,14 +42,23 @@ public: bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string getHTMLSingleStep(string host); - string getReadout(); + string getReadout(int _analog); void DrawROI(CImageBasis *_zw); bool doNeuralNetwork(string time); bool doAlignAndCut(string time); std::vector GetHTMLInfo(); - int AnzahlROIs(); + int AnzahlROIs(int _analog); + + int getAnzahlANALOG(); + analog* GetANALOG(int _analog); + analog* GetANALOG(string _name, bool _create); + analog* FindANALOG(string _name_number); + string getNameANALOG(int _analog); + + void UpdateNameNumbers(std::vector *_name_numbers); + string name(){return "ClassFlowAnalog";}; }; diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp index 7399aa23..7cc091e1 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp @@ -120,6 +120,7 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type) } if (toUpper(_type).compare("[MQTT]") == 0) cfc = new ClassFlowMQTT(&FlowControll); + if (toUpper(_type).compare("[POSTPROCESSING]") == 0) { cfc = new ClassFlowPostProcessing(&FlowControll); @@ -209,7 +210,7 @@ bool ClassFlowControll::doFlow(string time) int repeat = 0; #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowAnalog::doFlow - Start"); + LogFile.WriteHeapInfo("ClassFlowControll::doFlow - Start"); #endif for (int i = 0; i < FlowControll.size(); ++i) @@ -238,7 +239,7 @@ bool ClassFlowControll::doFlow(string time) } #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowAnalog::doFlow"); + LogFile.WriteHeapInfo("ClassFlowControll::doFlow"); #endif } @@ -262,6 +263,38 @@ void ClassFlowControll::UpdateAktStatus(std::string _flow) } +string ClassFlowControll::getReadoutAll(int _type) +{ + std::vector numbers = flowpostprocessing->GetNumbers(); + std::string out = ""; + + for (int i = 0; i < numbers.size(); ++i) + { + out = out + numbers[i]->name + "\t"; + switch (_type) { + case READOUT_TYPE_VALUE: + out = out + numbers[i]->ReturnValue; + break; + case READOUT_TYPE_PREVALUE: + out = out + numbers[i]->ReturnPreValue; + break; + case READOUT_TYPE_RAWVALUE: + out = out + numbers[i]->ReturnRawValue; + break; + case READOUT_TYPE_ERROR: + out = out + numbers[i]->ErrorMessageText; + break; + } + if (i < numbers.size()-1) + out = out + "\r\n"; + } + +// printf("OUT: %s", out.c_str()); + + return out; +} + + string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false) { if (flowpostprocessing) @@ -285,17 +318,17 @@ string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = fal return result; } -string ClassFlowControll::GetPrevalue() +string ClassFlowControll::GetPrevalue(std::string _number) { if (flowpostprocessing) { - return flowpostprocessing->GetPreValue(); + return flowpostprocessing->GetPreValue(_number); } return std::string(); } -std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue) +std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers) { float zw; char* p; @@ -317,7 +350,7 @@ std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue) if (flowpostprocessing) { - flowpostprocessing->SavePreValue(zw); + flowpostprocessing->SetPreValue(zw, _numbers); return _newvalue; } @@ -442,7 +475,7 @@ int ClassFlowControll::CleanTempFolder() { esp_err_t ClassFlowControll::SendRawJPG(httpd_req_t *req) { - return flowmakeimage->SendRawJPG(req); + return flowmakeimage != NULL ? flowmakeimage->SendRawJPG(req) : ESP_FAIL; } @@ -454,6 +487,12 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req) esp_err_t result = ESP_FAIL; bool Dodelete = false; + if (flowalignment == NULL) + { + printf("Can't continue, flowalignment is NULL\n"); + return ESP_FAIL; + } + if (_fn == "alg.jpg") { _send = flowalignment->ImageBasis; @@ -485,7 +524,9 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req) if (htmlinfo[i]->image_org) _send = htmlinfo[i]->image_org; } + delete htmlinfo[i]; } + htmlinfo.clear(); htmlinfo = GetAllAnalog(); for (int i = 0; i < htmlinfo.size(); ++i) @@ -500,7 +541,9 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req) if (htmlinfo[i]->image_org) _send = htmlinfo[i]->image_org; } + delete htmlinfo[i]; } + htmlinfo.clear(); if (_send) { diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.h b/code/components/jomjol_flowcontroll/ClassFlowControll.h index 6ef26a2c..7a21406b 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.h +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.h @@ -11,6 +11,12 @@ #include "ClassFlowMQTT.h" +#define READOUT_TYPE_VALUE 0 +#define READOUT_TYPE_PREVALUE 1 +#define READOUT_TYPE_RAWVALUE 2 +#define READOUT_TYPE_ERROR 3 + + class ClassFlowControll : public ClassFlow { @@ -38,8 +44,9 @@ public: void doFlowMakeImageOnly(string time); bool getStatusSetupModus(){return SetupModeActive;}; string getReadout(bool _rawvalue, bool _noerror); - string UpdatePrevalue(std::string _newvalue); - string GetPrevalue(); + string getReadoutAll(int _type); + string UpdatePrevalue(std::string _newvalue, std::string _numbers); + string GetPrevalue(std::string _number = ""); bool ReadParameter(FILE* pfile, string& aktparamgraph); esp_err_t GetJPGStream(std::string _fn, httpd_req_t *req); diff --git a/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp b/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp index 6e37cc0b..0c214a63 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp @@ -64,16 +64,16 @@ ClassFlowDigit::ClassFlowDigit(std::vector* lfc, ClassFlow *_prev) : } } -string ClassFlowDigit::getReadout() +string ClassFlowDigit::getReadout(int _digit = 0) { string rst = ""; - for (int i = 0; i < ROI.size(); ++i) + for (int i = 0; i < DIGIT[_digit]->ROI.size(); ++i) { - if (ROI[i]->resultklasse == 10) + if (DIGIT[_digit]->ROI[i]->resultklasse == 10) rst = rst + "N"; else - rst = rst + std::to_string(ROI[i]->resultklasse); + rst = rst + std::to_string(DIGIT[_digit]->ROI[i]->resultklasse); } return rst; @@ -91,18 +91,11 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph) printf("aktparamgraph: %s\n", aktparamgraph.c_str()); - -/* - if ((aktparamgraph.compare("[Digits]") != 0) && (aktparamgraph.compare(";[Digits]") != 0)) // Paragraph passt nich zu MakeImage - return false; -*/ - if ((aktparamgraph.compare(0, 7, "[Digits") != 0) && (aktparamgraph.compare(0, 8, ";[Digits") != 0)) // Paragraph passt nich zu MakeImage return false; int _pospkt = aktparamgraph.find_first_of("."); int _posklammerzu = aktparamgraph.find_first_of("]"); -// printf("Pos: %d, %d\n", _pospkt, _posklammerzu); if (_pospkt > -1) NameDigit = aktparamgraph.substr(_pospkt+1, _posklammerzu - _pospkt-1); else @@ -137,8 +130,8 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph) } if (zerlegt.size() >= 5) { - roi* neuroi = new roi; - neuroi->name = zerlegt[0]; + digit* _digit = GetDIGIT(zerlegt[0], true); + roi* neuroi = _digit->ROI[_digit->ROI.size()-1]; neuroi->posx = std::stoi(zerlegt[1]); neuroi->posy = std::stoi(zerlegt[2]); neuroi->deltax = std::stoi(zerlegt[3]); @@ -146,7 +139,6 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph) neuroi->resultklasse = -1; neuroi->image = NULL; neuroi->image_org = NULL; - ROI.push_back(neuroi); } if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1)) @@ -157,15 +149,74 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph) } - for (int i = 0; i < ROI.size(); ++i) - { - ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3); - ROI[i]->image_org = new CImageBasis(ROI[i]->deltax, ROI[i]->deltay, 3); - } + for (int _dig = 0; _dig < DIGIT.size(); ++_dig) + for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i) + { + DIGIT[_dig]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3); + DIGIT[_dig]->ROI[i]->image_org = new CImageBasis(DIGIT[_dig]->ROI[i]->deltax, DIGIT[_dig]->ROI[i]->deltay, 3); + } return true; } +digit* ClassFlowDigit::FindDIGIT(string _name_number) +{ + digit *_ret = NULL; + + for (int i = 0; i < DIGIT.size(); ++i) + { + if (DIGIT[i]->name == _name_number) + return DIGIT[i]; + } + + return NULL; +} + + +digit* ClassFlowDigit::GetDIGIT(string _name, bool _create = true) +{ + string _digit, _roi; + int _pospunkt = _name.find_first_of("."); +// printf("Name: %s, Pospunkt: %d\n", _name.c_str(), _pospunkt); + if (_pospunkt > -1) + { + _digit = _name.substr(0, _pospunkt); + _roi = _name.substr(_pospunkt+1, _name.length() - _pospunkt - 1); + } + else + { + _digit = "default"; + _roi = _name; + } + + digit *_ret = NULL; + + for (int i = 0; i < DIGIT.size(); ++i) + { + if (DIGIT[i]->name == _digit) + _ret = DIGIT[i]; + } + + if (!_create) // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück + return _ret; + + if (_ret == NULL) + { + _ret = new digit; + _ret->name = _digit; + DIGIT.push_back(_ret); + } + + roi* neuroi = new roi; + neuroi->name = _roi; + _ret->ROI.push_back(neuroi); + + printf("GetDIGIT - digit %s - roi %s\n", _digit.c_str(), _roi.c_str()); + + return _ret; +} + + string ClassFlowDigit::getHTMLSingleStep(string host) { @@ -216,17 +267,32 @@ bool ClassFlowDigit::doAlignAndCut(string time) CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage(); - for (int i = 0; i < ROI.size(); ++i) + for (int _dig = 0; _dig < DIGIT.size(); ++_dig) { - printf("DigitalDigit %d - Align&Cut\n", i); - - caic->CutAndSave(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, ROI[i]->image_org); - if (SaveAllFiles) ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".jpg")); + printf("DIGIT[_dig]->ROI.size() %d\n", DIGIT[_dig]->ROI.size()); + for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i) + { + printf("DigitalDigit %d - Align&Cut\n", i); + + caic->CutAndSave(DIGIT[_dig]->ROI[i]->posx, DIGIT[_dig]->ROI[i]->posy, DIGIT[_dig]->ROI[i]->deltax, DIGIT[_dig]->ROI[i]->deltay, DIGIT[_dig]->ROI[i]->image_org); + if (SaveAllFiles) + { + if (DIGIT[_dig]->name == "default") + DIGIT[_dig]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->ROI[i]->name + ".jpg")); + else + DIGIT[_dig]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".jpg")); + } - ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image); - if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp")); + DIGIT[_dig]->ROI[i]->image_org->Resize(modelxsize, modelysize, DIGIT[_dig]->ROI[i]->image); + if (SaveAllFiles) + { + if (DIGIT[_dig]->name == "default") + DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->ROI[i]->name + ".bmp")); + else + DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".bmp")); + } + } } - return true; } @@ -241,26 +307,32 @@ bool ClassFlowDigit::doNeuralNetwork(string time) CTfLiteClass *tflite = new CTfLiteClass; string zwcnn = FormatFileName("/sdcard" + cnnmodelfile); printf(zwcnn.c_str());printf("\n"); - tflite->LoadModel(zwcnn); + if (!tflite->LoadModel(zwcnn)) { + printf("Can't read model file /sdcard%s\n", cnnmodelfile.c_str()); + delete tflite; + return false; + } + tflite->MakeAllocate(); #endif - for (int i = 0; i < ROI.size(); ++i) - { - printf("DigitalDigit %d - TfLite\n", i); - - ROI[i]->resultklasse = 0; -#ifndef OHNETFLITE - ROI[i]->resultklasse = tflite->GetClassFromImageBasis(ROI[i]->image); - -#endif - printf("Result Digit%i: %d\n", i, ROI[i]->resultklasse); - - if (isLogImage) + for (int _dig = 0; _dig < DIGIT.size(); ++_dig) + for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i) { - LogImage(logPath, ROI[i]->name, NULL, &ROI[i]->resultklasse, time, ROI[i]->image_org); + printf("DigitalDigit %d - TfLite\n", i); + + DIGIT[_dig]->ROI[i]->resultklasse = 0; + #ifndef OHNETFLITE + DIGIT[_dig]->ROI[i]->resultklasse = tflite->GetClassFromImageBasis(DIGIT[_dig]->ROI[i]->image); + + #endif + printf("Result Digit%i: %d\n", i, DIGIT[_dig]->ROI[i]->resultklasse); + + if (isLogImage) + { + LogImage(logPath, DIGIT[_dig]->ROI[i]->name, NULL, &DIGIT[_dig]->ROI[i]->resultklasse, time, DIGIT[_dig]->ROI[i]->image_org); + } } - } #ifndef OHNETFLITE delete tflite; #endif @@ -269,25 +341,82 @@ bool ClassFlowDigit::doNeuralNetwork(string time) void ClassFlowDigit::DrawROI(CImageBasis *_zw) { - for (int i = 0; i < ROI.size(); ++i) - _zw->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, 0, 0, 255, 2); + for (int _dig = 0; _dig < DIGIT.size(); ++_dig) + for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i) + _zw->drawRect(DIGIT[_dig]->ROI[i]->posx, DIGIT[_dig]->ROI[i]->posy, DIGIT[_dig]->ROI[i]->deltax, DIGIT[_dig]->ROI[i]->deltay, 0, 0, (255 - _dig*100), 2); } std::vector ClassFlowDigit::GetHTMLInfo() { std::vector result; - for (int i = 0; i < ROI.size(); ++i) - { - HTMLInfo *zw = new HTMLInfo; - zw->filename = ROI[i]->name + ".bmp"; - zw->filename_org = ROI[i]->name + ".jpg"; - zw->val = ROI[i]->resultklasse; - zw->image = ROI[i]->image; - zw->image_org = ROI[i]->image_org; - result.push_back(zw); - } + for (int _dig = 0; _dig < DIGIT.size(); ++_dig) + for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i) + { + if (DIGIT[_dig]->name == "default") + DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->ROI[i]->name + ".bmp")); + else + DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".bmp")); + + + HTMLInfo *zw = new HTMLInfo; + if (DIGIT[_dig]->name == "default") + { + zw->filename = DIGIT[_dig]->ROI[i]->name + ".bmp"; + zw->filename_org = DIGIT[_dig]->ROI[i]->name + ".jpg"; + } + else + { + zw->filename = DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".bmp"; + zw->filename_org = DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".jpg"; + } + + zw->val = DIGIT[_dig]->ROI[i]->resultklasse; + zw->image = DIGIT[_dig]->ROI[i]->image; + zw->image_org = DIGIT[_dig]->ROI[i]->image_org; + result.push_back(zw); + } return result; } +int ClassFlowDigit::getAnzahlDIGIT() +{ + return DIGIT.size(); +} + +string ClassFlowDigit::getNameDIGIT(int _digit) +{ + if (_digit < DIGIT.size()) + return DIGIT[_digit]->name; + + return "DIGIT DOES NOT EXIST"; +} + +digit* ClassFlowDigit::GetDIGIT(int _digit) +{ + if (_digit < DIGIT.size()) + return DIGIT[_digit]; + + return NULL; +} + +void ClassFlowDigit::UpdateNameNumbers(std::vector *_name_numbers) +{ + for (int _dig = 0; _dig < DIGIT.size(); _dig++) + { + std::string _name = DIGIT[_dig]->name; + bool found = false; + for (int i = 0; i < (*_name_numbers).size(); ++i) + { + if ((*_name_numbers)[i] == _name) + found = true; + } + if (!found) + (*_name_numbers).push_back(_name); + } +} + + + + diff --git a/code/components/jomjol_flowcontroll/ClassFlowDigit.h b/code/components/jomjol_flowcontroll/ClassFlowDigit.h index 3af92f85..f6d98616 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowDigit.h +++ b/code/components/jomjol_flowcontroll/ClassFlowDigit.h @@ -5,6 +5,8 @@ #include + + struct roi { int posx, posy, deltax, deltay; int resultklasse; @@ -13,11 +15,17 @@ struct roi { roi* next; }; +struct digit { + string name; + std::vector ROI; +}; + class ClassFlowDigit : public ClassFlowImage { protected: - std::vector ROI; +// std::vector ROI; + std::vector DIGIT; string cnnmodelfile; int modelxsize, modelysize; bool SaveAllFiles; @@ -31,6 +39,7 @@ protected: bool doNeuralNetwork(string time); bool doAlignAndCut(string time); + void SetInitialParameter(void); public: @@ -40,9 +49,18 @@ public: bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string getHTMLSingleStep(string host); - string getReadout(); + string getReadout(int _digit); std::vector GetHTMLInfo(); + int getAnzahlDIGIT(); + digit* GetDIGIT(int _digit); + digit* GetDIGIT(string _name, bool _create); + digit* FindDIGIT(string _name_number); + + string getNameDIGIT(int _digit); + + void UpdateNameNumbers(std::vector *_name_numbers); + void DrawROI(CImageBasis *_zw); string name(){return "ClassFlowDigit";}; diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp index 1d0e4c1b..4748b0d7 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp @@ -1,6 +1,8 @@ +#include #include "ClassFlowMQTT.h" #include "Helper.h" +#include "time_sntp.h" #include "interface_mqtt.h" #include "ClassFlowPostProcessing.h" @@ -13,6 +15,11 @@ void ClassFlowMQTT::SetInitialParameter(void) topicError = ""; topicRate = ""; topicTimeStamp = ""; + maintopic = ""; + mainerrortopic = ""; + + topicUptime = ""; + topicFreeMem = ""; clientname = "watermeter"; OldValue = ""; flowpostprocessing = NULL; @@ -21,6 +28,9 @@ void ClassFlowMQTT::SetInitialParameter(void) previousElement = NULL; ListFlowControll = NULL; disabled = false; + MQTTenable = false; + + } @@ -88,33 +98,24 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph) { this->uri = zerlegt[1]; } - if ((toUpper(zerlegt[0]) == "TOPIC") && (zerlegt.size() > 1)) - { - this->topic = zerlegt[1]; - } - if ((toUpper(zerlegt[0]) == "TOPICERROR") && (zerlegt.size() > 1)) - { - this->topicError = zerlegt[1]; - } - if ((toUpper(zerlegt[0]) == "TOPICRATE") && (zerlegt.size() > 1)) - { - this->topicRate = zerlegt[1]; - } - if ((toUpper(zerlegt[0]) == "TOPICTIMESTAMP") && (zerlegt.size() > 1)) - { - this->topicTimeStamp = zerlegt[1]; - } if ((toUpper(zerlegt[0]) == "CLIENTID") && (zerlegt.size() > 1)) { this->clientname = zerlegt[1]; } + if (((toUpper(zerlegt[0]) == "TOPIC") || (toUpper(zerlegt[0]) == "MAINTOPIC")) && (zerlegt.size() > 1)) + { + maintopic = zerlegt[1]; + } } - if ((uri.length() > 0) && (topic.length() > 0)) + if (!MQTTisConnected() && (uri.length() > 0) && (maintopic.length() > 0)) { - MQTTInit(uri, clientname, user, password, topicError, 60); + mainerrortopic = maintopic + "/connection"; + MQTTInit(uri, clientname, user, password, mainerrortopic, 60); + MQTTPublish(mainerrortopic, "connected"); + MQTTenable = true; } return true; @@ -123,18 +124,66 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph) bool ClassFlowMQTT::doFlow(string zwtime) { + if (!MQTTenable) + return true; + std::string result; std::string resulterror = ""; std::string resultrate = ""; std::string resulttimestamp = ""; string zw = ""; + string namenumber = ""; + + MQTTPublish(mainerrortopic, "connected"); + zw = maintopic + "/" + "uptime"; + char uptimeStr[11]; + sprintf(uptimeStr, "%ld", (long)getUpTime()); + MQTTPublish(zw, uptimeStr); + + zw = maintopic + "/" + "freeMem"; + char freeheapmem[11]; + sprintf(freeheapmem, "%zu", esp_get_free_heap_size()); + MQTTPublish(zw, freeheapmem); + if (flowpostprocessing) { - result = flowpostprocessing->getReadoutParam(false, true); - resulterror = flowpostprocessing->getReadoutError(); - resultrate = flowpostprocessing->getReadoutRate(); - resulttimestamp = flowpostprocessing->getReadoutTimeStamp(); + std::vector NUMBERS = flowpostprocessing->GetNumbers(); + + for (int i = 0; i < NUMBERS.size(); ++i) + { + result = NUMBERS[i]->ReturnValueNoError; + resulterror = NUMBERS[i]->ErrorMessageText; + resultrate = std::to_string(NUMBERS[i]->FlowRateAct); + resulttimestamp = NUMBERS[i]->timeStamp; + + namenumber = NUMBERS[i]->name; + if (namenumber == "default") + namenumber = maintopic + "/"; + else + namenumber = maintopic + "/" + namenumber + "/"; + + zw = namenumber + "value"; + MQTTPublish(zw, result); + + zw = namenumber + "error"; + MQTTPublish(zw, resulterror, 1); + + zw = namenumber + "rate"; + MQTTPublish(zw, resultrate); + + zw = namenumber + "timestamp"; + MQTTPublish(zw, resulttimestamp); + + + std::string json="{\"value\":"+result; + json += ",\"error\":\""+resulterror; + json += "\",\"rate\":"+resultrate; + json += ",\"timestamp\":\""+resulttimestamp+"\"}"; + + zw = namenumber + "json"; + MQTTPublish(zw, json); + } } else { @@ -149,26 +198,9 @@ bool ClassFlowMQTT::doFlow(string zwtime) result = result + "\t" + zw; } } + MQTTPublish(topic, result); } - MQTTPublish(topic, result); - - if (topicError.length() > 0) { - if (resulterror.length() == 0) - { - resulterror = " "; - } - MQTTPublish(topicError, resulterror, 1); - } - - if (topicRate.length() > 0) { - MQTTPublish(topicRate, resultrate); - } - - if (topicTimeStamp.length() > 0) { - MQTTPublish(topicTimeStamp, resulttimestamp); - } - OldValue = result; return true; diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h index 99035659..c79e9b13 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h @@ -9,10 +9,13 @@ class ClassFlowMQTT : public ClassFlow { protected: - std::string uri, topic, topicError, clientname, topicRate, topicTimeStamp; + std::string uri, topic, topicError, clientname, topicRate, topicTimeStamp, topicUptime, topicFreeMem; std::string OldValue; ClassFlowPostProcessing* flowpostprocessing; - std::string user, password; + std::string user, password; + bool MQTTenable; + + std::string maintopic, mainerrortopic; void SetInitialParameter(void); public: diff --git a/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp b/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp index e9d54cb0..4cb80201 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp @@ -1,8 +1,6 @@ #include "ClassFlowPostProcessing.h" #include "Helper.h" -#include "ClassFlowAnalog.h" -#include "ClassFlowDigit.h" #include "ClassFlowMakeImage.h" #include "ClassLogFile.h" @@ -18,130 +16,205 @@ #define PREVALUE_TIME_FORMAT_INPUT "%d-%d-%dT%d:%d:%d" -string ClassFlowPostProcessing::GetPreValue() +string ClassFlowPostProcessing::GetPreValue(std::string _number) { std::string result; - bool isAnalog = false; - bool isDigit = false; + int index = -1; - int AnzahlAnalog = 0; - result = RundeOutput(PreValue, -DecimalShift); + if (_number == "") + _number = "default"; - for (int i = 0; i < ListFlowControll->size(); ++i) - { - if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0) - { - isAnalog = true; - AnzahlAnalog = ((ClassFlowAnalog*)(*ListFlowControll)[i])->AnzahlROIs(); - } - if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0) - { - isDigit = true; - } - } + for (int i = 0; i < NUMBERS.size(); ++i) + if (NUMBERS[i]->name == _number) + index = i; - if (isDigit && isAnalog) - result = RundeOutput(PreValue, AnzahlAnalog - DecimalShift); +// result = RundeOutput(NUMBERS[index]->PreValue, -NUMBERS[index]->DecimalShift); + result = RundeOutput(NUMBERS[index]->PreValue, NUMBERS[index]->Nachkomma); + +// if (NUMBERS[index]->digit_roi && NUMBERS[index]->analog_roi) +// result = RundeOutput(NUMBERS[index]->PreValue, NUMBERS[index]->AnzahlAnalog - NUMBERS[index]->DecimalShift); return result; } +void ClassFlowPostProcessing::SetPreValue(float zw, string _numbers) +{ + for (int j = 0; j < NUMBERS.size(); ++j) + { + if (NUMBERS[j]->name == _numbers) + NUMBERS[j]->PreValue = zw; + } + UpdatePreValueINI = true; + SavePreValue(); +} + + bool ClassFlowPostProcessing::LoadPreValue(void) { + std::vector zerlegt; FILE* pFile; char zw[1024]; - string zwtime, zwvalue; + string zwtime, zwvalue, name; + bool _done = false; + + UpdatePreValueINI = false; // Konvertierung ins neue Format + pFile = fopen(FilePreValue.c_str(), "r"); if (pFile == NULL) return false; fgets(zw, 1024, pFile); - printf("%s", zw); + printf("Read Zeile Prevalue.ini: %s", zw); zwtime = trim(std::string(zw)); - - fgets(zw, 1024, pFile); - fclose(pFile); - printf("%s", zw); - zwvalue = trim(std::string(zw)); - PreValue = stof(zwvalue.c_str()); - - time_t tStart; - int yy, month, dd, hh, mm, ss; - struct tm whenStart; - - sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss); - whenStart.tm_year = yy - 1900; - whenStart.tm_mon = month - 1; - whenStart.tm_mday = dd; - whenStart.tm_hour = hh; - whenStart.tm_min = mm; - whenStart.tm_sec = ss; - whenStart.tm_isdst = -1; - - lastvalue = mktime(&whenStart); - - time(&tStart); - localtime(&tStart); - double difference = difftime(tStart, lastvalue); - difference /= 60; - if (difference > PreValueAgeStartup) + if (zwtime.length() == 0) return false; - Value = PreValue; - ReturnValue = to_string(Value); - ReturnValueNoError = ReturnValue; - - bool isAnalog = false; - bool isDigit = false; - int AnzahlAnalog = 0; - - for (int i = 0; i < ListFlowControll->size(); ++i) + zerlegt = HelperZerlegeZeile(zwtime, "\t"); + if (zerlegt.size() > 1) // neues Format { - if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0) - isAnalog = true; - if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0) - isDigit = true; - } + while ((zerlegt.size() > 1) && !_done) + { + name = trim(zerlegt[0]); + zwtime = trim(zerlegt[1]); + zwvalue = trim(zerlegt[2]); - if (isDigit || isAnalog) + for (int j = 0; j < NUMBERS.size(); ++j) + { + if (NUMBERS[j]->name == name) + { + NUMBERS[j]->PreValue = stof(zwvalue.c_str()); + NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma); + + time_t tStart; + int yy, month, dd, hh, mm, ss; + struct tm whenStart; + + sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss); + whenStart.tm_year = yy - 1900; + whenStart.tm_mon = month - 1; + whenStart.tm_mday = dd; + whenStart.tm_hour = hh; + whenStart.tm_min = mm; + whenStart.tm_sec = ss; + whenStart.tm_isdst = -1; + + NUMBERS[j]->lastvalue = mktime(&whenStart); + + time(&tStart); + localtime(&tStart); + double difference = difftime(tStart, NUMBERS[j]->lastvalue); + difference /= 60; + if (difference > PreValueAgeStartup) + { + NUMBERS[j]->PreValueOkay = false; + } + else + { + NUMBERS[j]->PreValueOkay = true; + NUMBERS[j]->Value = NUMBERS[j]->PreValue; + NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->Value); + NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue; + + if (NUMBERS[j]->digit_roi || NUMBERS[j]->analog_roi) + { + NUMBERS[j]->ReturnValue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift); + NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue; + } + } + + } + } + + if (!fgets(zw, 1024, pFile)) + _done = true; + else + { + printf("Read Zeile Prevalue.ini: %s", zw); + zerlegt = HelperZerlegeZeile(trim(std::string(zw)), "\t"); + if (zerlegt.size() > 1) + { + name = trim(zerlegt[0]); + zwtime = trim(zerlegt[1]); + zwvalue = trim(zerlegt[2]); + } + } + } + fclose(pFile); + } + else // altes Format { - ReturnValue = RundeOutput(Value, AnzahlAnalog - DecimalShift); - ReturnValueNoError = ReturnValue; - } - + fgets(zw, 1024, pFile); + fclose(pFile); + printf("%s", zw); + zwvalue = trim(std::string(zw)); + NUMBERS[0]->PreValue = stof(zwvalue.c_str()); + + time_t tStart; + int yy, month, dd, hh, mm, ss; + struct tm whenStart; + + sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss); + whenStart.tm_year = yy - 1900; + whenStart.tm_mon = month - 1; + whenStart.tm_mday = dd; + whenStart.tm_hour = hh; + whenStart.tm_min = mm; + whenStart.tm_sec = ss; + whenStart.tm_isdst = -1; + + printf("TIME: %d, %d, %d, %d, %d, %d\n", whenStart.tm_year, whenStart.tm_mon, whenStart.tm_wday, whenStart.tm_hour, whenStart.tm_min, whenStart.tm_sec); + + NUMBERS[0]->lastvalue = mktime(&whenStart); + + time(&tStart); + localtime(&tStart); + double difference = difftime(tStart, NUMBERS[0]->lastvalue); + difference /= 60; + if (difference > PreValueAgeStartup) + return false; + + NUMBERS[0]->Value = NUMBERS[0]->PreValue; + NUMBERS[0]->ReturnValue = to_string(NUMBERS[0]->Value); + NUMBERS[0]->ReturnValueNoError = NUMBERS[0]->ReturnValue; + + if (NUMBERS[0]->digit_roi || NUMBERS[0]->analog_roi) + { + NUMBERS[0]->ReturnValue = RundeOutput(NUMBERS[0]->Value, NUMBERS[0]->AnzahlAnalog - NUMBERS[0]->DecimalShift); + NUMBERS[0]->ReturnValueNoError = NUMBERS[0]->ReturnValue; + } + + UpdatePreValueINI = true; // Konvertierung ins neue Format + SavePreValue(); + } + return true; } -void ClassFlowPostProcessing::SavePreValue(float value, string zwtime) +void ClassFlowPostProcessing::SavePreValue() { FILE* pFile; + string _zw; + + if (!UpdatePreValueINI) // PreValues unverändert --> File muss nicht neu geschrieben werden + return; pFile = fopen(FilePreValue.c_str(), "w"); - if (strlen(zwtime.c_str()) == 0) + for (int j = 0; j < NUMBERS.size(); ++j) { - time_t rawtime; - struct tm* timeinfo; char buffer[80]; - - time(&rawtime); - timeinfo = localtime(&rawtime); - + struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue); strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo); - timeStamp = std::string(buffer); - } - else - { - timeStamp = zwtime; + NUMBERS[j]->timeStamp = std::string(buffer); + + _zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + to_string(NUMBERS[j]->PreValue) + "\n"; + printf("Write PreValue Zeile: %s\n", _zw.c_str()); + + fputs(_zw.c_str(), pFile); } - PreValue = value; - - fputs(timeStamp.c_str(), pFile); - fputs("\n", pFile); - fputs(to_string(value).c_str(), pFile); - fputs("\n", pFile); + UpdatePreValueINI = false; fclose(pFile); } @@ -149,22 +222,19 @@ void ClassFlowPostProcessing::SavePreValue(float value, string zwtime) ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector* lfc) { - FlowRateAct = 0; +// FlowRateAct = 0; PreValueUse = false; PreValueAgeStartup = 30; - AllowNegativeRates = false; - MaxRateValue = 0.1; ErrorMessage = false; ListFlowControll = NULL; - PreValueOkay = false; - useMaxRateValue = false; - checkDigitIncreaseConsistency = false; - DecimalShift = 0; - ErrorMessageText = ""; - timeStamp = ""; +// PreValueOkay = false; +// DecimalShift = 0; +// ErrorMessageText = ""; +// timeStamp = ""; FilePreValue = FormatFileName("/sdcard/config/prevalue.ini"); ListFlowControll = lfc; flowMakeImage = NULL; + UpdatePreValueINI = false; for (int i = 0; i < ListFlowControll->size(); ++i) { @@ -175,10 +245,82 @@ ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector* lfc) } } +void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _value) +{ + string _digit, _decpos; + int _pospunkt = _decsep.find_first_of("."); +// printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt); + if (_pospunkt > -1) + _digit = _decsep.substr(0, _pospunkt); + else + _digit = "default"; + + for (int j = 0; j < NUMBERS.size(); ++j) + { + int _zwdc = 0; + + try + { + _zwdc = stoi(_value); + } + catch(const std::exception& e) + { + printf("ERROR - Decimalshift is not a number: %s\n", _value.c_str()); + } + + if (_digit == "default") // erstmal auf default setzen (falls sonst nichts gesetzt) + NUMBERS[j]->DecimalShift = _zwdc; + + if (NUMBERS[j]->name == _digit) + NUMBERS[j]->DecimalShift = _zwdc; + + NUMBERS[j]->Nachkomma = NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift; + } +} + +void ClassFlowPostProcessing::handleMaxRateValue(string _decsep, string _value) +{ + string _digit, _decpos; + int _pospunkt = _decsep.find_first_of("."); +// printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt); + if (_pospunkt > -1) + _digit = _decsep.substr(0, _pospunkt); + else + _digit = "default"; + + for (int j = 0; j < NUMBERS.size(); ++j) + { + float _zwdc = 1; + + try + { + _zwdc = stof(_value); + } + catch(const std::exception& e) + { + printf("ERROR - MaxRateValue is not a number: %s\n", _value.c_str()); + } + + + if (_digit == "default") // erstmal auf default setzen (falls sonst nichts gesetzt) + { + NUMBERS[j]->useMaxRateValue = true; + NUMBERS[j]->MaxRateValue = _zwdc; + } + + if (NUMBERS[j]->name == _digit) + { + NUMBERS[j]->useMaxRateValue = true; + NUMBERS[j]->MaxRateValue = _zwdc; + } + } +} + bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph) { std::vector zerlegt; + int _n; aktparamgraph = trim(aktparamgraph); @@ -190,53 +332,148 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph) if (aktparamgraph.compare("[PostProcessing]") != 0) // Paragraph passt nich zu MakeImage return false; + InitNUMBERS(); + + while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) { zerlegt = this->ZerlegeZeile(aktparamgraph); - if ((toUpper(zerlegt[0]) == "DECIMALSHIFT") && (zerlegt.size() > 1)) + std::string _param = GetParameterName(zerlegt[0]); + + if ((toUpper(_param) == "DECIMALSHIFT") && (zerlegt.size() > 1)) { - DecimalShift = stoi(zerlegt[1]); + handleDecimalSeparator(zerlegt[0], zerlegt[1]); + } + if ((toUpper(_param) == "MAXRATEVALUE") && (zerlegt.size() > 1)) + { + handleMaxRateValue(zerlegt[0], zerlegt[1]); } - if ((toUpper(zerlegt[0]) == "PREVALUEUSE") && (zerlegt.size() > 1)) + if ((toUpper(_param) == "PREVALUEUSE") && (zerlegt.size() > 1)) { if (toUpper(zerlegt[1]) == "TRUE") { PreValueUse = true; } } - if ((toUpper(zerlegt[0]) == "CHECKDIGITINCREASECONSISTENCY") && (zerlegt.size() > 1)) + if ((toUpper(_param) == "CHECKDIGITINCREASECONSISTENCY") && (zerlegt.size() > 1)) { if (toUpper(zerlegt[1]) == "TRUE") - checkDigitIncreaseConsistency = true; + for (_n = 0; _n < NUMBERS.size(); ++_n) + NUMBERS[_n]->checkDigitIncreaseConsistency = true; } - if ((toUpper(zerlegt[0]) == "ALLOWNEGATIVERATES") && (zerlegt.size() > 1)) + if ((toUpper(_param) == "ALLOWNEGATIVERATES") && (zerlegt.size() > 1)) { if (toUpper(zerlegt[1]) == "TRUE") - AllowNegativeRates = true; + for (_n = 0; _n < NUMBERS.size(); ++_n) + NUMBERS[_n]->AllowNegativeRates = true; } - if ((toUpper(zerlegt[0]) == "ERRORMESSAGE") && (zerlegt.size() > 1)) + if ((toUpper(_param) == "ERRORMESSAGE") && (zerlegt.size() > 1)) { if (toUpper(zerlegt[1]) == "TRUE") ErrorMessage = true; } - if ((toUpper(zerlegt[0]) == "PREVALUEAGESTARTUP") && (zerlegt.size() > 1)) + if ((toUpper(_param) == "PREVALUEAGESTARTUP") && (zerlegt.size() > 1)) { PreValueAgeStartup = std::stoi(zerlegt[1]); } - if ((toUpper(zerlegt[0]) == "MAXRATEVALUE") && (zerlegt.size() > 1)) - { - useMaxRateValue = true; - MaxRateValue = std::stof(zerlegt[1]); - } } if (PreValueUse) { - PreValueOkay = LoadPreValue(); + LoadPreValue(); } + return true; } +void ClassFlowPostProcessing::InitNUMBERS() +{ +// ClassFlowDigit* _cdigit = NULL; +// ClassFlowAnalog* _canalog = NULL; + int anzDIGIT = 0; + int anzANALOG = 0; + std::vector name_numbers; + + flowAnalog = NULL; + flowDigit = NULL; + + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0) + { + flowDigit = (ClassFlowDigit*) (*ListFlowControll)[i]; + anzDIGIT = flowDigit->getAnzahlDIGIT(); + } + if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0) + { + flowAnalog = (ClassFlowAnalog*)(*ListFlowControll)[i]; + anzANALOG = flowAnalog->getAnzahlANALOG(); + } + } + + if (flowDigit) + flowDigit->UpdateNameNumbers(&name_numbers); + if (flowAnalog) + flowAnalog->UpdateNameNumbers(&name_numbers); + + printf("Anzahl NUMBERS: %d - DIGITS: %d, ANALOG: %d\n", name_numbers.size(), anzDIGIT, anzANALOG); + + for (int _num = 0; _num < name_numbers.size(); ++_num) + { + NumberPost *_number = new NumberPost; + + _number->name = name_numbers[_num]; + + _number->digit_roi = NULL; + if (flowDigit) + _number->digit_roi = flowDigit->FindDIGIT(name_numbers[_num]); + + if (_number->digit_roi) + _number->AnzahlDigital = _number->digit_roi->ROI.size(); + else + _number->AnzahlDigital = 0; + + _number->analog_roi = NULL; + if (flowAnalog) + _number->analog_roi = flowAnalog->FindANALOG(name_numbers[_num]); + + + if (_number->analog_roi) + _number->AnzahlAnalog = _number->analog_roi->ROI.size(); + else + _number->AnzahlAnalog = 0; + + _number->ReturnRawValue = ""; // Rohwert (mit N & führenden 0) + _number->ReturnValue = ""; // korrigierter Rückgabewert, ggf. mit Fehlermeldung + _number->ReturnValueNoError = ""; // korrigierter Rückgabewert ohne Fehlermeldung + _number->ErrorMessageText = ""; // Fehlermeldung bei Consistency Check + _number->ReturnPreValue = ""; + _number->PreValueOkay = false; + _number->AllowNegativeRates = false; + _number->MaxRateValue = 0.1; + _number->useMaxRateValue = false; + _number->checkDigitIncreaseConsistency = false; + _number->PreValueOkay = false; + _number->useMaxRateValue = false; + _number->DecimalShift = 0; + + _number->FlowRateAct = 0; // m3 / min + _number->PreValue = 0; // letzter Wert, der gut ausgelesen wurde + _number->Value = 0; // letzer ausgelesener Wert, inkl. Korrekturen + _number->ReturnRawValue = ""; // Rohwert (mit N & führenden 0) + _number->ReturnValue = ""; // korrigierter Rückgabewert, ggf. mit Fehlermeldung + _number->ReturnValueNoError = ""; // korrigierter Rückgabewert ohne Fehlermeldung + _number->ErrorMessageText = ""; // Fehlermeldung bei Consistency Check + + _number->Nachkomma = _number->AnzahlAnalog; + + NUMBERS.push_back(_number); + } + + for (int i = 0; i < NUMBERS.size(); ++i) + printf("Number %s, Anz DIG: %d, Anz ANA %d\n", NUMBERS[i]->name.c_str(), NUMBERS[i]->AnzahlDigital, NUMBERS[i]->AnzahlAnalog); +} + string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){ if (_decShift == 0){ @@ -285,173 +522,127 @@ bool ClassFlowPostProcessing::doFlow(string zwtime) string digit = ""; string analog = ""; string zwvalue; - bool isdigit = false; - bool isanalog = false; - int AnzahlAnalog = 0; string zw; time_t imagetime = 0; string rohwert; - ErrorMessageText = ""; - - - for (int i = 0; i < ListFlowControll->size(); ++i) - { - if (((*ListFlowControll)[i])->name().compare("ClassFlowMakeImage") == 0) - { - imagetime = ((ClassFlowMakeImage*)(*ListFlowControll)[i])->getTimeImageTaken(); - } - if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0) - { - isdigit = true; - digit = (*ListFlowControll)[i]->getReadout(); - } - if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0) - { - isanalog = true; - analog = (*ListFlowControll)[i]->getReadout(); - AnzahlAnalog = ((ClassFlowAnalog*)(*ListFlowControll)[i])->AnzahlROIs(); - } - } +// ErrorMessageText = ""; + imagetime = flowMakeImage->getTimeImageTaken(); if (imagetime == 0) time(&imagetime); struct tm* timeinfo; timeinfo = localtime(&imagetime); - char strftime_buf[64]; strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%dT%H:%M:%S", timeinfo); zwtime = std::string(strftime_buf); + printf("Anzahl NUMBERS: %d\n", NUMBERS.size()); - // // TESTING ONLY//////////////////// - // isdigit = true; digit = "12N"; - // isanalog = true; analog = "456"; - - ReturnRawValue = ""; - - if (isdigit) - ReturnRawValue = digit; - if (isdigit && isanalog) - ReturnRawValue = ReturnRawValue + "."; - if (isanalog) - ReturnRawValue = ReturnRawValue + analog; - - - if (!isdigit) + for (int j = 0; j < NUMBERS.size(); ++j) { - AnzahlAnalog = 0; - } + NUMBERS[j]->ReturnRawValue = ""; + NUMBERS[j]->ErrorMessageText = ""; - ReturnRawValue = ShiftDecimal(ReturnRawValue, DecimalShift); + if (NUMBERS[j]->digit_roi) + NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j); + if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) + NUMBERS[j]->ReturnRawValue = NUMBERS[j]->ReturnRawValue + "."; + if (NUMBERS[j]->analog_roi) + NUMBERS[j]->ReturnRawValue = NUMBERS[j]->ReturnRawValue + flowAnalog->getReadout(j); - rohwert = ReturnRawValue; + NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift); - if (!PreValueUse || !PreValueOkay) - { - ReturnValue = ReturnRawValue; - ReturnValueNoError = ReturnRawValue; + rohwert = NUMBERS[j]->ReturnRawValue; - if ((findDelimiterPos(ReturnValue, "N") == std::string::npos) && (ReturnValue.length() > 0)) + if (!PreValueUse || !NUMBERS[j]->PreValueOkay) { - while ((ReturnValue.length() > 1) && (ReturnValue[0] == '0')) - { - ReturnValue.erase(0, 1); - } - Value = std::stof(ReturnValue); - ReturnValueNoError = ReturnValue; + NUMBERS[j]->ReturnValue = NUMBERS[j]->ReturnRawValue; + NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnRawValue; - PreValueOkay = true; - PreValue = Value; - if (flowMakeImage) + if ((findDelimiterPos(NUMBERS[j]->ReturnValue, "N") == std::string::npos) && (NUMBERS[j]->ReturnValue.length() > 0)) { - lastvalue = flowMakeImage->getTimeImageTaken(); - zwtime = ConvertTimeToString(lastvalue, PREVALUE_TIME_FORMAT_OUTPUT); - } - else - { - time(&lastvalue); - localtime(&lastvalue); - } + while ((NUMBERS[j]->ReturnValue.length() > 1) && (NUMBERS[j]->ReturnValue[0] == '0')) + { + NUMBERS[j]->ReturnValue.erase(0, 1); + } + NUMBERS[j]->Value = std::stof(NUMBERS[j]->ReturnValue); + NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue; - SavePreValue(Value, zwtime); + NUMBERS[j]->PreValueOkay = true; + NUMBERS[j]->PreValue = NUMBERS[j]->Value; + NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma); + NUMBERS[j]->lastvalue = flowMakeImage->getTimeImageTaken(); + zwtime = ConvertTimeToString(NUMBERS[j]->lastvalue, PREVALUE_TIME_FORMAT_OUTPUT); + + UpdatePreValueINI = true; + SavePreValue(); + } + } + else + { + zw = ErsetzteN(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->PreValue); + + NUMBERS[j]->Value = std::stof(zw); + if (NUMBERS[j]->checkDigitIncreaseConsistency) + { + NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue); + } + + zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift); + + if ((!NUMBERS[j]->AllowNegativeRates) && (NUMBERS[j]->Value < NUMBERS[j]->PreValue)) + { + NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + std::to_string(NUMBERS[j]->Value) + " "; + NUMBERS[j]->Value = NUMBERS[j]->PreValue; + zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift); + } + + if (NUMBERS[j]->useMaxRateValue && (abs(NUMBERS[j]->Value - NUMBERS[j]->PreValue) > NUMBERS[j]->MaxRateValue)) + { + NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Rate too high - Read: " + RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma) + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma); + NUMBERS[j]->Value = NUMBERS[j]->PreValue; + zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma); + } + + NUMBERS[j]->ReturnValueNoError = zwvalue; + NUMBERS[j]->ReturnValue = zwvalue; + if (NUMBERS[j]->ErrorMessage && (NUMBERS[j]->ErrorMessageText.length() > 0)) + NUMBERS[j]->ReturnValue = NUMBERS[j]->ReturnValue + "\t" + NUMBERS[j]->ErrorMessageText; + + + double difference = difftime(imagetime, NUMBERS[j]->lastvalue); // in Sekunden + difference /= 60; // in Minuten + NUMBERS[j]->FlowRateAct = (NUMBERS[j]->Value - NUMBERS[j]->PreValue) / difference; + NUMBERS[j]->lastvalue = imagetime; + + if (NUMBERS[j]->ErrorMessageText.length() == 0) + { + NUMBERS[j]->PreValue = NUMBERS[j]->Value; + NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma); + NUMBERS[j]->ErrorMessageText = "no error"; + UpdatePreValueINI = true; + } } - return true; } - - zw = ErsetzteN(ReturnRawValue); - - Value = std::stof(zw); - if (checkDigitIncreaseConsistency) - { - Value = checkDigitConsistency(Value, DecimalShift, isanalog); - } - - zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift); - - if ((!AllowNegativeRates) && (Value < PreValue)) - { - ErrorMessageText = ErrorMessageText + "Negative Rate - Returned old value - read value: " + zwvalue + " - raw value: " + ReturnRawValue + " - checked value: " + std::to_string(Value) + " "; - Value = PreValue; - zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift); - } - - if (useMaxRateValue && (abs(Value - PreValue) > MaxRateValue)) - { - ErrorMessageText = ErrorMessageText + "Rate too high - Returned old value - read value: " + zwvalue + " - checked value: " + RundeOutput(Value, AnzahlAnalog - DecimalShift) + " "; - Value = PreValue; - zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift); - } - - - ReturnValueNoError = zwvalue; - ReturnValue = zwvalue; - if (ErrorMessage && (ErrorMessageText.length() > 0)) - ReturnValue = ReturnValue + "\t" + ErrorMessageText; - - time_t currenttime; - if (flowMakeImage) - { - currenttime = flowMakeImage->getTimeImageTaken(); - zwtime = ConvertTimeToString(currenttime, PREVALUE_TIME_FORMAT_OUTPUT); - } - else - { - time(¤ttime); - localtime(¤ttime); - } - - double difference = difftime(currenttime, lastvalue); // in Sekunden - difference /= 60; // in Minuten - FlowRateAct = (Value - PreValue) / difference; - lastvalue = currenttime; -// std::string _zw = "CalcRate: " + std::to_string(FlowRateAct) + " TimeDifference[min]: " + std::to_string(difference); -// _zw = _zw + " Value: " + std::to_string(Value) + " PreValue: " + std::to_string(PreValue); -// LogFile.WriteToFile(_zw); - - if (ErrorMessageText.length() == 0) - { - PreValue = Value; - ErrorMessageText = "no error"; - SavePreValue(Value, zwtime); - } + SavePreValue(); return true; } -string ClassFlowPostProcessing::getReadout() +string ClassFlowPostProcessing::getReadout(int _number) { - return ReturnValue; + return NUMBERS[_number]->ReturnValue; } -string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror) +string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror, int _number) { if (_rawValue) - return ReturnRawValue; + return NUMBERS[_number]->ReturnRawValue; if (_noerror) - return ReturnValueNoError; - return ReturnValue; + return NUMBERS[_number]->ReturnValueNoError; + return NUMBERS[_number]->ReturnValue; } string ClassFlowPostProcessing::RundeOutput(float _in, int _anzNachkomma){ @@ -478,7 +669,7 @@ string ClassFlowPostProcessing::RundeOutput(float _in, int _anzNachkomma){ } -string ClassFlowPostProcessing::ErsetzteN(string input) +string ClassFlowPostProcessing::ErsetzteN(string input, float _prevalue) { int posN, posPunkt; int pot, ziffer; @@ -499,7 +690,7 @@ string ClassFlowPostProcessing::ErsetzteN(string input) pot = posPunkt - posN; } - zw = PreValue / pow(10, pot); + zw =_prevalue / pow(10, pot); ziffer = ((int) zw) % 10; input[posN] = ziffer + 48; @@ -509,7 +700,7 @@ string ClassFlowPostProcessing::ErsetzteN(string input) return input; } -float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamshift, bool _isanalog){ +float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamshift, bool _isanalog, float _preValue){ int aktdigit, olddigit; int aktdigit_before, olddigit_before; int pot, pot_max; @@ -527,12 +718,12 @@ float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamsh { zw = input / pow(10, pot-1); aktdigit_before = ((int) zw) % 10; - zw = PreValue / pow(10, pot-1); + zw = _preValue / pow(10, pot-1); olddigit_before = ((int) zw) % 10; zw = input / pow(10, pot); aktdigit = ((int) zw) % 10; - zw = PreValue / pow(10, pot); + zw = _preValue / pow(10, pot); olddigit = ((int) zw) % 10; no_nulldurchgang = (olddigit_before <= aktdigit_before); @@ -558,18 +749,18 @@ float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamsh return input; } -string ClassFlowPostProcessing::getReadoutRate() +string ClassFlowPostProcessing::getReadoutRate(int _number) { - return std::to_string(FlowRateAct); + return std::to_string(NUMBERS[_number]->FlowRateAct); } -string ClassFlowPostProcessing::getReadoutTimeStamp() +string ClassFlowPostProcessing::getReadoutTimeStamp(int _number) { - return timeStamp; + return NUMBERS[_number]->timeStamp; } -string ClassFlowPostProcessing::getReadoutError() +string ClassFlowPostProcessing::getReadoutError(int _number) { - return ErrorMessageText; + return NUMBERS[_number]->ErrorMessageText; } diff --git a/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h b/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h index 8a115705..48a5510e 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h +++ b/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h @@ -1,58 +1,94 @@ #pragma once #include "ClassFlow.h" #include "ClassFlowMakeImage.h" +#include "ClassFlowAnalog.h" +#include "ClassFlowDigit.h" + #include +struct NumberPost { +// int PreValueAgeStartup; + float MaxRateValue; + bool useMaxRateValue; + bool ErrorMessage; + bool PreValueOkay; + bool AllowNegativeRates; + bool checkDigitIncreaseConsistency; + time_t lastvalue; + string timeStamp; + float FlowRateAct; // m3 / min + float PreValue; // letzter Wert, der gut ausgelesen wurde + float Value; // letzer ausgelesener Wert, inkl. Korrekturen + string ReturnRawValue; // Rohwert (mit N & führenden 0) + string ReturnValue; // korrigierter Rückgabewert, ggf. mit Fehlermeldung + string ReturnPreValue; // korrigierter Rückgabewert ohne Fehlermeldung + string ReturnValueNoError; + string ErrorMessageText; // Fehlermeldung bei Consistency Check + int AnzahlAnalog; + int AnzahlDigital; + int DecimalShift; + int Nachkomma; +// ClassFlowAnalog* ANALOG; +// ClassFlowDigit* DIGIT; + + digit *digit_roi; + analog *analog_roi; + + + + string name; +}; + + class ClassFlowPostProcessing : public ClassFlow { protected: + std::vector NUMBERS; + bool UpdatePreValueINI; + bool PreValueUse; int PreValueAgeStartup; - bool AllowNegativeRates; - float MaxRateValue; - bool useMaxRateValue; bool ErrorMessage; - bool PreValueOkay; - bool checkDigitIncreaseConsistency; - int DecimalShift; - time_t lastvalue; - float FlowRateAct; // m3 / min + + + ClassFlowAnalog* flowAnalog; + ClassFlowDigit* flowDigit; string FilePreValue; - float PreValue; // letzter Wert, der gut ausgelesen wurde - float Value; // letzer ausgelesener Wert, inkl. Korrekturen - string ReturnRawValue; // Rohwert (mit N & führenden 0) - string ReturnValue; // korrigierter Rückgabewert, ggf. mit Fehlermeldung - string ReturnValueNoError; // korrigierter Rückgabewert ohne Fehlermeldung - string ErrorMessageText; // Fehlermeldung bei Consistency Check - string timeStamp; ClassFlowMakeImage *flowMakeImage; bool LoadPreValue(void); string ShiftDecimal(string in, int _decShift); - string ErsetzteN(string); - float checkDigitConsistency(float input, int _decilamshift, bool _isanalog); + string ErsetzteN(string, float _prevalue); + float checkDigitConsistency(float input, int _decilamshift, bool _isanalog, float _preValue); string RundeOutput(float _in, int _anzNachkomma); + void InitNUMBERS(); + void handleDecimalSeparator(string _decsep, string _value); + void handleMaxRateValue(string _decsep, string _value); + + public: ClassFlowPostProcessing(std::vector* lfc); bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); - string getReadout(); - string getReadoutParam(bool _rawValue, bool _noerror); - string getReadoutError(); - string getReadoutRate(); - string getReadoutTimeStamp(); - void SavePreValue(float value, string time = ""); - string GetPreValue(); + string getReadout(int _number); + string getReadoutParam(bool _rawValue, bool _noerror, int _number = 0); + string getReadoutError(int _number = 0); + string getReadoutRate(int _number = 0); + string getReadoutTimeStamp(int _number = 0); + void SavePreValue(); + string GetPreValue(std::string _number = ""); + void SetPreValue(float zw, string _numbers); + std::vector GetNumbers(){return NUMBERS;}; string name(){return "ClassFlowPostProcessing";}; }; diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index 0a32b30e..07f7e7e0 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/code/components/jomjol_helper/Helper.cpp @@ -10,6 +10,7 @@ #include #include + #include "ClassLogFile.h" //#include "ClassLogFile.h" @@ -77,8 +78,9 @@ void memCopyGen(uint8_t* _source, uint8_t* _target, int _size) -FILE* OpenFileAndWait(const char* nm, char* _mode, int _waitsec) +FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec) { + printf("open config file %s in mode %s\n", nm, _mode); FILE *pfile = fopen(nm, _mode); if (pfile == NULL) @@ -313,6 +315,14 @@ string toUpper(string in) return in; } +string toLower(string in) +{ + for (int i = 0; i < in.length(); ++i) + in[i] = tolower(in[i]); + + return in; +} + // CPU Temp extern "C" uint8_t temprature_sens_read(); float temperatureRead() @@ -358,3 +368,30 @@ int removeFolder(const char* folderPath, const char* logTag) { return deleted; } + + + +std::vector HelperZerlegeZeile(std::string input, std::string _delimiter = "") +{ + std::vector Output; + std::string delimiter = " =,"; + if (_delimiter.length() > 0){ + delimiter = _delimiter; + } + + input = trim(input, delimiter); + size_t pos = findDelimiterPos(input, delimiter); + std::string token; + while (pos != std::string::npos) { + token = input.substr(0, pos); + token = trim(token, delimiter); + Output.push_back(token); + input.erase(0, pos + 1); + input = trim(input, delimiter); + pos = findDelimiterPos(input, delimiter); + } + Output.push_back(input); + + return Output; +} + diff --git a/code/components/jomjol_helper/Helper.h b/code/components/jomjol_helper/Helper.h index 5ecf2f5f..46fbf8d6 100644 --- a/code/components/jomjol_helper/Helper.h +++ b/code/components/jomjol_helper/Helper.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include using namespace std; @@ -10,7 +11,7 @@ void FindReplace(std::string& line, std::string& oldString, std::string& newStri void CopyFile(string input, string output); -FILE* OpenFileAndWait(const char* nm, char* _mode, int _waitsec = 1); +FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec = 1); size_t findDelimiterPos(string input, string delimiter); //string trim(string istring); @@ -22,6 +23,7 @@ string getFileType(string filename); int mkdir_r(const char *dir, const mode_t mode); int removeFolder(const char* folderPath, const char* logTag); +string toLower(string in); string toUpper(string in); float temperatureRead(); @@ -30,6 +32,8 @@ time_t addDays(time_t startTime, int days); void memCopyGen(uint8_t* _source, uint8_t* _target, int _size); +std::vector HelperZerlegeZeile(std::string input, std::string _delimiter); + /////////////////////////// size_t getInternalESPHeapSize(); size_t getESPHeapSize(); diff --git a/code/components/jomjol_logfile/ClassLogFile.cpp b/code/components/jomjol_logfile/ClassLogFile.cpp index 71825ca7..a026d985 100644 --- a/code/components/jomjol_logfile/ClassLogFile.cpp +++ b/code/components/jomjol_logfile/ClassLogFile.cpp @@ -12,7 +12,7 @@ ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt"); void ClassLogFile::WriteHeapInfo(std::string _id) { -std::string _zw = "\t" + _id; + std::string _zw = "\t" + _id; if (loglevel > 0) _zw = _zw + "\t" + getESPHeapInfo(); diff --git a/code/components/jomjol_mqtt/interface_mqtt.cpp b/code/components/jomjol_mqtt/interface_mqtt.cpp index 7fde4733..3230cb8f 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.cpp +++ b/code/components/jomjol_mqtt/interface_mqtt.cpp @@ -1,12 +1,14 @@ #include "interface_mqtt.h" - +//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #include "esp_log.h" #include "mqtt_client.h" #include "ClassLogFile.h" -static const char *TAG = "interface_mqtt"; +static const char *TAG_INTERFACEMQTT = "interface_mqtt"; +std::map>* connectFunktionMap = NULL; +std::map>* subscribeFunktionMap = NULL; bool debugdetail = true; // #define CONFIG_BROKER_URL "mqtt://192.168.178.43:1883" @@ -23,44 +25,67 @@ void MQTTPublish(std::string _key, std::string _content, int retained_flag){ msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag); zw = "sent publish successful in MQTTPublish, msg_id=" + std::to_string(msg_id) + ", " + _key + ", " + _content; if (debugdetail) LogFile.WriteToFile(zw); - ESP_LOGI(TAG, "sent publish successful in MQTTPublish, msg_id=%d, %s, %s", msg_id, _key.c_str(), _content.c_str()); + ESP_LOGD(TAG_INTERFACEMQTT, "sent publish successful in MQTTPublish, msg_id=%d, %s, %s", msg_id, _key.c_str(), _content.c_str()); } else { - ESP_LOGI(TAG, "Problem with Publish, client=%d, mqtt_connected %d", (int) client, (int) mqtt_connected); + ESP_LOGW(TAG_INTERFACEMQTT, "Problem with Publish, client=%d, mqtt_connected %d", (int) client, (int) mqtt_connected); } } static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { + int msg_id; + std::string topic = ""; switch (event->event_id) { + case MQTT_EVENT_BEFORE_CONNECT: + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_BEFORE_CONNECT"); + break; case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_CONNECTED"); mqtt_connected = true; + MQTTconnected(); break; case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DISCONNECTED"); + break; + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG_INTERFACEMQTT, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_PUBLISHED: - ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - printf("DATA=%.*s\r\n", event->data_len, event->data); + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DATA"); + ESP_LOGI(TAG_INTERFACEMQTT, "TOPIC=%.*s\r\n", event->topic_len, event->topic); + ESP_LOGI(TAG_INTERFACEMQTT, "DATA=%.*s\r\n", event->data_len, event->data); + topic.assign(event->topic, event->topic_len); + if (subscribeFunktionMap != NULL) { + if (subscribeFunktionMap->find(topic) != subscribeFunktionMap->end()) { + ESP_LOGD(TAG_INTERFACEMQTT, "call handler function\r\n"); + (*subscribeFunktionMap)[topic](topic, event->data, event->data_len); + } + } else { + ESP_LOGW(TAG_INTERFACEMQTT, "no handler available\r\n"); + } break; case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_ERROR"); break; default: - ESP_LOGI(TAG, "Other event id:%d", event->event_id); + ESP_LOGI(TAG_INTERFACEMQTT, "Other event id:%d", event->event_id); break; } return ESP_OK; } static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { - ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); + ESP_LOGD(TAG_INTERFACEMQTT, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); mqtt_event_handler_cb((esp_mqtt_event_handle_t) event_data); } @@ -82,7 +107,7 @@ void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, st if (_user.length() && _password.length()){ mqtt_cfg.username = _user.c_str(); mqtt_cfg.password = _password.c_str(); - printf("Connect to MQTT: %s, %s", mqtt_cfg.username, mqtt_cfg.password); + ESP_LOGI(TAG_INTERFACEMQTT, "Connect to MQTT: %s, %s", mqtt_cfg.username, mqtt_cfg.password); }; client = esp_mqtt_client_init(&mqtt_cfg); @@ -91,3 +116,91 @@ void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, st MQTTPublish(_LWTContext, "", 1); } + +void MQTTdestroy() { + if (client != NULL) { + esp_mqtt_client_stop(client); + esp_mqtt_client_destroy(client); + } +} + +bool MQTTisConnected() { + return mqtt_connected; +} + +void MQTTregisterConnectFunction(std::string name, std::function func){ + ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str()); + if (connectFunktionMap == NULL) { + connectFunktionMap = new std::map>(); + } + + if ((*connectFunktionMap)[name] != NULL) { + ESP_LOGW(TAG_INTERFACEMQTT, "connect function %s already registred", name.c_str()); + return; + } + + (*connectFunktionMap)[name] = func; + + if (mqtt_connected) { + func(); + } +} + +void MQTTunregisterConnectFunction(std::string name){ + ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str()); + if ((connectFunktionMap != NULL) && (connectFunktionMap->find(name) != connectFunktionMap->end())) { + connectFunktionMap->erase(name); + } +} + +void MQTTregisterSubscribeFunction(std::string topic, std::function func){ + ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisterSubscribeFunction %s\r\n", topic.c_str()); + if (subscribeFunktionMap == NULL) { + subscribeFunktionMap = new std::map>(); + } + + if ((*subscribeFunktionMap)[topic] != NULL) { + ESP_LOGW(TAG_INTERFACEMQTT, "topic %s already registred for subscription", topic.c_str()); + return; + } + + (*subscribeFunktionMap)[topic] = func; + + if (mqtt_connected) { + int msg_id = esp_mqtt_client_subscribe(client, topic.c_str(), 0); + ESP_LOGD(TAG_INTERFACEMQTT, "topic %s subscribe successful, msg_id=%d", topic.c_str(), msg_id); + } +} + +void MQTTconnected(){ + if (mqtt_connected) { + if (connectFunktionMap != NULL) { + for(std::map>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) { + it->second(); + ESP_LOGD(TAG_INTERFACEMQTT, "call connect function %s", it->first.c_str()); + } + } + + if (subscribeFunktionMap != NULL) { + for(std::map>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) { + int msg_id = esp_mqtt_client_subscribe(client, it->first.c_str(), 0); + ESP_LOGD(TAG_INTERFACEMQTT, "topic %s subscribe successful, msg_id=%d", it->first.c_str(), msg_id); + } + } + } +} + +void MQTTdestroySubscribeFunction(){ + if (subscribeFunktionMap != NULL) { + if (mqtt_connected) { + for(std::map>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) { + int msg_id = esp_mqtt_client_unsubscribe(client, it->first.c_str()); + ESP_LOGI(TAG_INTERFACEMQTT, "topic %s unsubscribe successful, msg_id=%d", it->first.c_str(), msg_id); + } + } + + subscribeFunktionMap->clear(); + delete subscribeFunktionMap; + subscribeFunktionMap = NULL; + } +} \ No newline at end of file diff --git a/code/components/jomjol_mqtt/interface_mqtt.h b/code/components/jomjol_mqtt/interface_mqtt.h index f514ea2d..50990e6f 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.h +++ b/code/components/jomjol_mqtt/interface_mqtt.h @@ -1,7 +1,23 @@ +#ifndef INTERFACE_MQTT_H +#define INTERFACE_MQTT_H + #include +#include +#include void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, std::string _LWTContext, int _keepalive); +void MQTTdestroy(); //void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user = "", std::string _password = ""); -void MQTTPublish(std::string _key, std::string _content, int retained_flag = 0); \ No newline at end of file +void MQTTPublish(std::string _key, std::string _content, int retained_flag = 0); + +bool MQTTisConnected(); + +void MQTTregisterConnectFunction(std::string name, std::function func); +void MQTTunregisterConnectFunction(std::string name); +void MQTTregisterSubscribeFunction(std::string topic, std::function func); +void MQTTdestroySubscribeFunction(); +void MQTTconnected(); + +#endif //INTERFACE_MQTT_H \ No newline at end of file diff --git a/code/components/jomjol_tfliteclass/CTfLiteClass.cpp b/code/components/jomjol_tfliteclass/CTfLiteClass.cpp index d0a529f5..e2e20227 100644 --- a/code/components/jomjol_tfliteclass/CTfLiteClass.cpp +++ b/code/components/jomjol_tfliteclass/CTfLiteClass.cpp @@ -98,7 +98,8 @@ void CTfLiteClass::GetOutPut() void CTfLiteClass::Invoke() { - interpreter->Invoke(); + if (interpreter != nullptr) + interpreter->Invoke(); } @@ -208,7 +209,7 @@ unsigned char* CTfLiteClass::ReadFileToCharArray(std::string _fn) return result; } -void CTfLiteClass::LoadModel(std::string _fn){ +bool CTfLiteClass::LoadModel(std::string _fn){ #ifdef SUPRESS_TFLITE_ERRORS this->error_reporter = new tflite::OwnMicroErrorReporter; @@ -219,9 +220,14 @@ void CTfLiteClass::LoadModel(std::string _fn){ unsigned char *rd; rd = ReadFileToCharArray(_fn.c_str()); + if (rd == NULL) + return false; + this->model = tflite::GetModel(rd); free(rd); TFLITE_MINIMAL_CHECK(model != nullptr); + + return true; } diff --git a/code/components/jomjol_tfliteclass/CTfLiteClass.h b/code/components/jomjol_tfliteclass/CTfLiteClass.h index 07279f14..4c6ed8f7 100644 --- a/code/components/jomjol_tfliteclass/CTfLiteClass.h +++ b/code/components/jomjol_tfliteclass/CTfLiteClass.h @@ -56,7 +56,7 @@ class CTfLiteClass public: CTfLiteClass(); ~CTfLiteClass(); - void LoadModel(std::string _fn); + bool LoadModel(std::string _fn); void MakeAllocate(); void GetInputTensorSize(); bool LoadInputImageBasis(CImageBasis *rs); diff --git a/code/components/jomjol_tfliteclass/server_tflite.cpp b/code/components/jomjol_tfliteclass/server_tflite.cpp index f29e384c..d6b42067 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.cpp +++ b/code/components/jomjol_tfliteclass/server_tflite.cpp @@ -8,6 +8,7 @@ #include #include +#include "defines.h" #include "Helper.h" #include "esp_camera.h" @@ -17,8 +18,9 @@ #include "ClassFlowControll.h" #include "ClassLogFile.h" +#include "server_GPIO.h" -//#define DEBUG_DETAIL_ON +// #define DEBUG_DETAIL_ON ClassFlowControll tfliteflow; @@ -37,6 +39,9 @@ bool auto_isrunning = false; int countRounds = 0; +static const char *TAGTFLITE = "server_tflite"; + + int getCountFlowRounds() { return countRounds; } @@ -64,9 +69,11 @@ void KillTFliteTasks() #ifdef DEBUG_DETAIL_ON printf("Handle: xHandleblink_task_doFlow: %ld\n", (long) xHandleblink_task_doFlow); #endif - if (xHandleblink_task_doFlow) + if (xHandleblink_task_doFlow != NULL) { - vTaskDelete(xHandleblink_task_doFlow); + TaskHandle_t xHandleblink_task_doFlowTmp = xHandleblink_task_doFlow; + xHandleblink_task_doFlow = NULL; + vTaskDelete(xHandleblink_task_doFlowTmp); #ifdef DEBUG_DETAIL_ON printf("Killed: xHandleblink_task_doFlow\n"); #endif @@ -75,9 +82,11 @@ void KillTFliteTasks() #ifdef DEBUG_DETAIL_ON printf("Handle: xHandletask_autodoFlow: %ld\n", (long) xHandletask_autodoFlow); #endif - if (xHandletask_autodoFlow) + if (xHandletask_autodoFlow != NULL) { - vTaskDelete(xHandletask_autodoFlow); + TaskHandle_t xHandletask_autodoFlowTmp = xHandletask_autodoFlow; + xHandletask_autodoFlow = NULL; + vTaskDelete(xHandletask_autodoFlowTmp); #ifdef DEBUG_DETAIL_ON printf("Killed: xHandletask_autodoFlow\n"); #endif @@ -87,11 +96,10 @@ void KillTFliteTasks() void doInit(void) { - string config = "/sdcard/config/config.ini"; #ifdef DEBUG_DETAIL_ON printf("Start tfliteflow.InitFlow(config);\n"); #endif - tfliteflow.InitFlow(config); + tfliteflow.InitFlow(CONFIG_FILE); #ifdef DEBUG_DETAIL_ON printf("Finished tfliteflow.InitFlow(config);\n"); #endif @@ -136,7 +144,7 @@ esp_err_t handler_init(httpd_req_t *req) printf("handler_doinit uri:\n"); printf(req->uri); printf("\n"); #endif - char* resp_str = "Init started
"; + const char* resp_str = "Init started
"; httpd_resp_send(req, resp_str, strlen(resp_str)); doInit(); @@ -159,8 +167,6 @@ esp_err_t handler_doflow(httpd_req_t *req) LogFile.WriteHeapInfo("handler_doflow - Start"); #endif - char* resp_str; - printf("handler_doFlow uri: "); printf(req->uri); printf("\n"); if (flowisrunning) @@ -173,7 +179,7 @@ esp_err_t handler_doflow(httpd_req_t *req) { xTaskCreate(&blink_task_doFlow, "blink_doFlow", configMINIMAL_STACK_SIZE * 64, NULL, tskIDLE_PRIORITY+1, &xHandleblink_task_doFlow); } - resp_str = "doFlow gestartet - dauert ca. 60 Sekunden"; + const char* resp_str = "doFlow gestartet - dauert ca. 60 Sekunden"; httpd_resp_send(req, resp_str, strlen(resp_str)); /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); @@ -196,6 +202,8 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req) bool _rawValue = false; bool _noerror = false; + bool _all = false; + std::string _type = "value"; string zw; printf("handler_wasserzaehler uri:\n"); printf(req->uri); printf("\n"); @@ -206,6 +214,22 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req) if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) { // printf("Query: "); printf(_query); printf("\n"); + if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + printf("all is found"); printf(_size); printf("\n"); +#endif + _all = true; + } + + if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + printf("all is found"); printf(_size); printf("\n"); +#endif + _type = std::string(_size); + } + if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK) { #ifdef DEBUG_DETAIL_ON @@ -222,6 +246,29 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req) } } + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (_all) + { + httpd_resp_set_type(req, "text/plain"); + printf("TYPE: %s\n", _type.c_str()); + int _intype = READOUT_TYPE_VALUE; + if (_type == "prevalue") + _intype = READOUT_TYPE_PREVALUE; + if (_type == "raw") + _intype = READOUT_TYPE_RAWVALUE; + if (_type == "error") + _intype = READOUT_TYPE_ERROR; + + + zw = tfliteflow.getReadoutAll(_intype); + printf("ZW: %s\n", zw.c_str()); + if (zw.length() > 0) + httpd_resp_sendstr_chunk(req, zw.c_str()); + httpd_resp_sendstr_chunk(req, NULL); + return ESP_OK; + } + zw = tfliteflow.getReadout(_rawValue, _noerror); if (zw.length() > 0) httpd_resp_sendstr_chunk(req, zw.c_str()); @@ -429,7 +476,7 @@ esp_err_t handler_editflow(httpd_req_t *req) // printf("Parameter host: "); printf(_host.c_str()); printf("\n"); // string zwzw = "Do " + _task + " start\n"; printf(zwzw.c_str()); - bool changed = Camera.SetBrightnessContrastSaturation(bri, con, sat); + Camera.SetBrightnessContrastSaturation(bri, con, sat); std::string zw = tfliteflow.doSingleStep("[MakeImage]", _host); httpd_resp_sendstr_chunk(req, zw.c_str()); } @@ -498,6 +545,7 @@ esp_err_t handler_prevalue(httpd_req_t *req) char _query[100]; char _size[10] = ""; + char _numbers[50] = "default"; if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) { @@ -511,15 +559,24 @@ esp_err_t handler_prevalue(httpd_req_t *req) printf("Value: "); printf(_size); printf("\n"); #endif } + + httpd_query_key_value(_query, "numbers", _numbers, 50); } if (strlen(_size) == 0) - zw = tfliteflow.GetPrevalue(); + { + zw = tfliteflow.GetPrevalue(std::string(_numbers)); + } else - zw = "SetPrevalue to " + tfliteflow.UpdatePrevalue(_size); + { + zw = "SetPrevalue to " + tfliteflow.UpdatePrevalue(_size, _numbers); + } resp_str = zw.c_str(); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + httpd_resp_send(req, resp_str, strlen(resp_str)); /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); @@ -535,17 +592,17 @@ void task_autodoFlow(void *pvParameter) { int64_t fr_start, fr_delta_ms; + printf("task_autodoFlow: start\r\n"); doInit(); - - auto_isrunning = tfliteflow.isAutoStart(auto_intervall); + gpio_handler_init(); + auto_isrunning = tfliteflow.isAutoStart(auto_intervall); if (isSetupModusActive()) { auto_isrunning = false; std::string zw_time = gettimestring(LOGFILE_TIME_FORMAT); tfliteflow.doFlowMakeImageOnly(zw_time); } - while (auto_isrunning) { std::string _zw = "task_autodoFlow - next round - Round #" + std::to_string(++countRounds); @@ -590,6 +647,7 @@ void task_autodoFlow(void *pvParameter) } vTaskDelete(NULL); //Delete this task if it exits from the loop above xHandletask_autodoFlow = NULL; + printf("task_autodoFlow: end\r\n"); } void TFliteDoAutoStart() diff --git a/code/components/jomjol_tfliteclass/server_tflite.h b/code/components/jomjol_tfliteclass/server_tflite.h index 148be20e..cb39a10f 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.h +++ b/code/components/jomjol_tfliteclass/server_tflite.h @@ -5,8 +5,6 @@ //#include "ClassControllCamera.h" -static const char *TAGTFLITE = "server_tflite"; - void register_server_tflite_uri(httpd_handle_t server); void KillTFliteTasks(); diff --git a/code/components/jomjol_time_sntp/time_sntp.cpp b/code/components/jomjol_time_sntp/time_sntp.cpp index 51f9175d..240a36d9 100644 --- a/code/components/jomjol_time_sntp/time_sntp.cpp +++ b/code/components/jomjol_time_sntp/time_sntp.cpp @@ -18,6 +18,7 @@ static const char *TAG = "sntp"; bool setTimeAlwaysOnReboot = true; +time_t bootTime; static void obtain_time(void); static void initialize_sntp(void); @@ -125,4 +126,17 @@ static void initialize_sntp(void) sntp_setservername(0, "pool.ntp.org"); // sntp_set_time_sync_notification_cb(time_sync_notification_cb); sntp_init(); +} + +void setBootTime() +{ + time(&bootTime); +} + +time_t getUpTime() +{ + time_t now; + time(&now); + + return now - bootTime; } \ No newline at end of file diff --git a/code/components/jomjol_time_sntp/time_sntp.h b/code/components/jomjol_time_sntp/time_sntp.h index da37ae0b..c56e6c91 100644 --- a/code/components/jomjol_time_sntp/time_sntp.h +++ b/code/components/jomjol_time_sntp/time_sntp.h @@ -18,4 +18,7 @@ std::string gettimestring(const char * frm); std::string ConvertTimeToString(time_t _time, const char * frm); void setTimeZone(std::string _tzstring); -void reset_servername(std::string _servername); \ No newline at end of file +void reset_servername(std::string _servername); + +void setBootTime(); +time_t getUpTime(); diff --git a/code/include/defines.h b/code/include/defines.h new file mode 100644 index 00000000..436b0baa --- /dev/null +++ b/code/include/defines.h @@ -0,0 +1,6 @@ +#ifndef defines_h +#define defines_h + +#define CONFIG_FILE "/sdcard/config/config.ini" + +#endif // ifndef defines_h \ No newline at end of file diff --git a/code/main/main.cpp b/code/main/main.cpp index 75dee4f9..145f862f 100644 --- a/code/main/main.cpp +++ b/code/main/main.cpp @@ -19,6 +19,7 @@ #include "connect_wlan.h" #include "read_wlanini.h" +#include "server_main.h" #include "server_tflite.h" #include "server_file.h" #include "server_ota.h" @@ -30,16 +31,14 @@ #define __SD_USE_ONE_LINE_MODE__ -#ifdef __SD_USE_ONE_LINE_MODE__ #include "server_GPIO.h" -#endif #define BLINK_GPIO GPIO_NUM_33 -static const char *TAGMAIN = "connect_wlan_main"; +static const char *TAGMAIN = "main"; -#define FLASH_GPIO GPIO_NUM_4 +//#define FLASH_GPIO GPIO_NUM_4 bool Init_NVS_SDCard() { @@ -50,7 +49,7 @@ bool Init_NVS_SDCard() } //////////////////////////////////////////////// - ESP_LOGI(TAG, "Using SDMMC peripheral"); + ESP_LOGI(TAGMAIN, "Using SDMMC peripheral"); sdmmc_host_t host = SDMMC_HOST_DEFAULT(); // This initializes the slot without card detect (CD) and write protect (WP) signals. @@ -92,10 +91,10 @@ bool Init_NVS_SDCard() if (ret != ESP_OK) { if (ret == ESP_FAIL) { - ESP_LOGE(TAG, "Failed to mount filesystem. " + ESP_LOGE(TAGMAIN, "Failed to mount filesystem. " "If you want the card to be formatted, set format_if_mount_failed = true."); } else { - ESP_LOGE(TAG, "Failed to initialize the card (%s). " + ESP_LOGE(TAGMAIN, "Failed to initialize the card (%s). " "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); } return false; @@ -108,9 +107,9 @@ bool Init_NVS_SDCard() // Init the GPIO // Flash ausschalten - gpio_pad_select_gpio(FLASH_GPIO); - gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); - gpio_set_level(FLASH_GPIO, 0); + // gpio_pad_select_gpio(FLASH_GPIO); + // gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); + // gpio_set_level(FLASH_GPIO, 0); return true; } @@ -174,11 +173,12 @@ extern "C" void app_main(void) TickType_t xDelay; xDelay = 2000 / portTICK_PERIOD_MS; - printf("Autoflow: sleep for : %ldms\n", (long) xDelay); + printf("main: sleep for : %ldms\n", (long) xDelay); // LogFile.WriteToFile("Startsequence 06"); vTaskDelay( xDelay ); // LogFile.WriteToFile("Startsequence 07"); setup_time(); + setBootTime(); LogFile.WriteToFile("============================================================================================="); LogFile.WriteToFile("=================================== Main Started ============================================"); LogFile.WriteToFile("============================================================================================="); @@ -190,7 +190,7 @@ extern "C" void app_main(void) // Camera.InitCam(); // Camera.LightOnOff(false); xDelay = 2000 / portTICK_PERIOD_MS; - printf("Autoflow: sleep for : %ldms\n", (long) xDelay); + printf("main: sleep for : %ldms\n", (long) xDelay); vTaskDelay( xDelay ); server = start_webserver(); @@ -199,13 +199,12 @@ extern "C" void app_main(void) register_server_file_uri(server, "/sdcard"); register_server_ota_sdcard_uri(server); -#ifdef __SD_USE_ONE_LINE_MODE__ - register_server_GPIO_uri(server); -#endif - printf("vor reg server main\n"); + gpio_handler_create(server); + printf("vor reg server main\n"); register_server_main_uri(server, "/sdcard"); printf("vor dotautostart\n"); TFliteDoAutoStart(); } + diff --git a/code/main/server_main.cpp b/code/main/server_main.cpp index ba31c09c..de2683e3 100644 --- a/code/main/server_main.cpp +++ b/code/main/server_main.cpp @@ -20,9 +20,9 @@ httpd_handle_t server = NULL; - std::string starttime = ""; +static const char *TAG_SERVERMAIN = "server-main"; /* An HTTP GET handler */ esp_err_t info_get_handler(httpd_req_t *req) @@ -198,7 +198,7 @@ esp_err_t hello_main_handler(httpd_req_t *req) printf("File requested: %s\n", filetosend.c_str()); if (!filename) { - ESP_LOGE(TAG, "Filename is too long"); + ESP_LOGE(TAG_SERVERMAIN, "Filename is too long"); /* Respond with 500 Internal Server Error */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); return ESP_FAIL; @@ -234,7 +234,7 @@ esp_err_t img_tmp_handler(httpd_req_t *req) filetosend = filetosend + "/img_tmp/" + std::string(filename); printf("File to upload: %s\n", filetosend.c_str()); - esp_err_t res = send_file(req, filetosend); + esp_err_t res = send_file(req, filetosend); if (res != ESP_OK) return res; @@ -299,7 +299,9 @@ esp_err_t sysinfo_handler(httpd_req_t *req) std::string gitbranch = libfive_git_branch(); std::string gitbasebranch = git_base_branch(); std::string htmlversion = getHTMLversion(); - + char freeheapmem[11]; + sprintf(freeheapmem, "%zu", esp_get_free_heap_size()); + tcpip_adapter_ip_info_t ip_info; ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info)); const char *hostname; @@ -314,7 +316,8 @@ esp_err_t sysinfo_handler(httpd_req_t *req) \"html\" : \"" + htmlversion + "\",\ \"cputemp\" : \"" + cputemp + "\",\ \"hostname\" : \"" + hostname + "\",\ - \"IPv4\" : \"" + ip4addr_ntoa(&ip_info.ip) + "\"\ + \"IPv4\" : \"" + ip4addr_ntoa(&ip_info.ip) + "\",\ + \"freeHeapMem\" : \"" + freeheapmem + "\"\ }\ ]"; @@ -387,7 +390,7 @@ httpd_handle_t start_webserver(void) httpd_config_t config = { }; config.task_priority = tskIDLE_PRIORITY+5; - config.stack_size = 32384; // bei 32k stürzt das Programm beim Bilderaufnehmen ab + config.stack_size = 32768; // bei 32k stürzt das Programm beim Bilderaufnehmen ab config.core_id = tskNO_AFFINITY; config.server_port = 80; config.ctrl_port = 32768; @@ -403,21 +406,22 @@ httpd_handle_t start_webserver(void) config.global_transport_ctx = NULL; config.global_transport_ctx_free_fn = NULL; config.open_fn = NULL; - config.close_fn = NULL; + config.close_fn = NULL; + config.lru_purge_enable = true; // neu, um schlechte Serverbindung zu verhindern // config.uri_match_fn = NULL; config.uri_match_fn = httpd_uri_match_wildcard; starttime = gettimestring("%Y%m%d-%H%M%S"); // Start the httpd server - ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + ESP_LOGI(TAG_SERVERMAIN, "Starting server on port: '%d'", config.server_port); if (httpd_start(&server, &config) == ESP_OK) { // Set URI handlers - ESP_LOGI(TAG, "Registering URI handlers"); + ESP_LOGI(TAG_SERVERMAIN, "Registering URI handlers"); return server; } - ESP_LOGI(TAG, "Error starting server!"); + ESP_LOGI(TAG_SERVERMAIN, "Error starting server!"); return NULL; } @@ -432,7 +436,7 @@ void disconnect_handler(void* arg, esp_event_base_t event_base, { httpd_handle_t* server = (httpd_handle_t*) arg; if (*server) { - ESP_LOGI(TAG, "Stopping webserver"); + ESP_LOGI(TAG_SERVERMAIN, "Stopping webserver"); stop_webserver(*server); *server = NULL; } @@ -443,9 +447,7 @@ void connect_handler(void* arg, esp_event_base_t event_base, { httpd_handle_t* server = (httpd_handle_t*) arg; if (*server == NULL) { - ESP_LOGI(TAG, "Starting webserver"); + ESP_LOGI(TAG_SERVERMAIN, "Starting webserver"); *server = start_webserver(); } } - - diff --git a/code/main/server_main.h b/code/main/server_main.h index e4f75b4c..00033b66 100644 --- a/code/main/server_main.h +++ b/code/main/server_main.h @@ -8,18 +8,17 @@ #include #include #include "nvs_flash.h" -#include "tcpip_adapter.h" +#include "esp_netif.h" #include "esp_eth.h" - +#include "server_GPIO.h" #include -static const char *TAG = "server-main"; - extern httpd_handle_t server; httpd_handle_t start_webserver(void); void register_server_main_uri(httpd_handle_t server, const char *base_path); + #endif diff --git a/code/main/version.cpp b/code/main/version.cpp index c13cc7d6..35d6530e 100644 --- a/code/main/version.cpp +++ b/code/main/version.cpp @@ -1,4 +1,4 @@ -const char* GIT_REV="21a59fb"; -const char* GIT_TAG="v7.1.1"; -const char* GIT_BRANCH="master"; -const char* BUILD_TIME="2021-06-17 19:59"; \ No newline at end of file +const char* GIT_REV="1f6b02a"; +const char* GIT_TAG=""; +const char* GIT_BRANCH="rolling"; +const char* BUILD_TIME="2021-07-13 20:37"; \ No newline at end of file diff --git a/code/platformio.ini b/code/platformio.ini index 50bf0706..ebdc5da7 100644 --- a/code/platformio.ini +++ b/code/platformio.ini @@ -22,7 +22,8 @@ framework = espidf ;board_build.partitions = partitions_singleapp.csv board_build.partitions = partitions.csv -lib_deps = +lib_deps = + jomjol_configfile jomjol_helper jomjol_wlan jomjol_image_proc @@ -36,6 +37,9 @@ lib_deps = jomjol_mqtt jomjol_controlGPIO + monitor_speed = 115200 +monitor_rts = 0 +monitor_dtr = 0 debug_tool = esp-prog diff --git a/code/sdkconfig b/code/sdkconfig index d27a104c..24129176 100644 --- a/code/sdkconfig +++ b/code/sdkconfig @@ -138,7 +138,8 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set -# CONFIG_COMPILER_CXX_EXCEPTIONS is not set +CONFIG_COMPILER_CXX_EXCEPTIONS=y +CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 # CONFIG_COMPILER_CXX_RTTI is not set CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set @@ -1061,7 +1062,8 @@ CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y # CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set # CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set -# CONFIG_CXX_EXCEPTIONS is not set +CONFIG_CXX_EXCEPTIONS=y +CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE=0 CONFIG_STACK_CHECK_NONE=y # CONFIG_STACK_CHECK_NORM is not set # CONFIG_STACK_CHECK_STRONG is not set diff --git a/code/sdkconfig.old b/code/sdkconfig.old index 757645d9..fff6566a 100644 --- a/code/sdkconfig.old +++ b/code/sdkconfig.old @@ -131,8 +131,8 @@ CONFIG_EXAMPLE_CONNECT_IPV6=y # # Compiler options # -CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y -# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set +# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set +CONFIG_COMPILER_OPTIMIZATION_SIZE=y # CONFIG_COMPILER_OPTIMIZATION_PERF is not set # CONFIG_COMPILER_OPTIMIZATION_NONE is not set CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y @@ -598,7 +598,6 @@ CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set # CONFIG_FREERTOS_DEBUG_INTERNALS is not set -CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set CONFIG_FREERTOS_DEBUG_OCDAWARE=y diff --git a/code/version.cpp b/code/version.cpp index e3848299..35d6530e 100644 --- a/code/version.cpp +++ b/code/version.cpp @@ -1,4 +1,4 @@ -const char* GIT_REV="21a59fb"; -const char* GIT_TAG="v7.1.1"; -const char* GIT_BRANCH="master"; -const char* BUILD_TIME="2021-06-17 19:47"; \ No newline at end of file +const char* GIT_REV="1f6b02a"; +const char* GIT_TAG=""; +const char* GIT_BRANCH="rolling"; +const char* BUILD_TIME="2021-07-13 20:37"; \ No newline at end of file diff --git a/firmware/bootloader.bin b/firmware/bootloader.bin index 23975263..5255e150 100644 Binary files a/firmware/bootloader.bin and b/firmware/bootloader.bin differ diff --git a/firmware/firmware.bin b/firmware/firmware.bin index 9aa13676..5d14c9ca 100644 Binary files a/firmware/firmware.bin and b/firmware/firmware.bin differ diff --git a/firmware/html.zip b/firmware/html.zip index d5078f8b..166afaf6 100644 Binary files a/firmware/html.zip and b/firmware/html.zip differ diff --git a/sd-card/config/config.ini b/sd-card/config/config.ini index 9e06820d..f0c55a0b 100644 --- a/sd-card/config/config.ini +++ b/sd-card/config/config.ini @@ -1,61 +1,69 @@ [MakeImage] ;LogImageLocation = /log/source -;LogfileRetentionInDays = 15 WaitBeforeTakingPicture = 5 +;LogfileRetentionInDays = 15 +Brightness = -2 +;Contrast = 0 +;Saturation = 0 ImageQuality = 5 ImageSize = VGA -;Brightness = -2 FixedExposure = false [Alignment] -InitialRotate=180 -FlipImageSize = false -/config/ref0.jpg 119 273 -/config/ref1.jpg 456 138 +InitialRotate = 179 +InitialMirror = false SearchFieldX = 20 SearchFieldY = 20 -InitialMirror= false AlignmentAlgo = Default +FlipImageSize = false +/config/ref0.jpg 103 271 +/config/ref1.jpg 442 142 [Digits] -Model = /config/dig0870s3q.tflite +Model = /config/dig1100s2q.tflite ;LogImageLocation = /log/digit ;LogfileRetentionInDays = 3 ModelInputSize = 20 32 -digit1 306 120 37 67 -digit2 355 120 37 67 -digit3 404 120 37 67 +main.dig1 294 126 30 54 +main.dig2 343 126 30 54 +main.dig3 391 126 30 54 [Analog] Model = /config/ana0700s1lq.tflite ;LogImageLocation = /log/analog ;LogfileRetentionInDays = 3 ModelInputSize = 32 32 -analog1 444 225 92 92 -analog2 391 329 92 92 -analog3 294 369 92 92 -analog4 168 326 92 92 -ExtendedResolution = false +ExtendedResolution = true +main.ana1 432 230 92 92 +main.ana2 379 332 92 92 +main.ana3 283 374 92 92 +main.ana4 155 328 92 92 [PostProcessing] -DecimalShift = 0 +main.DecimalShift = 0 PreValueUse = true PreValueAgeStartup = 720 AllowNegativeRates = false -MaxRateValue = 0.1 +main.MaxRateValue = 0.1 ErrorMessage = true -CheckDigitIncreaseConsistency = false +CheckDigitIncreaseConsistency = true -[MQTT] +;[MQTT] ;Uri = mqtt://IP-ADRESS:1883 -;Topic = wasserzaehler/zaehlerstand -;TopicError = wasserzaehler/error -;TopicRate = wasserzaehler/rate -;TopicTimeStamp = wasserzaehler/timestamp +;MainTopic = wasserzaehler ;ClientID = wasser ;user = USERNAME ;password = PASSWORD +;[GPIO] +;MainTopicMQTT = wasserzaehler/GPIO +;IO0 = input disabled 10 false false +;IO1 = input disabled 10 false false +;IO3 = input disabled 10 false false +;IO4 = built-in-led disabled 10 false false +;IO12 = input-pullup disabled 10 false false +;IO13 = input-pullup disabled 10 false false + [AutoTimer] AutoStart = true Intervall = 4.85 @@ -66,8 +74,7 @@ LogfileRetentionInDays = 3 [System] TimeZone = CET-1CEST,M3.5.0,M10.5.0/3 -;TimeServer = fritz.box -;hostname = watermeter +;TimeServer = undefined +;AutoAdjustSummertime = false +;Hostname = undefined SetupMode = true - -[Ende] \ No newline at end of file diff --git a/sd-card/config/dig0870s3q.tflite b/sd-card/config/dig0870s3q.tflite deleted file mode 100644 index c2dd4fdc..00000000 Binary files a/sd-card/config/dig0870s3q.tflite and /dev/null differ diff --git a/sd-card/config/dig1100s2q.tflite b/sd-card/config/dig1100s2q.tflite new file mode 100644 index 00000000..50bb7624 Binary files /dev/null and b/sd-card/config/dig1100s2q.tflite differ diff --git a/sd-card/html/edit_alignment.html b/sd-card/html/edit_alignment.html index 96d0e302..8fa933fb 100644 --- a/sd-card/html/edit_alignment.html +++ b/sd-card/html/edit_alignment.html @@ -61,7 +61,7 @@ select { - Storage Path/Name: + Storage Path/Name: x: @@ -90,9 +90,8 @@ select { - - + - - - - + + + + diff --git a/sd-card/html/edit_config.html b/sd-card/html/edit_config.html index 23825d5e..a8c2067e 100644 --- a/sd-card/html/edit_config.html +++ b/sd-card/html/edit_config.html @@ -41,7 +41,6 @@ textarea { - - - - + + + + diff --git a/sd-card/html/edit_explain_6.html b/sd-card/html/edit_explain_6.html index e13325dd..7e67df4f 100644 --- a/sd-card/html/edit_explain_6.html +++ b/sd-card/html/edit_explain_6.html @@ -63,10 +63,10 @@ p {font-size: 1em;} param = getConfigParameters(); param["System"]["SetupMode"]["enabled"] = false; param["System"]["SetupMode"]["value1"] = "false"; - setConfigParameters(param); - var textToSave = setConfigParameters(param); - FileDeleteOnServer("/config/config.ini", basepath); - FileSendContent(textToSave, "/config/config.ini", basepath); + + WriteConfigININew(); + SaveConfigToServer(basepath); + var stringota = "/reboot"; window.location = stringota; diff --git a/sd-card/html/edit_reference.html b/sd-card/html/edit_reference.html index e937db5b..91a53dda 100644 --- a/sd-card/html/edit_reference.html +++ b/sd-card/html/edit_reference.html @@ -53,7 +53,7 @@ table { - Degrees + Degrees Brightness: @@ -86,7 +86,6 @@ table { - @@ -209,7 +208,11 @@ table { param["Alignment"]["InitialRotate"].value1 = document.getElementById("prerotateangle").value; if ((param["Alignment"]["InitialMirror"].found == true) && (document.getElementById("mirror").checked)) + { param["Alignment"]["InitialMirror"].value1 = "true"; + param["Alignment"]["InitialMirror"]["found"] = true; + param["Alignment"]["InitialMirror"]["enabled"] = true; + } else param["Alignment"]["InitialMirror"].value1 = "false"; @@ -228,9 +231,8 @@ table { var canvas = document.getElementById("canvas"); drawRotated(false); - var textToSave = setConfigParameters(param); - FileDeleteOnServer("/config/config.ini", basepath); - FileSendContent(textToSave, "/config/config.ini", basepath); + WriteConfigININew(); + SaveConfigToServer(basepath); SaveCanvasToImage(canvas, "/config/reference.jpg", true, basepath); showReference(); diff --git a/sd-card/html/explain_3.html b/sd-card/html/explain_3.html index 077a6a9e..ff1ae887 100644 --- a/sd-card/html/explain_3.html +++ b/sd-card/html/explain_3.html @@ -22,7 +22,7 @@ p {font-size: 1em;}

Define Digits

-Here you define your digits you want to read. +Here you define your digits you want to read. If you have more than one number on the reading you can define several numbers with the "Number" selector. There you can also define new numbers.

With the drop down menue "ROI x" you can change between the different digits. Mark them with the mouse or the coordinates.
diff --git a/sd-card/html/explain_4.html b/sd-card/html/explain_4.html index 546376a3..862bfaf9 100644 --- a/sd-card/html/explain_4.html +++ b/sd-card/html/explain_4.html @@ -22,7 +22,7 @@ p {font-size: 1em;}

Define Digits

-Here you define your analog counters you want to read. If you do not have analog counters delete all ROIs. +Here you define your analog counters you want to read. If you have more than one number on the reading you can define several numbers with the "Number" selector. There you can also define new numbers. If you do not have analog counters delete all ROIs.

With the drop down menue "ROI x" you can change between the different counters. Mark them with the mouse or the coordinates.
diff --git a/sd-card/html/gethost.js b/sd-card/html/gethost.js index 40a7c87a..26a5520d 100644 --- a/sd-card/html/gethost.js +++ b/sd-card/html/gethost.js @@ -5,11 +5,12 @@ function gethost_Version(){ function getbasepath(){ var host = window.location.hostname; - if ((host == "127.0.0.1") || (host == "localhost")) + if ((host == "127.0.0.1") || (host == "localhost") || (host == "")) { -// host = "http://192.168.2.118"; // jomjol interner test -// host = "http://192.168.178.26"; // jomjol interner test +// host = "http://192.168.2.219"; // jomjol interner test +// host = "http://192.168.178.46"; // jomjol interner test host = "http://192.168.178.22"; // jomjol interner Real +// host = "http://192.168.43.191"; // host = "."; // jomjol interner localhost } diff --git a/sd-card/html/info.html b/sd-card/html/info.html index 66713d32..2bcf7d5b 100644 --- a/sd-card/html/info.html +++ b/sd-card/html/info.html @@ -24,8 +24,25 @@ div { +

Current

+ + + + + +
+ Last restart: + +
+ +
+
+ + +

Host Info

+
diff --git a/sd-card/html/jquery-3.5.1.min.js b/sd-card/html/jquery-3.5.1.min.js deleted file mode 100644 index b0614034..00000000 --- a/sd-card/html/jquery-3.5.1.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 - - - - -

Set the previous value for consistency check and substitution for NaN

+Choose Number: + + + + -

Current Value:

+

Current Value:

- - -

Set Value:

+

Set Value:

Input (Format = 123.456):

PreValue: Set PreValue

-

Result:

+

Result:

- \ No newline at end of file + + + + + + + + diff --git a/sd-card/html/readconfig.js b/sd-card/html/readconfig.js deleted file mode 100644 index 4a790646..00000000 --- a/sd-card/html/readconfig.js +++ /dev/null @@ -1,427 +0,0 @@ -function readconfig_Version(){ - return "1.0.0 - 20200910"; - } - -var config_gesamt; -var config_split; -var ref = new Array(2); -var digit = new Array(0); -var analog = new Array(0); -var initalrotate = new Object(); -var analogEnabled = false; -var posAnalogHeader; -var digitsEnabled = false; -var posDigitsHeader; - -function MakeRefZW(zw, _basepath){ - _filetarget = zw["name"].replace("/config/", "/img_tmp/"); - _filetarget = _filetarget.replace(".jpg", "_org.jpg"); - url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out="+_filetarget+"&x=" + zw["x"] + "&y=" + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"]; - var xhttp = new XMLHttpRequest(); - try { - xhttp.open("GET", url, false); - xhttp.send(); } - catch (error) - { -// alert("Deleting Config.ini failed"); - } - _filetarget2 = zw["name"].replace("/config/", "/img_tmp/"); -// _filetarget2 = _filetarget2.replace(".jpg", "_org.jpg"); - FileCopyOnServer(_filetarget, _filetarget2, _basepath); -} - -function CopyReferenceToImgTmp(_basepath) -{ - for (index = 0; index < 2; ++index) - { - _filenamevon = ref[index]["name"]; - _filenamenach = _filenamevon.replace("/config/", "/img_tmp/"); - FileDeleteOnServer(_filenamenach, _basepath); - FileCopyOnServer(_filenamevon, _filenamenach, _basepath); - - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - FileDeleteOnServer(_filenamenach, _basepath); - FileCopyOnServer(_filenamevon, _filenamenach, _basepath); - } -} - -function GetReferencesInfo(){ - return ref; -} - -function ParseConfigAlignment(_aktline){ - var akt_ref = 0; - ++_aktline; - - while ((_aktline < config_split.length) - && !(config_split[_aktline][0] == "[") - && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { - var linesplit = ZerlegeZeile(config_split[_aktline]); - if ((linesplit[0].toUpperCase() == "INITIALMIRROR") && (linesplit.length > 1)) - { - initalrotate["mirror"] = linesplit[1].toUpperCase().localeCompare("TRUE") == 0; - initalrotate["pos_config_mirror"] = _aktline; - } - - if (((linesplit[0].toUpperCase() == "INITALROTATE") || (linesplit[0].toUpperCase() == "INITIALROTATE")) && (linesplit.length > 1)) - { - initalrotate["angle"] = parseInt(linesplit[1]); - initalrotate["pos_config"] = _aktline; - } - if (linesplit.length == 3) - { - ref[akt_ref] = new Object(); - ref[akt_ref]["pos_ref"] = _aktline; - ref[akt_ref]["name"] = linesplit[0]; - ref[akt_ref]["x"] = linesplit[1]; - ref[akt_ref]["y"] = linesplit[2]; - akt_ref++; - } - ++_aktline; - } - return _aktline; -} - -function ParseConfigDigit(_aktline){ - ++_aktline; - digit.length = 0; - - while ((_aktline < config_split.length) - && !(config_split[_aktline][0] == "[") - && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { - var linesplit = ZerlegeZeile(config_split[_aktline]); - if (linesplit.length >= 5) - { - zw = new Object(); - zw["pos_ref"] = _aktline; - zw["name"] = linesplit[0]; - zw["x"] = linesplit[1]; - zw["y"] = linesplit[2]; - zw["dx"] = linesplit[3]; - zw["dy"] = linesplit[4]; - zw["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); - digit.push(zw); - } - ++_aktline; - } - return _aktline; -} - -function GetAnalogEnabled() { - return analogEnabled; -} - - -function GetDigitsEnabled() { - return digitsEnabled; -} - - -function ParseConfigAnalog(_aktline){ - ++_aktline; - analog.length = 0; - - while ((_aktline < config_split.length) - && !(config_split[_aktline][0] == "[") - && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { - var linesplit = ZerlegeZeile(config_split[_aktline]); - if (linesplit.length >= 5) - { - zw = new Object(); - zw["pos_ref"] = _aktline; - zw["name"] = linesplit[0]; - zw["x"] = linesplit[1]; - zw["y"] = linesplit[2]; - zw["dx"] = linesplit[3]; - zw["dy"] = linesplit[4]; - zw["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); - analog.push(zw); - } - ++_aktline; - } - return _aktline; -} - - -function getROIInfo(_typeROI){ - if (_typeROI == "[Digits]"){ - targetROI = digit; - } - if (_typeROI == "[Analog]"){ - targetROI = analog; - } - return targetROI.slice(); // Kopie senden, nicht orginal!!! -} - -function SaveROIToConfig(_ROIInfo, _typeROI, _basepath, _enabled){ - if (_enabled) { - text = _typeROI; - } - else { - text = ";" + _typeROI; - } - - if (_typeROI == "[Digits]"){ - config_split[posDigitsHeader] = text; - targetROI = digit; - } - - if (_typeROI == "[Analog]"){ - config_split[posAnalogHeader] = text; - targetROI = analog; - } - - // Abstimmen Anzahl ROIs: - var _pos = targetROI[targetROI.length-1]["pos_ref"]; - - for (var i = targetROI.length; i < _ROIInfo.length; ++i){ - var zw = config_split[config_split.length-1]; - config_split.push(zw); - for (var j = config_split.length-2; j > _pos + 1; --j){ - config_split[j] = config_split[j-1]; - } - } - - for (i = targetROI.length-1; i > _ROIInfo.length-1; --i){ - var _zwpos = targetROI[i]["pos_ref"]; - config_split.splice(_zwpos, 1); - } - - var linewrite = 0; - for (i = 0; i < _ROIInfo.length; ++i){ - if (i < targetROI.length){ - linewrite = targetROI[i]["pos_ref"]; - } - else { - linewrite++; - } - config_split[linewrite] = _ROIInfo[i]["name"] + " " + _ROIInfo[i]["x"] + " " + _ROIInfo[i]["y"] + " " + _ROIInfo[i]["dx"] + " " + _ROIInfo[i]["dy"]; - } - - SaveConfigToServer(_basepath); -} - - -function ParseConfig() { - config_split = config_gesamt.split("\n"); - var aktline = 0; - - while (aktline < config_split.length){ - if ((config_split[aktline].trim().toUpperCase() == "[ALIGNMENT]") || (config_split[aktline].trim().toUpperCase() == ";[ALIGNMENT]")){ - aktline = ParseConfigAlignment(aktline); - continue; - } - if ((config_split[aktline].trim().toUpperCase() == "[DIGITS]") || (config_split[aktline].trim().toUpperCase() == ";[DIGITS]")){ - posDigitsHeader = aktline; - if (config_split[aktline][0] == "[") { - digitsEnabled = true; - } - aktline = ParseConfigDigit(aktline); - continue; - } - - if ((config_split[aktline].trim().toUpperCase() == "[ANALOG]") || (config_split[aktline].trim().toUpperCase() == ";[ANALOG]")) { - posAnalogHeader = aktline; - if (config_split[aktline][0] == "[") { - analogEnabled = true; - } - aktline = ParseConfigAnalog(aktline); - continue; - } - - aktline++; - } -} - -function getPreRotate(){ - return initalrotate["angle"]; -} - -function setPreRotate(_prerotate){ - initalrotate["angle"] = _prerotate; -} - -function getMirror(){ - if (initalrotate.hasOwnProperty("mirror")) { - return initalrotate["mirror"]; - } - return false; -} - -function setMirror(_mirror){ - initalrotate["mirror"] = _mirror; -} - -function SaveCanvasToImage(_canvas, _filename, _delete = true, _basepath = ""){ - var JPEG_QUALITY=0.8; - var dataUrl = _canvas.toDataURL('image/jpeg', JPEG_QUALITY); - var rtn = dataURLtoBlob(dataUrl); - - if (_delete) { - FileDeleteOnServer(_filename, _basepath); - } - - FileSendContent(rtn, _filename, _basepath); -} - -function SaveConfigToServer(_basepath){ - // leere Zeilen am Ende löschen - var zw = config_split.length - 1; - while (config_split[zw] == "") { - config_split.pop(); - } - - var config_gesamt = ""; - for (var i = 0; i < config_split.length; ++i) - { - config_gesamt = config_gesamt + config_split[i] + "\n"; - } - - FileDeleteOnServer("/config/config.ini", _basepath); - - FileSendContent(config_gesamt, "/config/config.ini", _basepath); -} - -function UpdateConfigFileReferenceChange(_basepath){ - for (var _index = 0; _index < ref.length; ++_index){ - var zeile = ref[_index]["name"] + " " + ref[_index]["x"] + " " + ref[_index]["y"]; - var _pos = ref[_index]["pos_ref"]; - config_split[_pos] = zeile; - } - - zeile = "InitialRotate = " + initalrotate["angle"]; - var _pos = initalrotate["pos_config"]; - config_split[_pos] = zeile; - - var mirror = false; - if (initalrotate.hasOwnProperty("mirror")) { - mirror = initalrotate["mirror"]; - } - var mirror_pos = -1; - if (initalrotate.hasOwnProperty("pos_config_mirror")) { - mirror_pos = initalrotate["pos_config_mirror"]; - } - if (mirror_pos > -1) { - if (mirror) { - config_split[mirror_pos] = "InitialMirror = true"; - } - else { - config_split[mirror_pos] = "InitialMirror = false"; - } - } - else { - if (mirror) { // neue Zeile muss an der richtigen Stelle eingefügt werden - hier direct nach [Alignment] - var aktline = 0; - - while (aktline < config_split.length){ - if (config_split[aktline].trim() == "[Alignment]") { - break; - } - aktline++ - } - - // fuege neue Zeile in config_split ein - var zw = config_split[config_split.length-1]; - config_split.push(zw); - for (var j = config_split.length-2; j > aktline + 1; --j){ - config_split[j] = config_split[j-1]; - } - - config_split[aktline + 1] = "InitialMirror = True" - } - } - - SaveConfigToServer(_basepath); -} - -function UpdateConfigReference(zw, _basepath){ - for (var index = 0; index < 2; ++index) - { - var zeile = zw[index]["name"] + " " + zw[index]["x"] + " " + zw[index]["y"]; - var _pos = zw[index]["pos_ref"]; - config_split[_pos] = zeile; - - _filenamenach = ref[index]["name"]; - _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); - FileDeleteOnServer(_filenamenach, _basepath); - FileCopyOnServer(_filenamevon, _filenamenach, _basepath); - - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - FileDeleteOnServer(_filenamenach, _basepath); - FileCopyOnServer(_filenamevon, _filenamenach, _basepath); - - } - - SaveConfigToServer(_basepath); -} - -function MakeContrastImageZW(zw, _enhance, _basepath){ - _filename = zw["name"].replace("/config/", "/img_tmp/"); - url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out=" + _filename + "&x=" + zw["x"] + "&y=" + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"]; - if (_enhance == true){ - url = url + "&enhance=true"; - } - - var xhttp = new XMLHttpRequest(); - try { - xhttp.open("GET", url, false); - xhttp.send(); } - catch (error) - { -// alert("Deleting Config.ini failed"); - } -} - - -function GetReferenceSize(name){ - img = new Image(); - var xhttp = new XMLHttpRequest(); - - url = "http://192.168.178.22/fileserver" + name; - xhttp.open("GET", url, false); - xhttp.send(); - - var response = xhttp.responseText; - var binary = "" - - for (var responseText = xhttp.responseText, responseTextLen = responseText.length, binary = "", i = 0; i < responseTextLen; ++i) { - binary += String.fromCharCode(responseText.charCodeAt(i) & 255) - } - img.src = 'data:image/jpeg;base64,'+ window.btoa(binary); - - return [img.width, img.height]; -} - - -function getConfig() { - return config_gesamt; - } - - - -function dataURLtoBlob(dataurl) { - var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], - bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); - while(n--){ - u8arr[n] = bstr.charCodeAt(n); - } - return new Blob([u8arr], {type:mime}); - } - - -function SaveReferenceImage(_id_canvas, _filename, _doDelete, _basepath = ""){ - if (_doDelete){ - FileDeleteOnServer(_filename, _basepath); - } - - var canvas = document.getElementById(_id_canvas); - var JPEG_QUALITY=0.8; - var dataUrl = canvas.toDataURL('image/jpeg', JPEG_QUALITY); - var rtn = dataURLtoBlob(dataUrl); - if (!FileSendContent(rtn, _filename, _basepath)){ - alert("Error on saving reference image (" + _filename + ")!\nPlease retry."); - location.reload(); - }; -} diff --git a/sd-card/html/readconfigcommon.js b/sd-card/html/readconfigcommon.js index f2165dc8..f384cd0c 100644 --- a/sd-card/html/readconfigcommon.js +++ b/sd-card/html/readconfigcommon.js @@ -20,65 +20,7 @@ function SaveConfigToServer(_basepath){ FileSendContent(config_gesamt, "/config/config.ini", _basepath); } -function UpdateConfigFileReferenceChange(_basepath){ - for (var _index = 0; _index < ref.length; ++_index){ - var zeile = ref[_index]["name"] + " " + ref[_index]["x"] + " " + ref[_index]["y"]; - var _pos = ref[_index]["pos_ref"]; - config_split[_pos] = zeile; - } - - zeile = "InitialRotate = " + initalrotate["angle"]; - var _pos = initalrotate["pos_config"]; - config_split[_pos] = zeile; - - var mirror = false; - if (initalrotate.hasOwnProperty("mirror")) { - mirror = initalrotate["mirror"]; - } - var mirror_pos = -1; - if (initalrotate.hasOwnProperty("pos_config_mirror")) { - mirror_pos = initalrotate["pos_config_mirror"]; - } - if (mirror_pos > -1) { - if (mirror) { - config_split[mirror_pos] = "InitialMirror = true"; - } - else { - config_split[mirror_pos] = "InitialMirror = false"; - } - } - else { - if (mirror) { // neue Zeile muss an der richtigen Stelle eingefügt werden - hier direct nach [Alignment] - var aktline = 0; - - while (aktline < config_split.length){ - if (config_split[aktline].trim() == "[Alignment]") { - break; - } - aktline++ - } - - // fuege neue Zeile in config_split ein - var zw = config_split[config_split.length-1]; - config_split.push(zw); - for (var j = config_split.length-2; j > aktline + 1; --j){ - config_split[j] = config_split[j-1]; - } - - config_split[aktline + 1] = "InitialMirror = True" - } - } - - SaveConfigToServer(_basepath); -} - function UpdateConfig(zw, _index, _enhance, _basepath){ - var zeile = zw["name"] + " " + zw["x"] + " " + zw["y"]; - var _pos = ref[_index]["pos_ref"]; - config_split[_pos] = zeile; - - SaveConfigToServer(_basepath); - var namezw = zw["name"]; FileCopyOnServer("/img_tmp/ref_zw.jpg", namezw, _basepath); var namezw = zw["name"].replace(".jpg", "_org.jpg"); @@ -102,10 +44,10 @@ function createReader(file) { -function ZerlegeZeile(input) +function ZerlegeZeile(input, delimiter = " =\t\r") { var Output = Array(0); - delimiter = " =,\r"; +// delimiter = " =,\t"; input = trim(input, delimiter); var pos = findDelimiterPos(input, delimiter); @@ -164,6 +106,11 @@ function trim(istring, adddelimiter) } +function getConfig() +{ + return config_gesamt; +} + function loadConfig(_basepath) { var xhttp = new XMLHttpRequest(); @@ -261,4 +208,54 @@ function FileSendContent(_content, _filename, _basepath = ""){ // alert("Deleting Config.ini failed"); } return okay; -} \ No newline at end of file +} + + +function SaveCanvasToImage(_canvas, _filename, _delete = true, _basepath = ""){ + var JPEG_QUALITY=0.8; + var dataUrl = _canvas.toDataURL('image/jpeg', JPEG_QUALITY); + var rtn = dataURLtoBlob(dataUrl); + + if (_delete) { + FileDeleteOnServer(_filename, _basepath); + } + + FileSendContent(rtn, _filename, _basepath); +} + +function MakeContrastImageZW(zw, _enhance, _basepath){ + _filename = zw["name"].replace("/config/", "/img_tmp/"); + url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out=" + _filename + "&x=" + zw["x"] + "&y=" + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"]; + if (_enhance == true){ + url = url + "&enhance=true"; + } + + var xhttp = new XMLHttpRequest(); + try { + xhttp.open("GET", url, false); + xhttp.send(); } + catch (error) + { +// alert("Deleting Config.ini failed"); + } +} + + + +function MakeRefZW(zw, _basepath){ + _filetarget = zw["name"].replace("/config/", "/img_tmp/"); + _filetarget = _filetarget.replace(".jpg", "_org.jpg"); + url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out="+_filetarget+"&x=" + zw["x"] + "&y=" + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"]; + var xhttp = new XMLHttpRequest(); + try { + xhttp.open("GET", url, false); + xhttp.send(); } + catch (error) + { +// alert("Deleting Config.ini failed"); + } + _filetarget2 = zw["name"].replace("/config/", "/img_tmp/"); +// _filetarget2 = _filetarget2.replace(".jpg", "_org.jpg"); + FileCopyOnServer(_filetarget, _filetarget2, _basepath); +} + diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index af7a0d00..047fba65 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -7,6 +7,8 @@ var config_split; var param; var category; var ref = new Array(2); +var NUMBERS = new Array(0); +var REFERENCES = new Array(0); function ParseConfig() { config_split = config_gesamt.split("\n"); @@ -68,11 +70,11 @@ function ParseConfig() { category[catname]["enabled"] = false; category[catname]["found"] = false; param[catname] = new Object(); - ParamAddValue(param, catname, "DecimalShift"); + ParamAddValue(param, catname, "DecimalShift", 1, true); ParamAddValue(param, catname, "PreValueUse"); ParamAddValue(param, catname, "PreValueAgeStartup"); ParamAddValue(param, catname, "AllowNegativeRates"); - ParamAddValue(param, catname, "MaxRateValue"); + ParamAddValue(param, catname, "MaxRateValue", 1, true); ParamAddValue(param, catname, "ErrorMessage"); ParamAddValue(param, catname, "CheckDigitIncreaseConsistency"); @@ -82,13 +84,23 @@ function ParseConfig() { category[catname]["found"] = false; param[catname] = new Object(); ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "Topic"); - ParamAddValue(param, catname, "TopicError"); - ParamAddValue(param, catname, "TopicRate"); - ParamAddValue(param, catname, "TopicTimeStamp"); + ParamAddValue(param, catname, "MainTopic", 1, false, [/^([a-zA-Z0-9_-]+\/){0,10}[a-zA-Z0-9_-]+$/]); ParamAddValue(param, catname, "ClientID"); ParamAddValue(param, catname, "user"); - ParamAddValue(param, catname, "password"); + ParamAddValue(param, catname, "password"); + + var catname = "GPIO"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "MainTopicMQTT", 1, false, [/^([a-zA-Z0-9_-]+\/){0,10}[a-zA-Z0-9_-]+$/]); + ParamAddValue(param, catname, "IO0", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO1", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO3", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO4", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO12", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO13", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); var catname = "AutoTimer"; category[catname] = new Object(); @@ -115,8 +127,9 @@ function ParseConfig() { ParamAddValue(param, catname, "TimeServer"); ParamAddValue(param, catname, "AutoAdjustSummertime"); ParamAddValue(param, catname, "Hostname"); - ParamAddValue(param, catname, "SetupMode"); - + ParamAddValue(param, catname, "SetupMode"); + + while (aktline < config_split.length){ for (var cat in category) { zw = cat.toUpperCase(); @@ -136,16 +149,16 @@ function ParseConfig() { } } -function ParamAddValue(param, _cat, _param, _anzParam = 1){ +function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _checkRegExList = null){ param[_cat][_param] = new Object(); param[_cat][_param]["found"] = false; param[_cat][_param]["enabled"] = false; param[_cat][_param]["line"] = -1; - param[_cat][_param]["anzParam"] = _anzParam; + param[_cat][_param]["anzParam"] = _anzParam; + param[_cat][_param]["Numbers"] = _isNUMBER; + param[_cat][_param].checkRegExList = _checkRegExList; }; - - function ParseConfigParamAll(_aktline, _catname){ ++_aktline; @@ -156,6 +169,18 @@ function ParseConfigParamAll(_aktline, _catname){ let [isCom, input] = isCommented(_input); var linesplit = ZerlegeZeile(input); ParamExtractValueAll(param, linesplit, _catname, _aktline, isCom); + if (!isCom && (linesplit.length == 5) && (_catname == 'Digits')) + ExtractROIs(input, "digit"); + if (!isCom && (linesplit.length == 5) && (_catname == 'Analog')) + ExtractROIs(input, "analog"); + if (!isCom && (linesplit.length == 3) && (_catname == 'Alignment')) + { + _newref = new Object(); + _newref["name"] = linesplit[0]; + _newref["x"] = linesplit[1]; + _newref["y"] = linesplit[2]; + REFERENCES.push(_newref); + } ++_aktline; } @@ -177,14 +202,59 @@ function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _ function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom){ for (var paramname in _param[_catname]) { - if ((_linesplit[0].toUpperCase() == paramname.toUpperCase()) && (_linesplit.length > _param[_catname][paramname]["anzParam"])) + _AktROI = "default"; + _AktPara = _linesplit[0]; + _pospunkt = _AktPara.indexOf ("."); + if (_pospunkt > -1) { + _AktROI = _AktPara.substring(0, _pospunkt); + _AktPara = _AktPara.substring(_pospunkt+1); + } + if (_AktPara.toUpperCase() == paramname.toUpperCase()) + { + while (_linesplit.length <= _param[_catname][paramname]["anzParam"]) { + _linesplit.push(""); + } + _param[_catname][paramname]["found"] = true; _param[_catname][paramname]["enabled"] = !_iscom; _param[_catname][paramname]["line"] = _aktline; - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - _param[_catname][paramname]["value"+j] = _linesplit[j]; + if (_param[_catname][paramname]["Numbers"] == true) // möglicher Multiusage + { + abc = getNUMBERS(_linesplit[0]); + abc[_catname][paramname] = new Object; + abc[_catname][paramname]["found"] = true; + abc[_catname][paramname]["enabled"] = !_iscom; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + abc[_catname][paramname]["value"+j] = _linesplit[j]; + } + if (abc["name"] == "default") + { + for (_num in NUMBERS) // wert mit Default belegen + { + if (NUMBERS[_num][_catname][paramname]["found"] == false) + { + NUMBERS[_num][_catname][paramname]["found"] = true; + NUMBERS[_num][_catname][paramname]["enabled"] = !_iscom; + NUMBERS[_num][_catname][paramname]["line"] = _aktline; + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + NUMBERS[_num][_catname][paramname]["value"+j] = _linesplit[j]; + } + + } + } } + } + else + { + _param[_catname][paramname]["found"] = true; + _param[_catname][paramname]["enabled"] = !_iscom; + _param[_catname][paramname]["line"] = _aktline; + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + _param[_catname][paramname]["value"+j] = _linesplit[j]; + } + } } } } @@ -193,54 +263,114 @@ function getConfigParameters() { return param; } -function setConfigParameters(_param, _category = "") { - for (var cat in _param) { - for (var name in _param[cat]) { - param[cat][name]["found"] = _param[cat][name]["found"]; - param[cat][name]["enabled"] = _param[cat][name]["enabled"]; - param[cat][name]["line"] = _param[cat][name]["line"]; +function WriteConfigININew() +{ + // Cleanup empty NUMBERS + for (var j = 0; j < NUMBERS.length; ++j) + { + if ((NUMBERS[j]["digit"].length + NUMBERS[j]["analog"].length) == 0) + { + NUMBERS.splice(j, 1); + } + } - param[cat][name]["anzParam"] = _param[cat][name]["anzParam"]; - for (var j = 1; j <= _param[cat][name]["anzParam"]; ++j) { - param[cat][name]["value"+j] = _param[cat][name]["value"+j]; + + + config_split = new Array(0); + + for (var cat in param) { + text = "[" + cat + "]"; + if (!category[cat]["enabled"]) { + text = ";" + text; + } + config_split.push(text); + + for (var name in param[cat]) { + if (param[cat][name]["Numbers"]) + { + for (_num in NUMBERS) + { + text = NUMBERS[_num]["name"] + "." + name; + + var text = text + " =" + + for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { + if (!(typeof NUMBERS[_num][cat][name]["value"+j] == 'undefined')) + text = text + " " + NUMBERS[_num][cat][name]["value"+j]; + } + if (!NUMBERS[_num][cat][name]["enabled"]) { + text = ";" + text; + } + config_split.push(text); } - - if (param[cat][name]["found"]) { + } + else + { var text = name + " =" - for (var j = 1; j <= _param[cat][name]["anzParam"]; ++j) { - text = text + " " + param[cat][name]["value"+j]; + for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { + if (!(typeof param[cat][name]["value"+j] == 'undefined')) + text = text + " " + param[cat][name]["value"+j]; } if (!param[cat][name]["enabled"]) { text = ";" + text; } - config_split[param[cat][name]["line"]] = text; + config_split.push(text); } } - } - - for (var cat in _category) { - if (category[cat]["found"]) + if (cat == "Digits") { - category[cat]["enabled"] = _category[cat]["enabled"]; - text = "[" + cat + "]"; - if (!category[cat]["enabled"]) { - text = ";" + text; + for (var _roi in NUMBERS) + { + if (NUMBERS[_roi]["digit"].length > 0) + { + for (var _roiddet in NUMBERS[_roi]["digit"]) + { + text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["digit"][_roiddet]["name"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["x"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["y"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dx"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dy"]; + config_split.push(text); + } + } + } + } + if (cat == "Analog") + { + for (var _roi in NUMBERS) + { + if (NUMBERS[_roi]["analog"].length > 0) + { + for (var _roiddet in NUMBERS[_roi]["analog"]) + { + text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["analog"][_roiddet]["name"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["x"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["y"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dx"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dy"]; + config_split.push(text); + } + } + } + } + if (cat == "Alignment") + { + for (var _roi in REFERENCES) + { + text = REFERENCES[_roi]["name"]; + text = text + " " + REFERENCES[_roi]["x"]; + text = text + " " + REFERENCES[_roi]["y"]; + config_split.push(text); } - config_split[category[cat]["line"]] = text; - } - } - - config_gesamt = config_split[0]; - for (var i = 1; i < config_split.length; ++i){ - config_gesamt = config_gesamt + "\n" + config_split[i]; - } - return config_gesamt; + config_split.push(""); + } } + function isCommented(input) { let isComment = false; @@ -275,6 +405,271 @@ function getConfig() { function getConfigCategory() { return category; } + + + +function ExtractROIs(_aktline, _type){ + var linesplit = ZerlegeZeile(_aktline); + abc = getNUMBERS(linesplit[0], _type); + abc["pos_ref"] = _aktline; + abc["x"] = linesplit[1]; + abc["y"] = linesplit[2]; + abc["dx"] = linesplit[3]; + abc["dy"] = linesplit[4]; + abc["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); +} + + +function getNUMBERS(_name, _type, _create = true) +{ + _pospunkt = _name.indexOf ("."); + if (_pospunkt > -1) + { + _digit = _name.substring(0, _pospunkt); + _roi = _name.substring(_pospunkt+1); + } + else + { + _digit = "default"; + _roi = _name; + } + + _ret = -1; + + for (i = 0; i < NUMBERS.length; ++i) + { + if (NUMBERS[i]["name"] == _digit) + _ret = NUMBERS[i]; + } + + if (!_create) // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück + return _ret; + + if (_ret == -1) + { + _ret = new Object(); + _ret["name"] = _digit; + _ret['digit'] = new Array(); + _ret['analog'] = new Array(); + + for (_cat in param) + for (_param in param[_cat]) + if (param[_cat][_param]["Numbers"] == true){ + if (typeof _ret[_cat] == 'undefined') + _ret[_cat] = new Object(); + _ret[_cat][_param] = new Object(); + _ret[_cat][_param]["found"] = false; + _ret[_cat][_param]["enabled"] = false; + _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; + + } + + NUMBERS.push(_ret); + } + + if (typeof _type == 'undefined') // muss schon existieren !!! - also erst nach Digits / Analog aufrufen + return _ret; + + neuroi = new Object(); + neuroi["name"] = _roi; + _ret[_type].push(neuroi); + + + return neuroi; + +} + + + +function CopyReferenceToImgTmp(_basepath) +{ + for (index = 0; index < 2; ++index) + { + _filenamevon = REFERENCES[index]["name"]; + _filenamenach = _filenamevon.replace("/config/", "/img_tmp/"); + FileDeleteOnServer(_filenamenach, _basepath); + FileCopyOnServer(_filenamevon, _filenamenach, _basepath); + + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + FileDeleteOnServer(_filenamenach, _basepath); + FileCopyOnServer(_filenamevon, _filenamenach, _basepath); + } +} + +function GetReferencesInfo(){ + return REFERENCES; +} + + +function UpdateConfigReference(_basepath){ + for (var index = 0; index < 2; ++index) + { + _filenamenach = REFERENCES[index]["name"]; + _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); + FileDeleteOnServer(_filenamenach, _basepath); + FileCopyOnServer(_filenamevon, _filenamenach, _basepath); + + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + FileDeleteOnServer(_filenamenach, _basepath); + FileCopyOnServer(_filenamevon, _filenamenach, _basepath); + + } +} + + +function getNUMBERInfo(){ + return NUMBERS; +} + +function RenameNUMBER(_alt, _neu){ + index = -1; + found = false; + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _alt) + index = i; + if (NUMBERS[i]["name"] == _neu) + found = true; + } + + if (found) + return "Name is already existing - please use another name"; + + NUMBERS[index]["name"] = _neu; + + return ""; +} + +function DeleteNUMBER(_delte){ + if (NUMBERS.length == 1) + return "The last number cannot be deleted." + index = -1; + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _delte) + index = i; + } + if (index > -1) { + NUMBERS.splice(index, 1); + } + + return ""; +} + +function CreateNUMBER(_numbernew){ + found = false; + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _numbernew) + found = true; + } + + if (found) + return "Name does already exist, please choose another one!"; + + _ret = new Object(); + _ret["name"] = _numbernew; + _ret['digit'] = new Array(); + _ret['analog'] = new Array(); + + for (_cat in param) + for (_param in param[_cat]) + if (param[_cat][_param]["Numbers"] == true) + { + if (typeof (_ret[_cat]) === "undefined") + { + _ret[_cat] = new Object(); + } + _ret[_cat][_param] = new Object(); + _ret[_cat][_param]["found"] = false; + _ret[_cat][_param]["enabled"] = false; + _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; + + } + + NUMBERS.push(_ret); + return ""; +} + + +function getROIInfo(_typeROI, _number){ + index = 0; + for (var i = 0; i < NUMBERS.length; ++i) + if (NUMBERS[i]["name"] == _number) + index = i; + + return NUMBERS[index][_typeROI]; +} + + +function RenameROI(_number, _type, _alt, _neu){ + index = -1; + found = false; + _indexnumber = -1; + for (j = 0; j < NUMBERS.length; ++j) + if (NUMBERS[j]["name"] == _number) + _indexnumber = j; + + for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { + if (NUMBERS[_indexnumber][_type][i]["name"] == _alt) + index = i; + if (NUMBERS[_indexnumber][_type][i]["name"] == _neu) + found = true; + } + + if (found) + return "Name is already existing - please use another name"; + + NUMBERS[_indexnumber][_type][index]["name"] = _neu; + + return ""; +} + +function DeleteNUMBER(_delte){ + if (NUMBERS.length == 1) + return "The last number cannot be deleted." + + + index = -1; + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _delte) + index = i; + } + + if (index > -1) { + NUMBERS.splice(index, 1); + } + + return ""; +} + +function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy){ + _indexnumber = -1; + for (j = 0; j < NUMBERS.length; ++j) + if (NUMBERS[j]["name"] == _number) + _indexnumber = j; + + + found = false; + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[_indexnumber][_type]["name"] == _roinew) + found = true; + } + + if (found) + return "ROI does already exist, please choose another name!"; + + _ret = new Object(); + _ret["name"] = _roinew; + _ret["x"] = _x; + _ret["y"] = _y; + _ret["dx"] = _dx; + _ret["dy"] = _dy; + _ret["ar"] = _dx / _dy; + + NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret); + + return ""; +} \ No newline at end of file diff --git a/sd-card/html/sd-card - Verknüpfung.lnk b/sd-card/html/sd-card - Verknüpfung.lnk deleted file mode 100644 index 4c6bfce3..00000000 Binary files a/sd-card/html/sd-card - Verknüpfung.lnk and /dev/null differ diff --git a/sd-card/html/test.html b/sd-card/html/test.html new file mode 100644 index 00000000..5cd12021 --- /dev/null +++ b/sd-card/html/test.html @@ -0,0 +1,32 @@ + + + + + + + + testschrift +
+ + + + + + diff --git a/sd-card/html/version.txt b/sd-card/html/version.txt index e029aa99..d223b451 100644 --- a/sd-card/html/version.txt +++ b/sd-card/html/version.txt @@ -1 +1 @@ -6.8.0 +9.5.0 diff --git a/sd-card/html/wasserzaehler_roi.html b/sd-card/html/wasserzaehler_roi.html index d12cbe64..322c74fb 100644 --- a/sd-card/html/wasserzaehler_roi.html +++ b/sd-card/html/wasserzaehler_roi.html @@ -7,7 +7,7 @@