diff --git a/README.md b/README.md index 049be878..24b55ffd 100644 --- a/README.md +++ b/README.md @@ -19,13 +19,30 @@ A 3d-printable housing can be found here: https://www.thingiverse.com/thing:4571 ### Known Issues -* Reboot on extensive web access due to the limits of the internal web server +* Spontaneous reboots, most probably due to weak power supply during power intensive operations (taking / calculating pictures) ------ **General remark:** Beside the `firmware.bin`, typically also the content of `/html` needs to be updated! -##### Rolling - (2020-12-07) +##### Rolling - (2020-12-27) + +* Major change: no need of SD card for image processing anymore (all in memory) + * 95% less SD card writing + * SD use: mainly reading of data (config, html, tflite parameters), only log files and prevalue write on SD card anymore + * Need to limit camera resolution to VGA (due to memory limits) +* New Feature: setting of time server in `config.ini` + + ``` + [System] + TimeServer = fritz.box + ``` + +* Bug fix: corrected handling of out commented analog pointer ROIs + + +2020-12-07 + * Improvement: internal file handling diff --git a/code/components/connect_wlan/connect_wlan.cpp b/code/components/connect_wlan/connect_wlan.cpp index 81b144e7..1af2bf63 100644 --- a/code/components/connect_wlan/connect_wlan.cpp +++ b/code/components/connect_wlan/connect_wlan.cpp @@ -270,37 +270,6 @@ void LoadWlanFromFile(std::string fn, std::string &_ssid, std::string &_passphra } } -/* - if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "IP")){ - _ip = zerlegt[1]; - if ((_ip[0] == '"') && (_ip[_ip.length()-1] == '"')){ - _ip = _ip.substr(1, _ip.length()-2); - } - } - - if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "GATEWAY")){ - _gw = zerlegt[1]; - if ((_gw[0] == '"') && (_gw[_gw.length()-1] == '"')){ - _gw = _gw.substr(1, _gw.length()-2); - } - } - - if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "NETMASK")){ - _netmask = zerlegt[1]; - if ((_netmask[0] == '"') && (_netmask[_netmask.length()-1] == '"')){ - _netmask = _netmask.substr(1, _netmask.length()-2); - } - } - - if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "DNS")){ - _dns = zerlegt[1]; - if ((_dns[0] == '"') && (_dns[_dns.length()-1] == '"')){ - _dns = _dns.substr(1, _dns.length()-2); - } - } -*/ - - if (fgets(zw, 1024, pFile) == NULL) { line = ""; diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 9a1a4bc3..11af89d5 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -1,4 +1,5 @@ #include "ClassControllCamera.h" +#include "ClassLogFile.h" #include #include "driver/gpio.h" @@ -6,34 +7,11 @@ #include "esp_log.h" #include "Helper.h" -#include "CFindTemplate.h" +#include "CImageBasis.h" -// #include "camera_define.h" -///////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////// #define BOARD_ESP32CAM_AITHINKER -/** - * 2. Kconfig setup - * - * If you have a Kconfig file, copy the content from - * https://github.com/espressif/esp32-camera/blob/master/Kconfig into it. - * In case you haven't, copy and paste this Kconfig file inside the src directory. - * This Kconfig file has definitions that allows more control over the camera and - * how it will be initialized. - */ - -/** - * 3. Enable PSRAM on sdkconfig: - * - * CONFIG_ESP32_SPIRAM_SUPPORT=y - * - * More info on - * https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support - */ - -// ================================ CODE ====================================== #include #include @@ -47,31 +25,8 @@ #include "esp_camera.h" -// WROVER-KIT PIN Map -#ifdef BOARD_WROVER_KIT - -#define CAM_PIN_PWDN -1 //power down is not used -#define CAM_PIN_RESET -1 //software reset will be performed -#define CAM_PIN_XCLK 21 -#define CAM_PIN_SIOD 26 -#define CAM_PIN_SIOC 27 - -#define CAM_PIN_D7 35 -#define CAM_PIN_D6 34 -#define CAM_PIN_D5 39 -#define CAM_PIN_D4 36 -#define CAM_PIN_D3 19 -#define CAM_PIN_D2 18 -#define CAM_PIN_D1 5 -#define CAM_PIN_D0 4 -#define CAM_PIN_VSYNC 25 -#define CAM_PIN_HREF 23 -#define CAM_PIN_PCLK 22 - -#endif // ESP32Cam (AiThinker) PIN Map -#ifdef BOARD_ESP32CAM_AITHINKER #define CAM_PIN_PWDN (gpio_num_t) 32 #define CAM_PIN_RESET -1 //software reset will be performed @@ -91,8 +46,6 @@ #define CAM_PIN_HREF 23 #define CAM_PIN_PCLK 22 -#endif - static const char *TAG = "example:take_picture"; static camera_config_t camera_config = { @@ -120,7 +73,8 @@ static camera_config_t camera_config = { .ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG, //YUV422,GRAYSCALE,RGB565,JPEG - .frame_size = FRAMESIZE_UXGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG + .frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG +// .frame_size = FRAMESIZE_UXGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG @@ -128,14 +82,11 @@ static camera_config_t camera_config = { .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG }; -///////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////// #include "driver/ledc.h" CCamera Camera; - #define FLASH_GPIO GPIO_NUM_4 #define BLINK_GPIO GPIO_NUM_33 @@ -145,8 +96,6 @@ typedef struct { } jpg_chunking_t; - -/////////////////////////////////////////////////////////////////////////////////////////////////////// #define LEDC_LS_CH2_GPIO (4) #define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2 #define LEDC_LS_TIMER LEDC_TIMER_1 @@ -172,14 +121,6 @@ void test(){ - -//////////////////////////////////////////////////////////////////////////////////////////////////////// - - - - - - static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ jpg_chunking_t *j = (jpg_chunking_t *)arg; if(!index){ @@ -200,12 +141,157 @@ void CCamera::SetQualitySize(int qual, framesize_t resol) s->set_framesize(s, resol); ActualResolution = resol; ActualQuality = qual; + + if (resol == FRAMESIZE_QVGA) + { + image_height = 240; + image_width = 320; + } + if (resol == FRAMESIZE_VGA) + { + image_height = 480; + image_width = 640; + } + // No higher Mode than VGA, damit der Kameraspeicher ausreicht. +/* + if (resol == FRAMESIZE_SVGA) + { + image_height = 600; + image_width = 800; + } + if (resol == FRAMESIZE_XGA) + { + image_height = 768; + image_width = 1024; + } + if (resol == FRAMESIZE_SXGA) + { + image_height = 1024; + image_width = 1280; + } + if (resol == FRAMESIZE_UXGA) + { + image_height = 1200; + image_width = 1600; + } +*/ +} + + +esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) +{ + string ftype; + static const int BMP_HEADER_LEN = 54; // von to_bmp.c !!!!!!!!!!!!!!! + + LEDOnOff(true); + +// if (debug_detail_heap) LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Start"); + + if (delay > 0) + { + LightOnOff(true); + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay( xDelay ); + } + +// if (debug_detail_heap) LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LightOn"); + + camera_fb_t * fb = esp_camera_fb_get(); + if (!fb) { + ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed"); + LEDOnOff(false); + return ESP_FAIL; + } + +// if (debug_detail_heap) LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After fb_get"); + + LEDOnOff(false); + + + if (delay > 0) + { + LightOnOff(false); + } + + + TickType_t xDelay = 1000 / portTICK_PERIOD_MS; + vTaskDelay( xDelay ); // wait for power to recover + + uint8_t * buf = NULL; + size_t buf_len = 0; + + int _anz = 0; + xDelay = 3000 / portTICK_PERIOD_MS; + + while (!frame2bmp(fb, &buf, &buf_len) && _anz < 5) + { + std::string _zw1 = "CCamera::CaptureToBasisImage failed #" + std::to_string(++_anz); + LogFile.WriteToFile(_zw1); + + esp_camera_fb_return(fb); + _zw1 = "CCamera::CaptureToBasisImage failed #" + std::to_string(_anz) + " - after esp_camera_fb_return"; + LogFile.WriteToFile(_zw1); + free(buf); + + _zw1 = "CCamera::CaptureToBasisImage failed #" + std::to_string(_anz) + " - after free"; + LogFile.WriteToFile(_zw1); + + InitCam(); + + _zw1 = "CCamera::CaptureToBasisImage failed #" + std::to_string(_anz) + " - after InitCam"; + LogFile.WriteToFile(_zw1); + + vTaskDelay( xDelay ); + fb = esp_camera_fb_get(); + + _zw1 = "CCamera::CaptureToBasisImage failed #" + std::to_string(_anz) + " - after esp_camera_fb_get"; + LogFile.WriteToFile(_zw1); + + } + + + esp_camera_fb_return(fb); + + if (debug_detail_heap) LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After frame2bmp"); + + int _len_zw = buf_len - BMP_HEADER_LEN; + uint8_t *_buf_zeiger = buf + BMP_HEADER_LEN; + + stbi_uc* p_target; + stbi_uc* p_source; + int channels = 3; + int width = image_width; + int height = image_height; + + std::string _zw = "Targetimage: " + std::to_string((int) _Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height); + _zw = _zw + " Buf: " + std::to_string((int) buf); + + if (debug_detail_heap) LogFile.WriteToFile(_zw); + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + p_target = _Image->rgb_image + (channels * (y * width + x)); + p_source = _buf_zeiger + (channels * (y * width + x)); + p_target[0] = p_source[2]; + p_target[1] = p_source[1]; + p_target[2] = p_source[0]; + } + + if (debug_detail_heap) LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After Copy To Target"); + +// _Image->CopyFromMemory(_buf_zeiger, _len_zw); + + free(buf); + + if (debug_detail_heap) LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Done"); + + return ESP_OK; } esp_err_t CCamera::CaptureToFile(std::string nm, int delay) { -// nm = "/sdcard/josef_zw.bmp"; string ftype; LEDOnOff(true); @@ -286,15 +372,29 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) size_t fb_len = 0; int64_t fr_start = esp_timer_get_time(); + + LEDOnOff(true); + + if (delay > 0) + { + LightOnOff(true); + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay( xDelay ); + } + + fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAGCAMERACLASS, "Camera capture failed"); httpd_resp_send_500(req); return ESP_FAIL; } + + LEDOnOff(false); + res = httpd_resp_set_type(req, "image/jpeg"); if(res == ESP_OK){ - res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg"); + res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=raw.jpg"); } if(res == ESP_OK){ @@ -312,6 +412,12 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) int64_t fr_end = esp_timer_get_time(); ESP_LOGI(TAGCAMERACLASS, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000)); + + if (delay > 0) + { + LightOnOff(false); + } + return res; } @@ -369,7 +475,7 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol if (strcmp(_size, "SXGA") == 0) resol = FRAMESIZE_SXGA; // 1280x1024 if (strcmp(_size, "UXGA") == 0) - resol = FRAMESIZE_UXGA; // 1600x1200 + resol = FRAMESIZE_UXGA; // 1600x1200 } if (httpd_query_key_value(_query, "quality", _qual, 10) == ESP_OK) { @@ -409,8 +515,6 @@ CCamera::CCamera() esp_err_t CCamera::InitCam() { - printf("Init Flash\n"); - //power up the camera if PWDN pin is defined if(CAM_PIN_PWDN != -1){ // Init the GPIO gpio_pad_select_gpio(CAM_PIN_PWDN); diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index 7ccfae19..702bc286 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -10,12 +10,13 @@ #include "esp_camera.h" #include #include +#include "CImageBasis.h" #define CAMERA_MODEL_AI_THINKER -static const char *TAGCAMERACLASS = "server_part_camera"; +static const char *TAGCAMERACLASS = "server_part_camera"; class CCamera { @@ -24,6 +25,8 @@ class CCamera { framesize_t ActualResolution; public: + int image_height, image_width; + CCamera(); esp_err_t InitCam(); @@ -35,13 +38,13 @@ class CCamera { framesize_t TextToFramesize(const char * text); - esp_err_t CaptureToFile(std::string nm, int delay = 0); - + esp_err_t CaptureToBasisImage(CImageBasis *_Image, int delay = 0); }; extern CCamera Camera; +extern bool debug_detail_heap; #endif \ No newline at end of file diff --git a/code/components/jomjol_controlcamera/server_camera.cpp b/code/components/jomjol_controlcamera/server_camera.cpp index 0904ea48..e7157f44 100644 --- a/code/components/jomjol_controlcamera/server_camera.cpp +++ b/code/components/jomjol_controlcamera/server_camera.cpp @@ -29,26 +29,38 @@ void PowerResetCamera(){ esp_err_t handler_lightOn(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_lightOn - Start"); + LogFile.WriteToFile("handler_lightOn"); printf("handler_lightOn uri:\n"); printf(req->uri); printf("\n"); Camera.LightOnOff(true); const char* resp_str = (const char*) req->user_ctx; - httpd_resp_send(req, resp_str, strlen(resp_str)); + httpd_resp_send(req, resp_str, strlen(resp_str)); + + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_lightOn - Done"); + return ESP_OK; }; esp_err_t handler_lightOff(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_lightOff - Start"); + LogFile.WriteToFile("handler_lightOff"); printf("handler_lightOff uri:\n"); printf(req->uri); printf("\n"); Camera.LightOnOff(false); const char* resp_str = (const char*) req->user_ctx; httpd_resp_send(req, resp_str, strlen(resp_str)); + + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_lightOff - Done"); + return ESP_OK; }; esp_err_t handler_capture(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_capture - Start"); + LogFile.WriteToFile("handler_capture"); int quality; framesize_t res; @@ -59,12 +71,17 @@ esp_err_t handler_capture(httpd_req_t *req) esp_err_t ressult; ressult = Camera.CaptureToHTTP(req); + + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_capture - Done"); + return ressult; }; esp_err_t handler_capture_with_ligth(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_capture_with_ligth - Start"); + LogFile.WriteToFile("handler_capture_with_ligth"); char _query[100]; char _delay[10]; @@ -98,6 +115,8 @@ esp_err_t handler_capture_with_ligth(httpd_req_t *req) ressult = Camera.CaptureToHTTP(req); Camera.LightOnOff(false); + + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_capture_with_ligth - Done"); return ressult; }; @@ -106,6 +125,8 @@ esp_err_t handler_capture_with_ligth(httpd_req_t *req) esp_err_t handler_capture_save_to_file(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_capture_save_to_file - Start"); + LogFile.WriteToFile("handler_capture_save_to_file"); char _query[100]; char _delay[10]; @@ -151,6 +172,8 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req) const char* resp_str = (const char*) fn.c_str(); httpd_resp_send(req, resp_str, strlen(resp_str)); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_capture_save_to_file - Done"); + return ressult; }; diff --git a/code/components/jomjol_controlcamera/server_camera.h b/code/components/jomjol_controlcamera/server_camera.h index b3f1fe19..c0177356 100644 --- a/code/components/jomjol_controlcamera/server_camera.h +++ b/code/components/jomjol_controlcamera/server_camera.h @@ -13,4 +13,7 @@ void register_server_camera_uri(httpd_handle_t server); void PowerResetCamera(); + +extern bool debug_detail_heap; + #endif \ No newline at end of file diff --git a/code/components/jomjol_fileserver_ota/server_help.cpp b/code/components/jomjol_fileserver_ota/server_help.cpp index 17faa622..00b3e826 100644 --- a/code/components/jomjol_fileserver_ota/server_help.cpp +++ b/code/components/jomjol_fileserver_ota/server_help.cpp @@ -25,7 +25,7 @@ char scratch[SCRATCH_BUFSIZE]; (strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0) -esp_err_t send_file(httpd_req_t *req, std::string filename, struct stat * file_stat) +esp_err_t send_file(httpd_req_t *req, std::string filename) { FILE *fd = OpenFileAndWait(filename.c_str(), "r"); if (!fd) { @@ -35,7 +35,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename, struct stat * file_ return ESP_FAIL; } - ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filename.c_str(), file_stat->st_size); + ESP_LOGI(TAG, "Sending file : %s ...", filename.c_str()); set_content_type_from_file(req, filename.c_str()); /* Retrieve the pointer to scratch buffer for temporary storage */ @@ -67,6 +67,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename, struct stat * file_ + /* Copies the full path into destination buffer and returns * pointer to path (skipping the preceding base path) */ const char* get_path_from_uri(char *dest, const char *base_path, const char *uri, size_t destsize) diff --git a/code/components/jomjol_fileserver_ota/server_help.h b/code/components/jomjol_fileserver_ota/server_help.h index 650a8a8e..eb836cc6 100644 --- a/code/components/jomjol_fileserver_ota/server_help.h +++ b/code/components/jomjol_fileserver_ota/server_help.h @@ -5,6 +5,6 @@ const char* get_path_from_uri(char *dest, const char *base_path, const char *uri, size_t destsize); -esp_err_t send_file(httpd_req_t *req, std::string filename, struct stat * file_stat); +esp_err_t send_file(httpd_req_t *req, std::string filename); esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename); \ No newline at end of file diff --git a/code/components/jomjol_fileserver_ota/server_ota.cpp b/code/components/jomjol_fileserver_ota/server_ota.cpp index 44efdce2..e035b598 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.cpp +++ b/code/components/jomjol_fileserver_ota/server_ota.cpp @@ -303,6 +303,8 @@ void CheckOTAUpdate(void) esp_err_t handler_ota_update(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_ota_update - Start"); + LogFile.WriteToFile("handler_ota_update"); char _query[200]; char _filename[30]; @@ -378,7 +380,9 @@ esp_err_t handler_ota_update(httpd_req_t *req) } httpd_resp_send(req, resp_str, strlen(resp_str)); - + + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_ota_update - Done"); + return ESP_OK; }; @@ -414,6 +418,8 @@ void doReboot(){ esp_err_t handler_reboot(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_reboot - Start"); + LogFile.WriteToFile("handler_reboot"); ESP_LOGI(TAGPARTOTA, "!!! System will restart within 5 sec!!!"); const char* resp_str = "!!! System will restart within 5 sec!!!"; @@ -421,6 +427,7 @@ esp_err_t handler_reboot(httpd_req_t *req) doReboot(); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_reboot - Done"); return ESP_OK; } diff --git a/code/components/jomjol_fileserver_ota/server_ota.h b/code/components/jomjol_fileserver_ota/server_ota.h index 440cb67d..87ae1319 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.h +++ b/code/components/jomjol_fileserver_ota/server_ota.h @@ -8,4 +8,6 @@ static const char *TAGPARTOTA = "server_ota"; void register_server_ota_sdcard_uri(httpd_handle_t server); void CheckOTAUpdate(); -void doReboot(); \ No newline at end of file +void doReboot(); + +extern bool debug_detail_heap; \ No newline at end of file diff --git a/code/components/jomjol_flowcontroll/CMakeLists.txt b/code/components/jomjol_flowcontroll/CMakeLists.txt index 670be171..b1dfec86 100644 --- a/code/components/jomjol_flowcontroll/CMakeLists.txt +++ b/code/components/jomjol_flowcontroll/CMakeLists.txt @@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*) idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "." - REQUIRES jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_fileserver_ota) + REQUIRES jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_fileserver_ota jomjol_image_proc) diff --git a/code/components/jomjol_flowcontroll/ClassFlow.cpp b/code/components/jomjol_flowcontroll/ClassFlow.cpp index 5913d304..60ca0620 100644 --- a/code/components/jomjol_flowcontroll/ClassFlow.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlow.cpp @@ -9,9 +9,11 @@ void ClassFlow::SetInitialParameter(void) { ListFlowControll = NULL; + previousElement = NULL; } -//std::vector ClassFlow::ZerlegeZeile(std::string input, std::string delimiter); + + std::vector ClassFlow::ZerlegeZeile(std::string input, std::string delimiter) { @@ -55,7 +57,6 @@ bool ClassFlow::GetNextParagraph(FILE* pfile, string& aktparamgraph) ClassFlow::ClassFlow(void) { SetInitialParameter(); - ListFlowControll = NULL; } ClassFlow::ClassFlow(std::vector * lfc) @@ -64,6 +65,13 @@ ClassFlow::ClassFlow(std::vector * lfc) ListFlowControll = lfc; } +ClassFlow::ClassFlow(std::vector * lfc, ClassFlow *_prev) +{ + SetInitialParameter(); + ListFlowControll = lfc; + previousElement = _prev; +} + bool ClassFlow::ReadParameter(FILE* pfile, string &aktparamgraph) { return false; @@ -100,7 +108,7 @@ bool ClassFlow::getNextLine(FILE* pfile, string *rt) } *rt = zw; *rt = trim(*rt); - while (zw[0] == '#' || (rt->size() == 0)) // Kommentarzeilen und Leerzeilen überspringen + while (zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) // Kommentarzeilen (; oder #) und Leerzeilen überspringen { fgets(zw, 1024, pfile); printf("%s", zw); diff --git a/code/components/jomjol_flowcontroll/ClassFlow.h b/code/components/jomjol_flowcontroll/ClassFlow.h index 11a5b25d..9a21bb11 100644 --- a/code/components/jomjol_flowcontroll/ClassFlow.h +++ b/code/components/jomjol_flowcontroll/ClassFlow.h @@ -5,7 +5,7 @@ #include #include "Helper.h" -#include "CFindTemplate.h" +#include "CImageBasis.h" using namespace std; @@ -16,7 +16,10 @@ using namespace std; struct HTMLInfo { float val; + CImageBasis *image = NULL; + CImageBasis *image_org = NULL; std::string filename; + std::string filename_org; }; @@ -30,12 +33,15 @@ protected: bool getNextLine(FILE* pfile, string* rt); std::vector* ListFlowControll; + ClassFlow *previousElement; virtual void SetInitialParameter(void); public: ClassFlow(void); ClassFlow(std::vector * lfc); + ClassFlow(std::vector * lfc, ClassFlow *_prev); + virtual bool ReadParameter(FILE* pfile, string &aktparamgraph); virtual bool doFlow(string time); virtual string getHTMLSingleStep(string host); diff --git a/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp b/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp index fa97aa7f..866d1952 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp @@ -1,29 +1,55 @@ #include "ClassFlowAlignment.h" +#include "ClassFlowMakeImage.h" +#include "ClassFlow.h" + +#include "CRotateImage.h" #include "ClassLogFile.h" -ClassFlowAlignment::ClassFlowAlignment() + + +bool AlignmentExtendedDebugging = true; + + +void ClassFlowAlignment::SetInitialParameter(void) { initalrotate = 0; anz_ref = 0; suchex = 40; suchey = 40; initialmirror = false; + SaveAllFiles = false; namerawimage = "/sdcard/img_tmp/raw.jpg"; ListFlowControll = NULL; + AlignAndCutImage = NULL; + ImageBasis = NULL; + ImageTMP = NULL; + previousElement = NULL; + ref_dx[0] = 0; ref_dx[1] = 0; + ref_dy[0] = 0; ref_dy[1] = 0; } ClassFlowAlignment::ClassFlowAlignment(std::vector* lfc) { - initalrotate = 0; - anz_ref = 0; - suchex = 40; - suchey = 40; - initialmirror = false; - namerawimage = "/sdcard/img_tmp/raw.jpg"; + SetInitialParameter(); ListFlowControll = lfc; + + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowMakeImage") == 0) + { + ImageBasis = ((ClassFlowMakeImage*) (*ListFlowControll)[i])->rawImage; + } + } + + if (!ImageBasis) // die Funktion Bilder aufnehmen existiert nicht --> muss erst erzeugt werden NUR ZU TESTZWECKEN + { + if (AlignmentExtendedDebugging) printf("CImageBasis musste erzeugt werden\n"); + ImageBasis = new CImageBasis(namerawimage); + } } + bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph) { std::vector zerlegt; @@ -59,11 +85,18 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph) } if ((zerlegt.size() == 3) && (anz_ref < 2)) { - this->reffilename[anz_ref] = FormatFileName("/sdcard" + zerlegt[0]); - this->ref_x[anz_ref] = std::stod(zerlegt[1]); - this->ref_y[anz_ref] = std::stod(zerlegt[2]); + reffilename[anz_ref] = FormatFileName("/sdcard" + zerlegt[0]); + ref_x[anz_ref] = std::stod(zerlegt[1]); + ref_y[anz_ref] = std::stod(zerlegt[2]); anz_ref++; } + + if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1)) + { + if (toUpper(zerlegt[1]) == "TRUE") + SaveAllFiles = true; + } + } return true; @@ -80,72 +113,52 @@ string ClassFlowAlignment::getHTMLSingleStep(string host) } -bool ClassFlowAlignment::doFlow(string time) +bool ClassFlowAlignment::doFlow(string time) { - string input = namerawimage; - string output = "/sdcard/img_tmp/rot.jpg"; - string output3 = "/sdcard/img_tmp/rot_roi.jpg"; - string output2 = "/sdcard/img_tmp/alg.jpg"; - string output4 = "/sdcard/img_tmp/alg_roi.jpg"; - string output1 = "/sdcard/img_tmp/mirror.jpg"; + if (!ImageTMP) + ImageTMP = new CImageBasis(ImageBasis, 5); - input = FormatFileName(input); - output = FormatFileName(output); - output2 = FormatFileName(output2); + if (AlignAndCutImage) + delete AlignAndCutImage; + AlignAndCutImage = new CAlignAndCutImage(ImageBasis, ImageTMP); + CRotateImage rt(AlignAndCutImage, ImageTMP); if (initialmirror){ - CRotate *rt; - rt = new CRotate(input); - if (!rt->ImageOkay()){ - LogFile.WriteToFile("ClassFlowAlignment::doFlow CRotate Inital Mirror raw.jpg not okay!"); - delete rt; - return false; - } printf("do mirror\n"); - rt->Mirror(); - rt->SaveToFile(output1); - input = output1; - delete rt; + rt.Mirror(); + if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg")); } - - + if (initalrotate != 0) { - CRotate *rt = NULL; - printf("Load rotationfile: %s\n", input.c_str()); - rt = new CRotate(input); - if (!rt->ImageOkay()){ - LogFile.WriteToFile("ClassFlowAlignment::doFlow CRotate raw.jpg not okay!"); - delete rt; - return false; - } - rt->Rotate(this->initalrotate); - rt->SaveToFile(output); - delete rt; + rt.Rotate(initalrotate); + if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg")); } - else + + AlignAndCutImage->Align(reffilename[0], ref_x[0], ref_y[0], reffilename[1], ref_x[1], ref_y[1], suchex, suchey, ""); + AlignAndCutImage->GetRefSize(ref_dx, ref_dy); + if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg")); + + if (SaveAllFiles) { - CopyFile(input, output); + DrawRef(ImageTMP); + ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg")); } - CAlignAndCutImage *caic; - caic = new CAlignAndCutImage(output); - caic->Align(this->reffilename[0], this->ref_x[0], this->ref_y[0], this->reffilename[1], this->ref_x[1], this->ref_y[1], suchex, suchey, output3); - caic->SaveToFile(output2); - - printf("Startwriting Output4:%s\n", output4.c_str()); - if (output4.length() > 0) + if (ImageTMP) // nuss gelöscht werden, um Speicherplatz für das Laden von tflite zu haben { - caic->drawRect(ref_x[0], ref_y[0], caic->t0_dx, caic->t0_dy, 255, 0, 0, 2); - caic->drawRect(ref_x[1], ref_y[1], caic->t1_dx, caic->t1_dy, 255, 0, 0, 2); - caic->SaveToFile(output4); - printf("Write output4: %s\n", output4.c_str()); - } + delete ImageTMP; + ImageTMP = NULL; + } - delete caic; - - // Align mit Templates return true; } + +void ClassFlowAlignment::DrawRef(CImageBasis *_zw) +{ + _zw->drawRect(ref_x[0], ref_y[0], ref_dx[0], ref_dy[0], 255, 0, 0, 2); + _zw->drawRect(ref_x[1], ref_y[1], ref_dx[1], ref_dy[1], 255, 0, 0, 2); +} + diff --git a/code/components/jomjol_flowcontroll/ClassFlowAlignment.h b/code/components/jomjol_flowcontroll/ClassFlowAlignment.h index b34908bc..3127064c 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAlignment.h +++ b/code/components/jomjol_flowcontroll/ClassFlowAlignment.h @@ -2,6 +2,7 @@ #include "ClassFlow.h" #include "Helper.h" +#include "CAlignAndCutImage.h" #include @@ -15,13 +16,24 @@ protected: bool initialmirror; string reffilename[2]; int ref_x[2], ref_y[2]; + int ref_dx[2], ref_dy[2]; int anz_ref; int suchex, suchey; string namerawimage; + bool SaveAllFiles; + CAlignAndCutImage *AlignAndCutImage; + + void SetInitialParameter(void); public: - ClassFlowAlignment(); + CImageBasis *ImageBasis, *ImageTMP; + ClassFlowAlignment(std::vector* lfc); + + CAlignAndCutImage* GetAlignAndCutImage(){return AlignAndCutImage;}; + + void DrawRef(CImageBasis *_zw); + bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string getHTMLSingleStep(string host); diff --git a/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp b/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp index d0dea860..d1e0494c 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp @@ -16,21 +16,30 @@ static const char* TAG = "flow_analog"; bool debugdetailanalog = false; -ClassFlowAnalog::ClassFlowAnalog() : ClassFlowImage(TAG) +void ClassFlowAnalog::SetInitialParameter(void) { string cnnmodelfile = ""; modelxsize = 1; modelysize = 1; ListFlowControll = NULL; -} + previousElement = NULL; + SaveAllFiles = false; +} ClassFlowAnalog::ClassFlowAnalog(std::vector* lfc) : ClassFlowImage(lfc, TAG) { - string cnnmodelfile = ""; - modelxsize = 1; - modelysize = 1; -} + SetInitialParameter(); + ListFlowControll = lfc; + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowAlignment") == 0) + { + flowpostalignment = (ClassFlowAlignment*) (*ListFlowControll)[i]; + } + } + +} string ClassFlowAnalog::getReadout() @@ -113,9 +122,24 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph) neuroi->deltax = std::stoi(zerlegt[3]); neuroi->deltay = std::stoi(zerlegt[4]); neuroi->result = -1; + neuroi->image = NULL; + neuroi->image_org = NULL; ROI.push_back(neuroi); } + + if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1)) + { + if (toUpper(zerlegt[1]) == "TRUE") + SaveAllFiles = true; + } } + + 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); + } + return true; } @@ -162,79 +186,37 @@ bool ClassFlowAnalog::doFlow(string time) bool ClassFlowAnalog::doAlignAndCut(string time) { - string input = "/sdcard/img_tmp/alg.jpg"; - string input_roi = "/sdcard/img_tmp/alg_roi.jpg"; - string ioresize = "/sdcard/img_tmp/resize.bmp"; - string output; - string nm; - input = FormatFileName(input); - input_roi = FormatFileName(input_roi); - - CResizeImage *rs; - CImageBasis *img_roi = NULL; - CAlignAndCutImage *caic = new CAlignAndCutImage(input); - - if (!caic->ImageOkay()){ - if (debugdetailanalog) LogFile.WriteToFile("ClassFlowAnalog::doAlignAndCut not okay!"); - delete caic; - return false; - } - - if (input_roi.length() > 0){ - img_roi = new CImageBasis(input_roi); - if (!img_roi->ImageOkay()){ - if (debugdetailanalog) LogFile.WriteToFile("ClassFlowAnalog::doAlignAndCut ImageRoi not okay!"); - delete caic; - delete img_roi; - return false; - } - } + CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage(); for (int i = 0; i < ROI.size(); ++i) { printf("Analog %d - Align&Cut\n", i); - output = "/sdcard/img_tmp/" + ROI[i]->name + ".jpg"; - output = FormatFileName(output); - caic->CutAndSave(output, ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay); + + 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")); - rs = new CResizeImage(output); - if (!rs->ImageOkay()){ - if (debugdetailanalog) LogFile.WriteToFile("ClassFlowAnalog::doAlignAndCut CResizeImage(output);!"); - delete caic; - delete rs; - return false; - } - - rs->Resize(modelxsize, modelysize); - ioresize = "/sdcard/img_tmp/ra" + std::to_string(i) + ".bmp"; - ioresize = FormatFileName(ioresize); - rs->SaveToFile(ioresize); - delete rs; - - if (img_roi) - { - int r = 0; - int g = 255; - int b = 0; - img_roi->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, r, g, b, 1); - img_roi->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); - img_roi->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); - img_roi->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); - } + ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image); + if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp")); } - delete caic; - - - if (img_roi) - { - img_roi->SaveToFile(input_roi); - delete img_roi; - } - return true; } +void ClassFlowAnalog::DrawROI(CImageBasis *_zw) +{ + int r = 0; + 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); + } +} + bool ClassFlowAnalog::doNeuralNetwork(string time) { string logPath = CreateLogFolder(time); @@ -265,7 +247,8 @@ bool ClassFlowAnalog::doNeuralNetwork(string time) #ifndef OHNETFLITE // LogFile.WriteToFile("ClassFlowAnalog::doNeuralNetwork vor CNN tflite->LoadInputImage(ioresize)"); - tflite->LoadInputImage(ioresize); +// tflite->LoadInputImage(ioresize); + tflite->LoadInputImageBasis(ROI[i]->image); tflite->Invoke(); if (debugdetailanalog) LogFile.WriteToFile("Nach Invoke"); @@ -278,9 +261,12 @@ bool ClassFlowAnalog::doNeuralNetwork(string time) // 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); + printf("Result Analog%i: %f\n", i, ROI[i]->result); - LogImage(logPath, ROI[i]->name, &ROI[i]->result, NULL, time); + if (isLogImage) + { + LogImage(logPath, ROI[i]->name, &ROI[i]->result, NULL, time, ROI[i]->image_org); + } } #ifndef OHNETFLITE delete tflite; diff --git a/code/components/jomjol_flowcontroll/ClassFlowAnalog.h b/code/components/jomjol_flowcontroll/ClassFlowAnalog.h index 89f2f6e2..64de44e0 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAnalog.h +++ b/code/components/jomjol_flowcontroll/ClassFlowAnalog.h @@ -1,10 +1,12 @@ #pragma once #include "ClassFlowImage.h" +#include "ClassFlowAlignment.h" // #include "CTfLiteClass.h" struct roianalog { int posx, posy, deltax, deltay; float result; + CImageBasis *image, *image_org; string name; }; @@ -17,14 +19,21 @@ protected: string cnnmodelfile; int modelxsize, modelysize; int ZeigerEval(float zahl, int ziffer_vorgaenger); + bool SaveAllFiles; + + ClassFlowAlignment* flowpostalignment; + + void SetInitialParameter(void); public: - ClassFlowAnalog(); ClassFlowAnalog(std::vector* lfc); + bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string getHTMLSingleStep(string host); - string getReadout(); + string getReadout(); + + void DrawROI(CImageBasis *_zw); bool doNeuralNetwork(string time); bool doAlignAndCut(string time); diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp index 5734ef26..934d9749 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp @@ -9,8 +9,11 @@ #include "Helper.h" #include "server_ota.h" +#include "server_help.h" + static const char* TAG = "flow_controll"; + std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _host){ std::string _classname = ""; std::string result = ""; @@ -68,6 +71,9 @@ void ClassFlowControll::SetInitialParameter(void) AutoStart = false; SetupModeActive = false; AutoIntervall = 10; + flowdigit = NULL; + flowanalog = NULL; + flowpostprocessing = NULL; } bool ClassFlowControll::isAutoStart(long &_intervall) @@ -83,13 +89,25 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type) _type = trim(_type); if (toUpper(_type).compare("[MAKEIMAGE]") == 0) + { cfc = new ClassFlowMakeImage(&FlowControll); + flowmakeimage = (ClassFlowMakeImage*) cfc; + } if (toUpper(_type).compare("[ALIGNMENT]") == 0) + { cfc = new ClassFlowAlignment(&FlowControll); + flowalignment = (ClassFlowAlignment*) cfc; + } if (toUpper(_type).compare("[ANALOG]") == 0) + { cfc = new ClassFlowAnalog(&FlowControll); + flowanalog = (ClassFlowAnalog*) cfc; + } if (toUpper(_type).compare("[DIGITS]") == 0) + { cfc = new ClassFlowDigit(&FlowControll); + flowdigit = (ClassFlowDigit*) cfc; + } if (toUpper(_type).compare("[MQTT]") == 0) cfc = new ClassFlowMQTT(&FlowControll); if (toUpper(_type).compare("[POSTPROCESSING]") == 0) @@ -139,6 +157,7 @@ void ClassFlowControll::InitFlow(std::string config) cfc = CreateClassFlow(line); if (cfc) { + printf("Start ReadParameter\n"); cfc->ReadParameter(pFile, line); } else @@ -158,9 +177,7 @@ std::string ClassFlowControll::getActStatus(){ } void ClassFlowControll::doFlowMakeImageOnly(string time){ - bool result = true; std::string zw_time; - int repeat = 0; for (int i = 0; i < FlowControll.size(); ++i) { @@ -181,12 +198,18 @@ bool ClassFlowControll::doFlow(string time) std::string zw_time; int repeat = 0; + +///////////////////////////////////////////////////// + if (debug_detail_heap) LogFile.WriteHeapInfo("ClassFlowAnalog::doFlow - Start"); +///////////////////////////////////////////////////////// + for (int i = 0; i < FlowControll.size(); ++i) { zw_time = gettimestring("%Y%m%d-%H%M%S"); aktstatus = zw_time + ": " + FlowControll[i]->name(); string zw = "FlowControll.doFlow - " + FlowControll[i]->name(); - LogFile.WriteToFile(zw); + if (debug_detail_heap) LogFile.WriteHeapInfo(zw); +// LogFile.WriteToFile(zw); if (!FlowControll[i]->doFlow(time)){ repeat++; LogFile.WriteToFile("Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt"); @@ -202,6 +225,8 @@ bool ClassFlowControll::doFlow(string time) { result = true; } + + if (debug_detail_heap) LogFile.WriteHeapInfo("ClassFlowAnalog::doFlow"); } zw_time = gettimestring("%Y%m%d-%H%M%S"); aktstatus = zw_time + ": Flow is done"; @@ -320,6 +345,14 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph) setTimeZone(zerlegt[1]); } + if ((toUpper(zerlegt[0]) == "TIMESERVER") && (zerlegt.size() > 1)) + { + string zw = "Set TimeZone: " + zerlegt[1]; + reset_servername(zerlegt[1]); + } + + + if ((toUpper(zerlegt[0]) == "SETUPMODE") && (zerlegt.size() > 1)) { if (toUpper(zerlegt[1]) == "TRUE") @@ -362,4 +395,85 @@ int ClassFlowControll::CleanTempFolder() { ESP_LOGI(TAG, "%d files deleted", deleted); return 0; +} + + +esp_err_t ClassFlowControll::SendRawJPG(httpd_req_t *req) +{ + return flowmakeimage->SendRawJPG(req); +} + + +esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req) +{ + printf("ClassFlowControll::GetJPGStream %s\n", _fn.c_str()); + + CImageBasis *_send = NULL; + esp_err_t result = ESP_FAIL; + bool Dodelete = false; + + if (_fn == "alg.jpg") + { + _send = flowalignment->ImageBasis; + } + + + + if (_fn == "alg_roi.jpg") + { + CImageBasis* _imgzw = new CImageBasis(flowalignment->ImageBasis); + flowalignment->DrawRef(_imgzw); + if (flowdigit) flowdigit->DrawROI(_imgzw); + if (flowanalog) flowanalog->DrawROI(_imgzw); + _send = _imgzw; + Dodelete = true; + } + + std::vector htmlinfo; + htmlinfo = GetAllDigital(); + for (int i = 0; i < htmlinfo.size(); ++i) + { + if (_fn == htmlinfo[i]->filename) + { + if (htmlinfo[i]->image) + _send = htmlinfo[i]->image; + } + if (_fn == htmlinfo[i]->filename_org) + { + if (htmlinfo[i]->image_org) + _send = htmlinfo[i]->image_org; + } + } + + htmlinfo = GetAllAnalog(); + for (int i = 0; i < htmlinfo.size(); ++i) + { + if (_fn == htmlinfo[i]->filename) + { + if (htmlinfo[i]->image) + _send = htmlinfo[i]->image; + } + if (_fn == htmlinfo[i]->filename_org) + { + if (htmlinfo[i]->image_org) + _send = htmlinfo[i]->image_org; + } + } + + if (_send) + { + ESP_LOGI(TAG, "Sending file : %s ...", _fn.c_str()); + set_content_type_from_file(req, _fn.c_str()); + result = _send->SendJPGtoHTTP(req); + ESP_LOGI(TAG, "File sending complete"); + /* Respond with an empty chunk to signal HTTP response completion */ + httpd_resp_send_chunk(req, NULL, 0); + } + + if (Dodelete) + { + delete _send; + } + + return result; } \ No newline at end of file diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.h b/code/components/jomjol_flowcontroll/ClassFlowControll.h index adf7ef6a..c491cb87 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.h +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.h @@ -17,6 +17,10 @@ class ClassFlowControll : protected: std::vector FlowControll; ClassFlowPostProcessing* flowpostprocessing; + ClassFlowAlignment* flowalignment; + ClassFlowAnalog* flowanalog; + ClassFlowDigit* flowdigit; + ClassFlowMakeImage* flowmakeimage; ClassFlow* CreateClassFlow(std::string _type); bool AutoStart; @@ -35,6 +39,9 @@ public: string GetPrevalue(); bool ReadParameter(FILE* pfile, string& aktparamgraph); + esp_err_t GetJPGStream(std::string _fn, httpd_req_t *req); + esp_err_t SendRawJPG(httpd_req_t *req); + std::string doSingleStep(std::string _stepname, std::string _host); bool isAutoStart(long &_intervall); @@ -49,3 +56,5 @@ public: string name(){return "ClassFlowControll";}; }; +extern bool debug_detail_heap; + diff --git a/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp b/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp index 90f02254..f0bf83ad 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp @@ -1,5 +1,6 @@ #include "ClassFlowDigit.h" + //#include "CFindTemplate.h" //#include "CTfLiteClass.h" @@ -15,19 +16,49 @@ static const char* TAG = "flow_digital"; -ClassFlowDigit::ClassFlowDigit() : ClassFlowImage(TAG) + +void ClassFlowDigit::SetInitialParameter(void) { string cnnmodelfile = ""; modelxsize = 1; modelysize = 1; ListFlowControll = NULL; + previousElement = NULL; + SaveAllFiles = false; +} + +ClassFlowDigit::ClassFlowDigit() : ClassFlowImage(TAG) +{ + SetInitialParameter(); } ClassFlowDigit::ClassFlowDigit(std::vector* lfc) : ClassFlowImage(lfc, TAG) { - string cnnmodelfile = ""; - modelxsize = 1; - modelysize = 1; + SetInitialParameter(); + ListFlowControll = lfc; + + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowAlignment") == 0) + { + flowpostalignment = (ClassFlowAlignment*) (*ListFlowControll)[i]; + } + } +} + +ClassFlowDigit::ClassFlowDigit(std::vector* lfc, ClassFlow *_prev) : ClassFlowImage(lfc, _prev, TAG) +{ + SetInitialParameter(); + ListFlowControll = lfc; + previousElement = _prev; + + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowAlignment") == 0) + { + flowpostalignment = (ClassFlowAlignment*) (*ListFlowControll)[i]; + } + } } string ClassFlowDigit::getReadout() @@ -85,9 +116,25 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph) neuroi->deltax = std::stoi(zerlegt[3]); neuroi->deltay = std::stoi(zerlegt[4]); neuroi->resultklasse = -1; + neuroi->image = NULL; + neuroi->image_org = NULL; ROI.push_back(neuroi); } + + if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1)) + { + if (toUpper(zerlegt[1]) == "TRUE") + SaveAllFiles = true; + } + } + + 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); + } + return true; } @@ -133,60 +180,17 @@ bool ClassFlowDigit::doFlow(string time) bool ClassFlowDigit::doAlignAndCut(string time) { - string input = "/sdcard/img_tmp/alg.jpg"; - string input_roi = "/sdcard/img_tmp/alg_roi.jpg"; - string ioresize = "/sdcard/img_tmp/resize.bmp"; - string output; - string nm; - input = FormatFileName(input); - input_roi = FormatFileName(input_roi); - - CResizeImage *rs; - CImageBasis *img_roi = NULL; - CAlignAndCutImage *caic = new CAlignAndCutImage(input); - if (!caic->ImageOkay()){ - LogFile.WriteToFile("ClassFlowDigit::doAlignAndCut not okay!"); - delete caic; - return false; - } - - if (input_roi.length() > 0){ - img_roi = new CImageBasis(input_roi); - if (!img_roi->ImageOkay()){ - LogFile.WriteToFile("ClassFlowDigit::doAlignAndCut ImageRoi not okay!"); - delete caic; - delete img_roi; - return false; - } - } - - + CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage(); for (int i = 0; i < ROI.size(); ++i) { printf("DigitalDigit %d - Align&Cut\n", i); - output = "/sdcard/img_tmp/" + ROI[i]->name + ".jpg"; - output = FormatFileName(output); - caic->CutAndSave(output, ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay); + + 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")); - rs = new CResizeImage(output); - rs->Resize(modelxsize, modelysize); - ioresize = "/sdcard/img_tmp/rd" + std::to_string(i) + ".bmp"; - ioresize = FormatFileName(ioresize); - rs->SaveToFile(ioresize); - delete rs; - - if (img_roi) - { - img_roi->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, 0, 0, 255, 2); - } - } - delete caic; - - if (img_roi) - { - img_roi->SaveToFile(input_roi); - delete img_roi; + ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image); + if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp")); } return true; @@ -196,17 +200,9 @@ bool ClassFlowDigit::doNeuralNetwork(string time) { string logPath = CreateLogFolder(time); - string input = "/sdcard/img_tmp/alg.jpg"; - string ioresize = "/sdcard/img_tmp/resize.bmp"; - string output; - string nm; - input = FormatFileName(input); - - #ifndef OHNETFLITE CTfLiteClass *tflite = new CTfLiteClass; - string zwcnn = "/sdcard" + cnnmodelfile; - zwcnn = FormatFileName(zwcnn); + string zwcnn = FormatFileName("/sdcard" + cnnmodelfile); printf(zwcnn.c_str());printf("\n"); tflite->LoadModel(zwcnn); tflite->MakeAllocate(); @@ -215,17 +211,18 @@ bool ClassFlowDigit::doNeuralNetwork(string time) for (int i = 0; i < ROI.size(); ++i) { printf("DigitalDigit %d - TfLite\n", i); - ioresize = "/sdcard/img_tmp/rd" + std::to_string(i) + ".bmp"; - ioresize = FormatFileName(ioresize); -// printf("output: %s, ioresize: %s\n", output.c_str(), ioresize.c_str()); ROI[i]->resultklasse = 0; #ifndef OHNETFLITE - ROI[i]->resultklasse = tflite->GetClassFromImage(ioresize); + ROI[i]->resultklasse = tflite->GetClassFromImageBasis(ROI[i]->image); + #endif printf("Result Digit%i: %d\n", i, ROI[i]->resultklasse); - LogImage(logPath, ROI[i]->name, NULL, &ROI[i]->resultklasse, time); + if (isLogImage) + { + LogImage(logPath, ROI[i]->name, NULL, &ROI[i]->resultklasse, time, ROI[i]->image_org); + } } #ifndef OHNETFLITE delete tflite; @@ -233,6 +230,11 @@ bool ClassFlowDigit::doNeuralNetwork(string time) return true; } +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); +} std::vector ClassFlowDigit::GetHTMLInfo() { @@ -241,10 +243,14 @@ std::vector ClassFlowDigit::GetHTMLInfo() for (int i = 0; i < ROI.size(); ++i) { HTMLInfo *zw = new HTMLInfo; - zw->filename = ROI[i]->name + ".jpg"; + 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); } return result; -} \ No newline at end of file +} + diff --git a/code/components/jomjol_flowcontroll/ClassFlowDigit.h b/code/components/jomjol_flowcontroll/ClassFlowDigit.h index 3546bb36..d3043642 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowDigit.h +++ b/code/components/jomjol_flowcontroll/ClassFlowDigit.h @@ -1,5 +1,6 @@ #pragma once #include "ClassFlowImage.h" +#include "ClassFlowAlignment.h" #include "Helper.h" #include @@ -8,6 +9,7 @@ struct roi { int posx, posy, deltax, deltay; int resultklasse; string name; + CImageBasis *image, *image_org; roi* next; }; @@ -18,19 +20,27 @@ protected: std::vector ROI; string cnnmodelfile; int modelxsize, modelysize; + bool SaveAllFiles; + + ClassFlowAlignment* flowpostalignment; bool doNeuralNetwork(string time); bool doAlignAndCut(string time); + void SetInitialParameter(void); + public: ClassFlowDigit(); ClassFlowDigit(std::vector* lfc); + ClassFlowDigit(std::vector* lfc, ClassFlow *_prev); bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string getHTMLSingleStep(string host); string getReadout(); std::vector GetHTMLInfo(); + void DrawROI(CImageBasis *_zw); + string name(){return "ClassFlowDigit";}; }; diff --git a/code/components/jomjol_flowcontroll/ClassFlowImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowImage.cpp index 5c09160e..35336462 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowImage.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowImage.cpp @@ -5,6 +5,7 @@ #include #include "time_sntp.h" #include "ClassLogFile.h" +#include "CImageBasis.h" ClassFlowImage::ClassFlowImage(const char* logTag) { @@ -12,12 +13,19 @@ ClassFlowImage::ClassFlowImage(const char* logTag) isLogImage = false; } -ClassFlowImage::ClassFlowImage(std::vector * lfc, const char* logTag) : ClassFlow((std::vector*)lfc) +ClassFlowImage::ClassFlowImage(std::vector * lfc, const char* logTag) : ClassFlow(lfc) { this->logTag = logTag; isLogImage = false; } +ClassFlowImage::ClassFlowImage(std::vector * lfc, ClassFlow *_prev, const char* logTag) : ClassFlow(lfc, _prev) +{ + this->logTag = logTag; + isLogImage = false; +} + + string ClassFlowImage::CreateLogFolder(string time) { if (!isLogImage) return ""; @@ -32,7 +40,7 @@ string ClassFlowImage::CreateLogFolder(string time) { return logPath; } -void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, int *resultInt, string time) { +void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, int *resultInt, string time, CImageBasis *_img) { if (!isLogImage) return; @@ -50,7 +58,8 @@ void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, i string output = "/sdcard/img_tmp/" + name + ".jpg"; output = FormatFileName(output); printf("save to file: %s\n", nm.c_str()); - CopyFile(output, nm); + _img->SaveToFile(nm); +// CopyFile(output, nm); } void ClassFlowImage::RemoveOldLogs() diff --git a/code/components/jomjol_flowcontroll/ClassFlowImage.h b/code/components/jomjol_flowcontroll/ClassFlowImage.h index 23154c64..e3dacc35 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowImage.h +++ b/code/components/jomjol_flowcontroll/ClassFlowImage.h @@ -12,11 +12,13 @@ protected: const char* logTag; string CreateLogFolder(string time); - void LogImage(string logPath, string name, float *resultFloat, int *resultInt, string time); + void LogImage(string logPath, string name, float *resultFloat, int *resultInt, string time, CImageBasis *_img); + public: ClassFlowImage(const char* logTag); ClassFlowImage(std::vector * lfc, const char* logTag); - + ClassFlowImage(std::vector * lfc, ClassFlow *_prev, const char* logTag); + void RemoveOldLogs(); }; diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp index e96de968..3200e57f 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp @@ -6,7 +6,7 @@ #include -ClassFlowMQTT::ClassFlowMQTT() +void ClassFlowMQTT::SetInitialParameter(void) { uri = ""; topic = ""; @@ -15,20 +15,35 @@ ClassFlowMQTT::ClassFlowMQTT() OldValue = ""; flowpostprocessing = NULL; user = ""; - password = ""; + password = ""; + previousElement = NULL; + ListFlowControll = NULL; +} + +ClassFlowMQTT::ClassFlowMQTT() +{ + SetInitialParameter(); } ClassFlowMQTT::ClassFlowMQTT(std::vector* lfc) { - uri = ""; - topic = ""; - topicError = ""; - clientname = "watermeter"; - OldValue = ""; - flowpostprocessing = NULL; - user = ""; - password = ""; + SetInitialParameter(); + ListFlowControll = lfc; + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0) + { + flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i]; + } + } +} + +ClassFlowMQTT::ClassFlowMQTT(std::vector* lfc, ClassFlow *_prev) +{ + SetInitialParameter(); + + previousElement = _prev; ListFlowControll = lfc; for (int i = 0; i < ListFlowControll->size(); ++i) @@ -38,9 +53,9 @@ ClassFlowMQTT::ClassFlowMQTT(std::vector* lfc) flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i]; } } - } + bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph) { std::vector zerlegt; diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h index 48e93f0f..2ac29135 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h @@ -13,11 +13,13 @@ protected: std::string OldValue; ClassFlowPostProcessing* flowpostprocessing; std::string user, password; - + void SetInitialParameter(void); public: ClassFlowMQTT(); ClassFlowMQTT(std::vector* lfc); + ClassFlowMQTT(std::vector* lfc, ClassFlow *_prev); + bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string name(){return "ClassFlowMQTT";}; diff --git a/code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp index d1f4d78c..e8a938a4 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp @@ -1,7 +1,8 @@ #include "ClassFlowMakeImage.h" #include "Helper.h" +#include "ClassLogFile.h" -#include "CFindTemplate.h" +#include "CImageBasis.h" #include "ClassControllCamera.h" #include @@ -16,30 +17,27 @@ esp_err_t ClassFlowMakeImage::camera_capture(){ void ClassFlowMakeImage::takePictureWithFlash(int flashdauer) { - string nm = namerawimage; - if (isImageSize && (ImageQuality > 0)) - Camera.SetQualitySize(ImageQuality, ImageSize); - printf("Start CaptureFile\n"); - Camera.CaptureToFile(nm, flashdauer); + Camera.CaptureToBasisImage(rawImage, flashdauer); + if (SaveAllFiles) rawImage->SaveToFile(namerawimage); } - -ClassFlowMakeImage::ClassFlowMakeImage() : ClassFlowImage(TAG) +void ClassFlowMakeImage::SetInitialParameter(void) { waitbeforepicture = 5; isImageSize = false; ImageQuality = -1; TimeImageTaken = 0; + ImageQuality = 5; + rawImage = NULL; + ImageSize = FRAMESIZE_VGA; + SaveAllFiles = false; namerawimage = "/sdcard/img_tmp/raw.jpg"; -} +} + ClassFlowMakeImage::ClassFlowMakeImage(std::vector* lfc) : ClassFlowImage(lfc, TAG) { - waitbeforepicture = 5; - isImageSize = false; - ImageQuality = -1; - TimeImageTaken = 0; - namerawimage = "/sdcard/img_tmp/raw.jpg"; + SetInitialParameter(); } bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph) @@ -64,14 +62,28 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph) isLogImage = true; } if ((zerlegt[0] == "ImageQuality") && (zerlegt.size() > 1)) - this->ImageQuality = std::stod(zerlegt[1]); + ImageQuality = std::stod(zerlegt[1]); + if ((zerlegt[0] == "ImageSize") && (zerlegt.size() > 1)) { ImageSize = Camera.TextToFramesize(zerlegt[1].c_str()); isImageSize = true; } + + if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1)) + { + if (toUpper(zerlegt[1]) == "TRUE") + SaveAllFiles = true; + } + } - + + Camera.SetQualitySize(ImageQuality, ImageSize); + image_width = Camera.image_width; + image_height = Camera.image_height; + rawImage = new CImageBasis(); + rawImage->CreateEmptyImage(image_width, image_height, 3); + return true; } @@ -84,27 +96,49 @@ string ClassFlowMakeImage::getHTMLSingleStep(string host) bool ClassFlowMakeImage::doFlow(string zwtime) { - //////////////////////////////////////////////////////////////////// - // TakeImage and Store into /image_tmp/raw.jpg TO BE DONE - //////////////////////////////////////////////////////////////////// - string logPath = CreateLogFolder(zwtime); int flashdauer = (int) waitbeforepicture * 1000; - + + if (debug_detail_heap) LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - Before takePictureWithFlash"); takePictureWithFlash(flashdauer); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - LogImage(logPath, "raw", NULL, NULL, zwtime); + if (debug_detail_heap) LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After takePictureWithFlash"); + + LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage); RemoveOldLogs(); + if (debug_detail_heap) LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After RemoveOldLogs"); return true; } +esp_err_t ClassFlowMakeImage::SendRawJPG(httpd_req_t *req) +{ + int flashdauer = (int) waitbeforepicture * 1000; + return Camera.CaptureToHTTP(req, flashdauer); +} + + +ImageData* ClassFlowMakeImage::SendRawImage() +{ + CImageBasis *zw = new CImageBasis(rawImage); + ImageData *id; + int flashdauer = (int) waitbeforepicture * 1000; + Camera.CaptureToBasisImage(zw, flashdauer); + id = zw->writeToMemoryAsJPG(); + delete zw; + return id; +} + time_t ClassFlowMakeImage::getTimeImageTaken() { return TimeImageTaken; } + +ClassFlowMakeImage::~ClassFlowMakeImage(void) +{ + delete rawImage; +} + diff --git a/code/components/jomjol_flowcontroll/ClassFlowMakeImage.h b/code/components/jomjol_flowcontroll/ClassFlowMakeImage.h index febb2ab3..19fdcb45 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMakeImage.h +++ b/code/components/jomjol_flowcontroll/ClassFlowMakeImage.h @@ -20,19 +20,34 @@ protected: int ImageQuality; time_t TimeImageTaken; string namerawimage; + int image_height, image_width; + bool SaveAllFiles; + void CopyFile(string input, string output); esp_err_t camera_capture(); - void takePictureWithFlash(int flashdauer); + void takePictureWithFlash(int flashdauer); + + void SetInitialParameter(void); public: - ClassFlowMakeImage(); + CImageBasis *rawImage; + ClassFlowMakeImage(std::vector* lfc); + bool ReadParameter(FILE* pfile, string& aktparamgraph); bool doFlow(string time); string getHTMLSingleStep(string host); time_t getTimeImageTaken(); string name(){return "ClassFlowMakeImage";}; + + ImageData* SendRawImage(); + esp_err_t SendRawJPG(httpd_req_t *req); + + ~ClassFlowMakeImage(void); }; + +extern bool debug_detail_heap; + diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index 00544c1e..0a32b30e 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/code/components/jomjol_helper/Helper.cpp @@ -18,6 +18,64 @@ using namespace std; +///////////////////////////////////////////////////////////////////////////////////////////// +string getESPHeapInfo(){ + string espInfoResultStr = ""; + char aMsgBuf[80]; + + multi_heap_info_t aMultiHead_info ; + heap_caps_get_info (&aMultiHead_info,MALLOC_CAP_8BIT); + size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t aMinFreeHeadSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT); + size_t aMinFreeHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT); + size_t aHeapLargestFreeBlockSize = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + sprintf(aMsgBuf," Free Heap Size: %ld", (long) aFreeHeapSize); + size_t aFreeSPIHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_SPIRAM); + size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL); + size_t aMinFreeInternalHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL); + + sprintf(aMsgBuf," Heap: %ld", (long) aFreeHeapSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf," Min Free: %ld", (long) aMinFreeHeapSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf," larg. Block: %ld", (long) aHeapLargestFreeBlockSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf," SPI Heap: %ld", (long) aFreeSPIHeapSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf," Min Free Heap Size: %ld", (long) aMinFreeHeadSize); + sprintf(aMsgBuf," NOT_SPI Heap: %ld", (long) (aFreeHeapSize - aFreeSPIHeapSize)); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf," largest Block Size: %ld", (long) aHeapLargestFreeBlockSize); + sprintf(aMsgBuf," Internal Heap: %ld", (long) (aFreeInternalHeapSize)); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf," Internal Min Heap free: %ld", (long) (aMinFreeInternalHeapSize)); + espInfoResultStr += string(aMsgBuf); + return espInfoResultStr; +} + + +size_t getESPHeapSize(){ + size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT); + return aFreeHeapSize; +} + +size_t getInternalESPHeapSize() { + size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL); + return aFreeInternalHeapSize; +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////// + +void memCopyGen(uint8_t* _source, uint8_t* _target, int _size) +{ + for (int i = 0; i < _size; ++i) + *(_target + i) = *(_source + i); +} + + FILE* OpenFileAndWait(const char* nm, char* _mode, int _waitsec) { diff --git a/code/components/jomjol_helper/Helper.h b/code/components/jomjol_helper/Helper.h index 3c65d222..5ecf2f5f 100644 --- a/code/components/jomjol_helper/Helper.h +++ b/code/components/jomjol_helper/Helper.h @@ -10,7 +10,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 = 10); +FILE* OpenFileAndWait(const char* nm, char* _mode, int _waitsec = 1); size_t findDelimiterPos(string input, string delimiter); //string trim(string istring); @@ -27,3 +27,12 @@ string toUpper(string in); float temperatureRead(); time_t addDays(time_t startTime, int days); + +void memCopyGen(uint8_t* _source, uint8_t* _target, int _size); + +/////////////////////////// +size_t getInternalESPHeapSize(); +size_t getESPHeapSize(); +string getESPHeapInfo(); + +///////////////////////////// diff --git a/code/components/jomjol_image_proc/CAlignAndCutImage.cpp b/code/components/jomjol_image_proc/CAlignAndCutImage.cpp new file mode 100644 index 00000000..b219b3a0 --- /dev/null +++ b/code/components/jomjol_image_proc/CAlignAndCutImage.cpp @@ -0,0 +1,192 @@ +#include "CAlignAndCutImage.h" +#include "CRotateImage.h" +#include "CFindTemplate.h" + +#define _USE_MATH_DEFINES +#include +#include + +//#define GET_MEMORY malloc +#define GET_MEMORY(X) heap_caps_malloc(X, MALLOC_CAP_SPIRAM) + + + +CAlignAndCutImage::CAlignAndCutImage(CImageBasis *_org, CImageBasis *_temp) +{ + rgb_image = _org->rgb_image; + channels = _org->channels; + width = _org->width; + height = _org->height; + bpp = _org->bpp; + externalImage = true; + + ImageTMP = _temp; +} + +void CAlignAndCutImage::GetRefSize(int *ref_dx, int *ref_dy) +{ + ref_dx[0] = t0_dx; + ref_dy[0] = t0_dy; + ref_dx[1] = t1_dx; + ref_dy[1] = t1_dy; +} + +void CAlignAndCutImage::Align(std::string _template0, int ref0_x, int ref0_y, std::string _template1, int ref1_x, int ref1_y, int deltax, int deltay, std::string imageROI) +{ + int dx, dy; + int r0_x, r0_y, r1_x, r1_y; + +// CFindTemplate* ft = new CFindTemplate(filename); + CFindTemplate* ft = new CFindTemplate(rgb_image, channels, width, height, bpp); + + r0_x = ref0_x; + r0_y = ref0_y; + ft->FindTemplate(_template0, &r0_x, &r0_y, deltax, deltay); + t0_dx = ft->tpl_width; + t0_dy = ft->tpl_height; + + r1_x = ref1_x; + r1_y = ref1_y; + ft->FindTemplate(_template1, &r1_x, &r1_y, deltax, deltay); + t1_dx = ft->tpl_width; + t1_dy = ft->tpl_height; + + delete ft; + + + dx = ref0_x - r0_x; + dy = ref0_y - r0_y; + + r0_x += dx; + r0_y += dy; + + r1_x += dx; + r1_y += dy; + + float w_org, w_ist, d_winkel; + + w_org = atan2(ref1_y - ref0_y, ref1_x - ref0_x); + w_ist = atan2(r1_y - r0_y, r1_x - r0_x); + + d_winkel = (w_org - w_ist) * 180 / M_PI; + + if (imageROI.length() > 0) + { + CImageBasis* imgzw = new CImageBasis(this); + imgzw->drawRect(r0_x, r0_y, t0_dx, t0_dy, 255, 0, 0, 2); + imgzw->drawRect(r1_x, r1_y, t1_dx, t1_dy, 255, 0, 0, 2); + imgzw->SaveToFile(imageROI); + printf("Alignment: alignment ROI created: %s\n", imageROI.c_str()); + delete imgzw; + } + + std::string zw = "\tdx:\t" + std::to_string(dx) + "\tdy:\t" + std::to_string(dy) + "\td_winkel:\t" + std::to_string(d_winkel); +// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zw); + + CRotateImage rt(this, ImageTMP); + rt.Translate(dx, dy); + rt.Rotate(d_winkel, ref0_x, ref0_y); + printf("Alignment: dx %d - dy %d - rot %f\n", dx, dy, d_winkel); +} + + + +void CAlignAndCutImage::CutAndSave(std::string _template1, int x1, int y1, int dx, int dy) +{ + + int x2, y2; + + x2 = x1 + dx; + y2 = y1 + dy; + x2 = std::min(x2, width - 1); + y2 = std::min(y2, height - 1); + + dx = x2 - x1; + dy = y2 - y1; + + int memsize = dx * dy * channels; + uint8_t* odata = (unsigned char*) GET_MEMORY(memsize); + + stbi_uc* p_target; + stbi_uc* p_source; + + for (int x = x1; x < x2; ++x) + for (int y = y1; y < y2; ++y) + { + p_target = odata + (channels * ((y - y1) * dx + (x - x1))); + p_source = rgb_image + (channels * (y * width + x)); + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = p_source[_channels]; + } + + // stbi_write_jpg(_template1.c_str(), dx, dy, channels, odata, 0); + stbi_write_bmp(_template1.c_str(), dx, dy, channels, odata); + + stbi_image_free(odata); +} + +void CAlignAndCutImage::CutAndSave(int x1, int y1, int dx, int dy, CImageBasis *_target) +{ + int x2, y2; + + x2 = x1 + dx; + y2 = y1 + dy; + x2 = std::min(x2, width - 1); + y2 = std::min(y2, height - 1); + + dx = x2 - x1; + dy = y2 - y1; + + if ((_target->height != dy) || (_target->width != dx) || (_target->channels != channels)) + { + printf("CAlignAndCutImage::CutAndSave - Bildgröße passt nicht !!!!!!!!!"); + return; + } + + uint8_t* odata = _target->rgb_image; + + stbi_uc* p_target; + stbi_uc* p_source; + + for (int x = x1; x < x2; ++x) + for (int y = y1; y < y2; ++y) + { + p_target = odata + (channels * ((y - y1) * dx + (x - x1))); + p_source = rgb_image + (channels * (y * width + x)); + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = p_source[_channels]; + } +} + + +CImageBasis* CAlignAndCutImage::CutAndSave(int x1, int y1, int dx, int dy) +{ + int x2, y2; + + x2 = x1 + dx; + y2 = y1 + dy; + x2 = std::min(x2, width - 1); + y2 = std::min(y2, height - 1); + + dx = x2 - x1; + dy = y2 - y1; + + int memsize = dx * dy * channels; + uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); + + stbi_uc* p_target; + stbi_uc* p_source; + + for (int x = x1; x < x2; ++x) + for (int y = y1; y < y2; ++y) + { + p_target = odata + (channels * ((y - y1) * dx + (x - x1))); + p_source = rgb_image + (channels * (y * width + x)); + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = p_source[_channels]; + } + + CImageBasis* rs = new CImageBasis(odata, channels, dx, dy, bpp); + rs->SetIndepended(); + return rs; +} diff --git a/code/components/jomjol_image_proc/CAlignAndCutImage.h b/code/components/jomjol_image_proc/CAlignAndCutImage.h new file mode 100644 index 00000000..92f4454a --- /dev/null +++ b/code/components/jomjol_image_proc/CAlignAndCutImage.h @@ -0,0 +1,18 @@ +#include "CImageBasis.h" + +class CAlignAndCutImage : public CImageBasis +{ + public: + int t0_dx, t0_dy, t1_dx, t1_dy; + CImageBasis *ImageTMP; + CAlignAndCutImage(std::string _image) : CImageBasis(_image) {ImageTMP = NULL;}; + CAlignAndCutImage(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL;}; + CAlignAndCutImage(CImageBasis *_org, CImageBasis *_temp); + + void Align(std::string _template1, int x1, int y1, std::string _template2, int x2, int y2, int deltax = 40, int deltay = 40, std::string imageROI = ""); + void CutAndSave(std::string _template1, int x1, int y1, int dx, int dy); + CImageBasis* CutAndSave(int x1, int y1, int dx, int dy); + void CutAndSave(int x1, int y1, int dx, int dy, CImageBasis *_target); + void GetRefSize(int *ref_dx, int *ref_dy); +}; + diff --git a/code/components/jomjol_image_proc/CFindTemplate.cpp b/code/components/jomjol_image_proc/CFindTemplate.cpp index 69397e81..4af20ccc 100644 --- a/code/components/jomjol_image_proc/CFindTemplate.cpp +++ b/code/components/jomjol_image_proc/CFindTemplate.cpp @@ -1,197 +1,26 @@ #include "CFindTemplate.h" -#include "Helper.h" -#include "ClassLogFile.h" - -#include "esp_system.h" - -#define _USE_MATH_DEFINES -#include -#include - -#define _ESP32_PSRAM - -using namespace std; - -#define GET_MEMORY malloc - -/* -CResizeImage::CResizeImage(std::string _image, int _new_dx, int _new_dy) -{ - CImageBasis::CImageBasis(_image); -} -*/ - -uint8_t CImageBasis::GetPixelColor(int x, int y, int ch) -{ - stbi_uc* p_source; - p_source = this->rgb_image + (this->channels * (y * this->width + x)); - return p_source[ch]; -} - -void CResizeImage::Resize(int _new_dx, int _new_dy) -{ - int memsize = _new_dx * _new_dy * this->channels; - uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); - - stbir_resize_uint8(this->rgb_image, this->width, this->height, 0, odata, _new_dx, _new_dy, 0, this->channels); - - stbi_image_free(this->rgb_image); - this->rgb_image = (unsigned char*)GET_MEMORY(memsize); - - this->memCopy(odata, this->rgb_image, memsize); - this->width = _new_dx; - this->height = _new_dy; - stbi_image_free(odata); -} - -void CRotate::Mirror(){ - int memsize = this->width * this->height * this->channels; - uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); - - int x_source, y_source; - stbi_uc* p_target; - stbi_uc* p_source; - - for (int x = 0; x < this->width; ++x) - for (int y = 0; y < this->height; ++y) - { - p_target = odata + (this->channels * (y * this->width + x)); - - x_source = this->width - x; - y_source = y; - - p_source = this->rgb_image + (this->channels * (y_source * this->width + x_source)); - for (int channels = 0; channels < this->channels; ++channels) - p_target[channels] = p_source[channels]; - } - - // memcpy(this->rgb_image, odata, memsize); - this->memCopy(odata, this->rgb_image, memsize); - stbi_image_free(odata); -} - -void CRotate::Rotate(float _angle, int _centerx, int _centery) -{ - float m[2][3]; - - float x_center = _centerx; - float y_center = _centery; - _angle = _angle / 180 * M_PI; - - m[0][0] = cos(_angle); - m[0][1] = sin(_angle); - m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center; - - m[1][0] = -m[0][1]; - m[1][1] = m[0][0]; - m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center; - - int memsize = this->width * this->height * this->channels; - uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); - - int x_source, y_source; - stbi_uc* p_target; - stbi_uc* p_source; - - for (int x = 0; x < this->width; ++x) - for (int y = 0; y < this->height; ++y) - { - p_target = odata + (this->channels * (y * this->width + x)); - - x_source = int(m[0][0] * x + m[0][1] * y); - y_source = int(m[1][0] * x + m[1][1] * y); - - x_source += int(m[0][2]); - y_source += int(m[1][2]); - - if ((x_source >= 0) && (x_source < this->width) && (y_source >= 0) && (y_source < this->height)) - { - p_source = this->rgb_image + (this->channels * (y_source * this->width + x_source)); - for (int channels = 0; channels < this->channels; ++channels) - p_target[channels] = p_source[channels]; - } - else - { - for (int channels = 0; channels < this->channels; ++channels) - p_target[channels] = 255; - } - } - - // memcpy(this->rgb_image, odata, memsize); - this->memCopy(odata, this->rgb_image, memsize); - stbi_image_free(odata); -} - -void CRotate::Rotate(float _angle) -{ - this->Rotate(_angle, this->width / 2, this->height / 2); -} - -void CRotate::Translate(int _dx, int _dy) -{ - int memsize = this->width * this->height * this->channels; - uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); - - - int x_source, y_source; - stbi_uc* p_target; - stbi_uc* p_source; - - for (int x = 0; x < this->width; ++x) - for (int y = 0; y < this->height; ++y) - { - p_target = odata + (this->channels * (y * this->width + x)); - - x_source = x - _dx; - y_source = y - _dy; - - if ((x_source >= 0) && (x_source < this->width) && (y_source >= 0) && (y_source < this->height)) - { - p_source = this->rgb_image + (this->channels * (y_source * this->width + x_source)); - for (int channels = 0; channels < this->channels; ++channels) - p_target[channels] = p_source[channels]; - } - else - { - for (int channels = 0; channels < this->channels; ++channels) - p_target[channels] = 255; - } - } - - // memcpy(this->rgb_image, odata, memsize); - this->memCopy(odata, this->rgb_image, memsize); - stbi_image_free(odata); -} - - - -CFindTemplate::CFindTemplate(std::string _image) -{ - this->channels = 1; - this->rgb_image = stbi_load(_image.c_str(), &(this->width), &(this->height), &(this->bpp), this->channels); -} void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found_y) { - this->FindTemplate(_template, found_x, found_y, 0, 0); + FindTemplate(_template, found_x, found_y, 0, 0); } void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found_y, int _dx, int _dy) { - uint8_t* rgb_template = stbi_load(_template.c_str(), &tpl_width, &tpl_height, &tpl_bpp, this->channels); + uint8_t* rgb_template = stbi_load(_template.c_str(), &tpl_width, &tpl_height, &tpl_bpp, channels); int ow, ow_start, ow_stop; int oh, oh_start, oh_stop; if (_dx == 0) { - _dx = this->width; + _dx = width; *found_x = 0; } if (_dy == 0) { - _dy = this->height; + _dy = height; *found_y = 0; } @@ -199,18 +28,18 @@ void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found ow_start = *found_x - _dx; ow_start = std::max(ow_start, 0); ow_stop = *found_x + _dx; - if ((ow_stop + tpl_width) > this->width) - ow_stop = this->width - tpl_width; + if ((ow_stop + tpl_width) > width) + ow_stop = width - tpl_width; ow = ow_stop - ow_start + 1; oh_start = *found_y - _dy; oh_start = std::max(oh_start, 0); oh_stop = *found_y + _dy; - if ((oh_stop + tpl_height) > this->height) - oh_stop = this->height - tpl_height; + if ((oh_stop + tpl_height) > height) + oh_stop = height - tpl_height; oh = oh_stop - oh_start + 1; - uint8_t* odata = (unsigned char*)GET_MEMORY(ow * oh * this->channels); + uint8_t* odata = (unsigned char*)GET_MEMORY(ow * oh * channels); double aktSAD; double minSAD = pow(tpl_width * tpl_height * 255, 2); @@ -222,11 +51,11 @@ void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found for (int tpl_x = 0; tpl_x < tpl_width; tpl_x++) for (int tpl_y = 0; tpl_y < tpl_height; tpl_y++) { - stbi_uc* p_org = this->rgb_image + (this->channels * ((youter + tpl_y) * this->width + (xouter + tpl_x))); - stbi_uc* p_tpl = rgb_template + (this->channels * (tpl_y * tpl_width + tpl_x)); + stbi_uc* p_org = rgb_image + (channels * ((youter + tpl_y) * width + (xouter + tpl_x))); + stbi_uc* p_tpl = rgb_template + (channels * (tpl_y * tpl_width + tpl_x)); aktSAD += pow(p_tpl[0] - p_org[0], 2); } - stbi_uc* p_out = odata + (this->channels * ((youter - oh_start) * ow + (xouter - ow_start))); + stbi_uc* p_out = odata + (channels * ((youter - oh_start) * ow + (xouter - ow_start))); p_out[0] = int(sqrt(aktSAD / (tpl_width * tpl_height))); if (aktSAD < minSAD) @@ -237,7 +66,7 @@ void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found } } - stbi_write_bmp("sdcard\\find.bmp", ow, oh, this->channels, odata); + stbi_write_bmp("sdcard\\find.bmp", ow, oh, channels, odata); stbi_image_free(odata); stbi_image_free(rgb_template); @@ -245,303 +74,14 @@ void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found_y, std::string _imageout) { - this->FindTemplate(_template, found_x, found_y); - this->SaveToFile(_imageout); + FindTemplate(_template, found_x, found_y); + SaveToFile(_imageout); } void CFindTemplate::FindTemplate(std::string _template, int* found_x, int* found_y, int _dx, int _dy, std::string _imageout) { - this->FindTemplate(_template, found_x, found_y, _dx, _dy); - this->SaveToFile(_imageout); + FindTemplate(_template, found_x, found_y, _dx, _dy); + SaveToFile(_imageout); } - -void CImageBasis::memCopy(uint8_t* _source, uint8_t* _target, int _size) -{ -#ifdef _ESP32_PSRAM - for (int i = 0; i < _size; ++i) - *(_target + i) = *(_source + i); -#else - memcpy(_target, _source, _size); -#endif -} - -bool CImageBasis::isInImage(int x, int y) -{ - if ((x < 0) || (x > this->width - 1)) - return false; - - if ((y < 0) || (y > this->height- 1)) - return false; - - return true; -} - -void CImageBasis::setPixelColor(int x, int y, int r, int g, int b) -{ - stbi_uc* p_source; - - p_source = this->rgb_image + (this->channels * (y * this->width + x)); - p_source[0] = r; - if (this-> channels > 2) - { - p_source[1] = g; - p_source[2] = b; - } -} - -void CImageBasis::drawRect(int x, int y, int dx, int dy, int r, int g, int b, int thickness) -{ - int zwx1, zwx2, zwy1, zwy2; - int _x, _y, _thick; - - zwx1 = x - thickness + 1; - zwx2 = x + dx + thickness - 1; - zwy1 = y; - zwy2 = y; - for (_thick = 0; _thick < thickness; _thick++) - for (_x = zwx1; _x <= zwx2; ++_x) - for (_y = zwy1; _y <= zwy2; _y++) - if (isInImage(_x, _y)) - setPixelColor(_x, _y - _thick, r, g, b); - - zwx1 = x - thickness + 1; - zwx2 = x + dx + thickness - 1; - zwy1 = y + dy; - zwy2 = y + dy; - for (_thick = 0; _thick < thickness; _thick++) - for (_x = zwx1; _x <= zwx2; ++_x) - for (_y = zwy1; _y <= zwy2; _y++) - if (isInImage(_x, _y)) - setPixelColor(_x, _y + _thick, r, g, b); - - zwx1 = x; - zwx2 = x; - zwy1 = y; - zwy2 = y + dy; - for (_thick = 0; _thick < thickness; _thick++) - for (_x = zwx1; _x <= zwx2; ++_x) - for (_y = zwy1; _y <= zwy2; _y++) - if (isInImage(_x, _y)) - setPixelColor(_x - _thick, _y, r, g, b); - - zwx1 = x + dx; - zwx2 = x + dx; - zwy1 = y; - zwy2 = y + dy; - for (_thick = 0; _thick < thickness; _thick++) - for (_x = zwx1; _x <= zwx2; ++_x) - for (_y = zwy1; _y <= zwy2; _y++) - if (isInImage(_x, _y)) - setPixelColor(_x + _thick, _y, r, g, b); - -} - -void CImageBasis::drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int thickness) -{ - int _x, _y, _thick; - int _zwy1, _zwy2; - thickness = (thickness-1) / 2; - - for (_thick = 0; _thick <= thickness; ++_thick) - for (_x = x1 - _thick; _x <= x2 + _thick; ++_x) - { - if (x2 == x1) - { - _zwy1 = y1; - _zwy2 = y2; - } - else - { - _zwy1 = (y2 - y1) * (float)(_x - x1) / (float)(x2 - x1) + y1; - _zwy2 = (y2 - y1) * (float)(_x + 1 - x1) / (float)(x2 - x1) + y1; - } - - for (_y = _zwy1 - _thick; _y <= _zwy2 + _thick; _y++) - if (isInImage(_x, _y)) - setPixelColor(_x, _y, r, g, b); - } -} - -void CImageBasis::drawCircle(int x1, int y1, int rad, int r, int g, int b, int thickness) -{ - float deltarad, aktrad; - int _thick, _x, _y; - - deltarad = 1 / (4 * M_PI * (rad + thickness - 1)); - - for (aktrad = 0; aktrad <= (2 * M_PI); aktrad += deltarad) - for (_thick = 0; _thick < thickness; ++_thick) - { - _x = sin(aktrad) * (rad + _thick) + x1; - _y = cos(aktrad) * (rad + _thick) + y1; - if (isInImage(_x, _y)) - setPixelColor(_x, _y, r, g, b); - } -} - -CImageBasis::CImageBasis() -{ - this->externalImage = false; -} - -CImageBasis::CImageBasis(std::string _image) -{ - channels = 3; - externalImage = false; - filename = _image; -// long freebefore = esp_get_free_heap_size(); - - rgb_image = stbi_load(_image.c_str(), &width, &height, &bpp, channels); -// if (rgb_image == NULL) -// LogFile.WriteToFile("Image Load failed:" + _image + " FreeHeapSize before: " + to_string(freebefore) + " after: " + to_string(esp_get_free_heap_size())); - // printf("CImageBasis after load\n"); - // printf("w %d, h %d, b %d, c %d", this->width, this->height, this->bpp, this->channels); -} - -bool CImageBasis::ImageOkay(){ - return rgb_image != NULL; -} - -CImageBasis::CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) -{ - this->rgb_image = _rgb_image; - this->channels = _channels; - this->width = _width; - this->height = _height; - this->bpp = _bpp; - this->externalImage = true; -} - -void CImageBasis::Contrast(float _contrast) //input range [-100..100] -{ - stbi_uc* p_source; - - float contrast = (_contrast/100) + 1; //convert to decimal & shift range: [0..2] - float intercept = 128 * (1 - contrast); - - for (int x = 0; x < width; ++x) - for (int y = 0; y < height; ++y) - { - p_source = this->rgb_image + (this->channels * (y * this->width + x)); - for (int channels = 0; channels < this->channels; ++channels) - p_source[channels] = (uint8_t) std::min(255, std::max(0, (int) (p_source[channels] * contrast + intercept))); - } -} - -CImageBasis::~CImageBasis() -{ - if (!this->externalImage) - stbi_image_free(this->rgb_image); -} - -void CImageBasis::SaveToFile(std::string _imageout) -{ - string typ = getFileType(_imageout); - - if ((typ == "jpg") || (typ == "JPG")) // ACHTUNG PROBLEMATISCH IM ESP32 - { - stbi_write_jpg(_imageout.c_str(), this->width, this->height, this->channels, this->rgb_image, 0); - } - - if ((typ == "bmp") || (typ == "BMP")) - { - stbi_write_bmp(_imageout.c_str(), this->width, this->height, this->channels, this->rgb_image); - } - // stbi_write_jpg(_imageout.c_str(), this->width, this->height, this->channels, this->rgb_image, 0); - // stbi_write_bmp(_imageout.c_str(), this->width, this->height, this->channels, this->rgb_image); -} - - - -void CAlignAndCutImage::Align(std::string _template0, int ref0_x, int ref0_y, std::string _template1, int ref1_x, int ref1_y, int deltax, int deltay, std::string imageROI) -{ - int dx, dy; - int r0_x, r0_y, r1_x, r1_y; - - CFindTemplate* ft = new CFindTemplate(this->filename); - - r0_x = ref0_x; - r0_y = ref0_y; - ft->FindTemplate(_template0, &r0_x, &r0_y, deltax, deltay); - t0_dx = ft->tpl_width; - t0_dy = ft->tpl_height; - - r1_x = ref1_x; - r1_y = ref1_y; - ft->FindTemplate(_template1, &r1_x, &r1_y, deltax, deltay); - t1_dx = ft->tpl_width; - t1_dy = ft->tpl_height; - - delete ft; - - - dx = ref0_x - r0_x; - dy = ref0_y - r0_y; - - r0_x += dx; - r0_y += dy; - - r1_x += dx; - r1_y += dy; - - float w_org, w_ist, d_winkel; - - w_org = atan2(ref1_y - ref0_y, ref1_x - ref0_x); - w_ist = atan2(r1_y - r0_y, r1_x - r0_x); - - d_winkel = (w_org - w_ist) * 180 / M_PI; - - if (imageROI.length() > 0) - { - CImageBasis* imgzw = new CImageBasis(this->filename); - imgzw->drawRect(r0_x, r0_y, t0_dx, t0_dy, 255, 0, 0, 2); - imgzw->drawRect(r1_x, r1_y, t1_dx, t1_dy, 255, 0, 0, 2); - imgzw->SaveToFile(imageROI); - printf("Alignment: alignment ROI created: %s\n", imageROI.c_str()); - delete imgzw; - } - - string zw = "\tdx:\t" + to_string(dx) + "\tdy:\t" + to_string(dy) + "\td_winkel:\t" + to_string(d_winkel); - LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zw); - - CRotate rt(this->rgb_image, this->channels, this->width, this->height, this->bpp); - rt.Translate(dx, dy); - rt.Rotate(d_winkel, ref0_x, ref0_y); - printf("Alignment: dx %d - dy %d - rot %f\n", dx, dy, d_winkel); -} - -void CAlignAndCutImage::CutAndSave(std::string _template1, int x1, int y1, int dx, int dy) -{ - - int x2, y2; - - x2 = x1 + dx; - y2 = y1 + dy; - x2 = min(x2, this->width - 1); - y2 = min(y2, this->height - 1); - - dx = x2 - x1; - dy = y2 - y1; - - int memsize = dx * dy * this->channels; - uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); - - stbi_uc* p_target; - stbi_uc* p_source; - - for (int x = x1; x < x2; ++x) - for (int y = y1; y < y2; ++y) - { - p_target = odata + (this->channels * ((y - y1) * dx + (x - x1))); - p_source = this->rgb_image + (this->channels * (y * this->width + x)); - for (int channels = 0; channels < this->channels; ++channels) - p_target[channels] = p_source[channels]; - } - - // stbi_write_jpg(_template1.c_str(), dx, dy, this->channels, odata, 0); - stbi_write_bmp(_template1.c_str(), dx, dy, this->channels, odata); - - stbi_image_free(odata); -} diff --git a/code/components/jomjol_image_proc/CFindTemplate.h b/code/components/jomjol_image_proc/CFindTemplate.h index 0023d666..c32c6672 100644 --- a/code/components/jomjol_image_proc/CFindTemplate.h +++ b/code/components/jomjol_image_proc/CFindTemplate.h @@ -1,98 +1,16 @@ -#pragma once +#include "CImageBasis.h" -#ifndef __CFINDTEMPLATE -#define __CFINGTEMPLATE - -#include -#include - -#define _USE_MATH_DEFINES -#include - -#include "stb_image.h" -#include "stb_image_write.h" -#include "stb_image_resize.h" - - -class CImageBasis -{ - protected: - uint8_t* rgb_image; - int channels; - int width, height, bpp; - bool externalImage; - std::string filename; - - void memCopy(uint8_t* _source, uint8_t* _target, int _size); - bool isInImage(int x, int y); - - public: - int getWidth(){return this->width;}; - int getHeight(){return this->height;}; - int getChannels(){return this->channels;}; - void drawRect(int x, int y, int dx, int dy, int r = 255, int g = 255, int b = 255, int thickness = 1); - void drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int thickness = 1); - void drawCircle(int x1, int y1, int rad, int r, int g, int b, int thickness = 1); - void setPixelColor(int x, int y, int r, int g, int b); - void Contrast(float _contrast); - bool ImageOkay(); - - - CImageBasis(); - CImageBasis(std::string _image); - CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp); - uint8_t GetPixelColor(int x, int y, int ch); - - ~CImageBasis(); - - void SaveToFile(std::string _imageout); -}; - class CFindTemplate : public CImageBasis { public: int tpl_width, tpl_height, tpl_bpp; - CFindTemplate(std::string _image); +// CFindTemplate(std::string _image); + CFindTemplate(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {}; + void FindTemplate(std::string _template, int* found_x, int* found_y, std::string _imageout); void FindTemplate(std::string _template, int* found_x, int* found_y, int _dx, int _dy, std::string _imageout); void FindTemplate(std::string _template, int* found_x, int* found_y); void FindTemplate(std::string _template, int* found_x, int* found_y, int _dx, int _dy); -}; - -class CRotate: public CImageBasis -{ - public: - CRotate(std::string _image) : CImageBasis(_image) {}; - CRotate(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {}; - - void Rotate(float _angle); - void Rotate(float _angle, int _centerx, int _centery); - void Translate(int _dx, int _dy); - void Mirror(); -}; - - -class CAlignAndCutImage : public CImageBasis -{ - public: - int t0_dx, t0_dy, t1_dx, t1_dy; - CAlignAndCutImage(std::string _image) : CImageBasis(_image) {}; - - void Align(std::string _template1, int x1, int y1, std::string _template2, int x2, int y2, int deltax = 40, int deltay = 40, std::string imageROI = ""); - void CutAndSave(std::string _template1, int x1, int y1, int dx, int dy); -}; - - -class CResizeImage : public CImageBasis -{ -public: - CResizeImage(std::string _image) : CImageBasis(_image) {}; -// CResizeImage(std::string _image, int _new_dx, int _new_dy); - void Resize(int _new_dx, int _new_dy); -}; - - -#endif - +}; \ No newline at end of file diff --git a/code/components/jomjol_image_proc/CImageBasis.cpp b/code/components/jomjol_image_proc/CImageBasis.cpp new file mode 100644 index 00000000..9033af43 --- /dev/null +++ b/code/components/jomjol_image_proc/CImageBasis.cpp @@ -0,0 +1,436 @@ +#include "CImageBasis.h" +#include "Helper.h" +#include "ClassLogFile.h" + +#include + +#include "esp_system.h" + +#include + + +#define _USE_MATH_DEFINES +#include +#include + +#define _ESP32_PSRAM + +using namespace std; + +static const char *TAG = "CImageBasis"; + + + +void writejpghelp(void *context, void *data, int size) +{ +// printf("Size all: %d, size %d\n", ((ImageData*)context)->size, size); + ImageData* _zw = (ImageData*) context; + uint8_t *voidstart = _zw->data; + uint8_t *datastart = (uint8_t*) data; + voidstart += _zw->size; + + for (int i = 0; i < size; ++i) + *(voidstart + i) = *(datastart + i); + + _zw->size += size; +} + + + + +ImageData* CImageBasis::writeToMemoryAsJPG(const int quality) +{ + ImageData* ii = new ImageData; + + stbi_write_jpg_to_func(writejpghelp, ii, width, height, channels, rgb_image, quality); + + return ii; +} + +#define HTTP_BUFFER_SENT 1024 + +struct SendJPGHTTP +{ + httpd_req_t *req; + esp_err_t res; + char buf[HTTP_BUFFER_SENT]; + int size = 0; +}; + +inline void writejpgtohttphelp(void *context, void *data, int size) +{ + SendJPGHTTP* _send = (SendJPGHTTP*) context; + if ((_send->size + size) >= HTTP_BUFFER_SENT) // data passt nich mehr in buffer + { + httpd_req_t *_req = _send->req; + if (httpd_resp_send_chunk(_req, _send->buf, _send->size) != ESP_OK) + { + ESP_LOGE(TAG, "File sending failed!"); + _send->res = ESP_FAIL; + } + _send->size = 0; + } + std::memcpy((void*) (&(_send->buf[0]) + _send->size), data, size); + _send->size+= size; +} + + + +esp_err_t CImageBasis::SendJPGtoHTTP(httpd_req_t *_req, const int quality) +{ + SendJPGHTTP ii; + ii.req = _req; + ii.res = ESP_OK; + ii.size = 0; + + stbi_write_jpg_to_func(writejpgtohttphelp, &ii, width, height, channels, rgb_image, quality); + + if (ii.size > 0) + { + if (httpd_resp_send_chunk(_req, (char*) ii.buf, ii.size) != ESP_OK) // verschicke noch den Rest + { + ESP_LOGE(TAG, "File sending failed!"); + ii.res = ESP_FAIL; + } + } + + return ii.res; +} + + + +bool CImageBasis::CopyFromMemory(uint8_t* _source, int _size) +{ + int gr = height * width * channels; + if (gr != _size) // Größe passt nicht + { + printf("Kann Bild nicht von Speicher kopierte - Größen passen nicht zusammen: soll %d, ist %d\n", _size, gr); + return false; + } + memCopy(_source, rgb_image, _size); + + return true; +} + +uint8_t CImageBasis::GetPixelColor(int x, int y, int ch) +{ + stbi_uc* p_source; + p_source = rgb_image + (channels * (y * width + x)); + return p_source[ch]; +} + + +void CImageBasis::memCopy(uint8_t* _source, uint8_t* _target, int _size) +{ +#ifdef _ESP32_PSRAM + for (int i = 0; i < _size; ++i) + *(_target + i) = *(_source + i); +#else + memcpy(_target, _source, _size); +#endif +} + +bool CImageBasis::isInImage(int x, int y) +{ + if ((x < 0) || (x > width - 1)) + return false; + + if ((y < 0) || (y > height- 1)) + return false; + + return true; +} + +void CImageBasis::setPixelColor(int x, int y, int r, int g, int b) +{ + stbi_uc* p_source; + + p_source = rgb_image + (channels * (y * width + x)); + p_source[0] = r; + if ( channels > 2) + { + p_source[1] = g; + p_source[2] = b; + } +} + +void CImageBasis::drawRect(int x, int y, int dx, int dy, int r, int g, int b, int thickness) +{ + int zwx1, zwx2, zwy1, zwy2; + int _x, _y, _thick; + + zwx1 = x - thickness + 1; + zwx2 = x + dx + thickness - 1; + zwy1 = y; + zwy2 = y; + for (_thick = 0; _thick < thickness; _thick++) + for (_x = zwx1; _x <= zwx2; ++_x) + for (_y = zwy1; _y <= zwy2; _y++) + if (isInImage(_x, _y)) + setPixelColor(_x, _y - _thick, r, g, b); + + zwx1 = x - thickness + 1; + zwx2 = x + dx + thickness - 1; + zwy1 = y + dy; + zwy2 = y + dy; + for (_thick = 0; _thick < thickness; _thick++) + for (_x = zwx1; _x <= zwx2; ++_x) + for (_y = zwy1; _y <= zwy2; _y++) + if (isInImage(_x, _y)) + setPixelColor(_x, _y + _thick, r, g, b); + + zwx1 = x; + zwx2 = x; + zwy1 = y; + zwy2 = y + dy; + for (_thick = 0; _thick < thickness; _thick++) + for (_x = zwx1; _x <= zwx2; ++_x) + for (_y = zwy1; _y <= zwy2; _y++) + if (isInImage(_x, _y)) + setPixelColor(_x - _thick, _y, r, g, b); + + zwx1 = x + dx; + zwx2 = x + dx; + zwy1 = y; + zwy2 = y + dy; + for (_thick = 0; _thick < thickness; _thick++) + for (_x = zwx1; _x <= zwx2; ++_x) + for (_y = zwy1; _y <= zwy2; _y++) + if (isInImage(_x, _y)) + setPixelColor(_x + _thick, _y, r, g, b); + +} + +void CImageBasis::drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int thickness) +{ + int _x, _y, _thick; + int _zwy1, _zwy2; + thickness = (thickness-1) / 2; + + for (_thick = 0; _thick <= thickness; ++_thick) + for (_x = x1 - _thick; _x <= x2 + _thick; ++_x) + { + if (x2 == x1) + { + _zwy1 = y1; + _zwy2 = y2; + } + else + { + _zwy1 = (y2 - y1) * (float)(_x - x1) / (float)(x2 - x1) + y1; + _zwy2 = (y2 - y1) * (float)(_x + 1 - x1) / (float)(x2 - x1) + y1; + } + + for (_y = _zwy1 - _thick; _y <= _zwy2 + _thick; _y++) + if (isInImage(_x, _y)) + setPixelColor(_x, _y, r, g, b); + } +} + +void CImageBasis::drawCircle(int x1, int y1, int rad, int r, int g, int b, int thickness) +{ + float deltarad, aktrad; + int _thick, _x, _y; + + deltarad = 1 / (4 * M_PI * (rad + thickness - 1)); + + for (aktrad = 0; aktrad <= (2 * M_PI); aktrad += deltarad) + for (_thick = 0; _thick < thickness; ++_thick) + { + _x = sin(aktrad) * (rad + _thick) + x1; + _y = cos(aktrad) * (rad + _thick) + y1; + if (isInImage(_x, _y)) + setPixelColor(_x, _y, r, g, b); + } +} + +CImageBasis::CImageBasis() +{ + externalImage = false; +} + +void CImageBasis::CreateEmptyImage(int _width, int _height, int _channels) +{ + bpp = _channels; + width = _width; + height = _height; + channels = _channels; + + int memsize = width * height * channels; + rgb_image = (unsigned char*)GET_MEMORY(memsize); + + + stbi_uc* p_source; + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + p_source = rgb_image + (channels * (y * width + x)); + for (int _channels = 0; _channels < channels; ++_channels) + p_source[_channels] = (uint8_t) 0; + } + + +} + +void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len) +{ +// if (rgb_image) +// free(rgb_image); + rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, 3); + bpp = channels; +// STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); + +} + +CImageBasis::CImageBasis(CImageBasis *_copyfrom, int _anzrepeat) +{ + externalImage = false; + channels = _copyfrom->channels; + width = _copyfrom->width; + height = _copyfrom->height; + bpp = _copyfrom->bpp; + + int memsize = width * height * channels; + rgb_image = (unsigned char*)GET_MEMORY(memsize); + + int anz = 1; + TickType_t xDelay; + while (!rgb_image && (anz < _anzrepeat)) + { + printf("Create Image from Copy - Speicher ist voll - Versuche es erneut: %d.\n", anz); + xDelay = 1000 / portTICK_PERIOD_MS; + rgb_image = (unsigned char*) malloc(memsize); + anz++; + } + + + if (!rgb_image) + { + printf(getESPHeapInfo().c_str()); + printf("\nKein freier Speicher mehr!!!! Benötigt: %d %d %d %d\n", width, height, channels, memsize); + return; + } + + memCopy(_copyfrom->rgb_image, rgb_image, memsize); +} + +CImageBasis::CImageBasis(int _width, int _height, int _channels) +{ + externalImage = false; + channels = _channels; + width = _width; + height = _height; + bpp = _channels; + + int memsize = width * height * channels; + rgb_image = (unsigned char*)GET_MEMORY(memsize); + if (!rgb_image) + { + printf(getESPHeapInfo().c_str()); + printf("\nKein freier Speicher mehr!!!! Benötigt: %d %d %d %d\n", width, height, channels, memsize); + return; + } +} + + +CImageBasis::CImageBasis(std::string _image) +{ + channels = 3; + externalImage = false; + filename = _image; + long zwld = esp_get_free_heap_size(); + printf("freeheapsize before: %ld\n", zwld); + + rgb_image = stbi_load(_image.c_str(), &width, &height, &bpp, channels); + zwld = esp_get_free_heap_size(); + printf("freeheapsize after : %ld\n", zwld); + + std::string zw = "Image Load failed:" + _image + "\n"; + if (rgb_image == NULL) + printf(zw.c_str()); + zw = "CImageBasis after load " + _image + "\n"; + printf(zw.c_str()); + printf("w %d, h %d, b %d, c %d\n", width, height, bpp, channels); +} + +bool CImageBasis::ImageOkay(){ + return rgb_image != NULL; +} + +CImageBasis::CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) +{ + rgb_image = _rgb_image; + channels = _channels; + width = _width; + height = _height; + bpp = _bpp; + externalImage = true; +} + +void CImageBasis::Contrast(float _contrast) //input range [-100..100] +{ + stbi_uc* p_source; + + float contrast = (_contrast/100) + 1; //convert to decimal & shift range: [0..2] + float intercept = 128 * (1 - contrast); + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + p_source = rgb_image + (channels * (y * width + x)); + for (int _channels = 0; _channels < channels; ++_channels) + p_source[_channels] = (uint8_t) std::min(255, std::max(0, (int) (p_source[_channels] * contrast + intercept))); + } +} + +CImageBasis::~CImageBasis() +{ + if (!externalImage) + stbi_image_free(rgb_image); +} + +void CImageBasis::SaveToFile(std::string _imageout) +{ + string typ = getFileType(_imageout); + + if ((typ == "jpg") || (typ == "JPG")) // ACHTUNG PROBLEMATISCH IM ESP32 + { + stbi_write_jpg(_imageout.c_str(), width, height, channels, rgb_image, 0); + } + + if ((typ == "bmp") || (typ == "BMP")) + { + stbi_write_bmp(_imageout.c_str(), width, height, channels, rgb_image); + } +} + + +void CImageBasis::Resize(int _new_dx, int _new_dy) +{ + int memsize = _new_dx * _new_dy * channels; + uint8_t* odata = (unsigned char*)GET_MEMORY(memsize); + + stbir_resize_uint8(rgb_image, width, height, 0, odata, _new_dx, _new_dy, 0, channels); + + stbi_image_free(rgb_image); + rgb_image = (unsigned char*)GET_MEMORY(memsize); + + memCopy(odata, rgb_image, memsize); + width = _new_dx; + height = _new_dy; + stbi_image_free(odata); +} + +void CImageBasis::Resize(int _new_dx, int _new_dy, CImageBasis *_target) +{ + if ((_target->height != _new_dy) || (_target->width != _new_dx) || (_target->channels != channels)) + { + printf("CImageBasis::Resize - Targetbildgröße passt nicht !!!!!!!!!"); + return; + } + + uint8_t* odata = _target->rgb_image; + stbir_resize_uint8(rgb_image, width, height, 0, odata, _new_dx, _new_dy, 0, channels); +} + diff --git a/code/components/jomjol_image_proc/CImageBasis.h b/code/components/jomjol_image_proc/CImageBasis.h new file mode 100644 index 00000000..65f822b2 --- /dev/null +++ b/code/components/jomjol_image_proc/CImageBasis.h @@ -0,0 +1,88 @@ +#pragma once + +#ifndef __CIMAGEBASIS +#define __CIMAGEBASIS + +#include +#include +#include + +#define _USE_MATH_DEFINES +#include + +#include "stb_image.h" +#include "stb_image_write.h" +#include "stb_image_resize.h" + +#include "esp_heap_caps.h" + +//#define GET_MEMORY malloc +#define GET_MEMORY(X) heap_caps_malloc(X, MALLOC_CAP_SPIRAM) + + +#define MAX_JPG_SIZE 128000 + + +struct ImageData +{ + uint8_t data[MAX_JPG_SIZE]; + size_t size = 0; +}; + + + +class CImageBasis +{ + protected: + bool externalImage; + std::string filename; + + void memCopy(uint8_t* _source, uint8_t* _target, int _size); + bool isInImage(int x, int y); + + public: + uint8_t* rgb_image; + int channels; + int width, height, bpp; + + int getWidth(){return this->width;}; + int getHeight(){return this->height;}; + int getChannels(){return this->channels;}; + void drawRect(int x, int y, int dx, int dy, int r = 255, int g = 255, int b = 255, int thickness = 1); + void drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int thickness = 1); + void drawCircle(int x1, int y1, int rad, int r, int g, int b, int thickness = 1); + void setPixelColor(int x, int y, int r, int g, int b); + void Contrast(float _contrast); + bool ImageOkay(); + bool CopyFromMemory(uint8_t* _source, int _size); + + void SetIndepended(){externalImage = false;}; + + void CreateEmptyImage(int _width, int _height, int _channels); + + + CImageBasis(); + CImageBasis(std::string _image); + CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp); + CImageBasis(int _width, int _height, int _channels); + CImageBasis(CImageBasis *_copyfrom, int _anzrepeat = 0); + + void Resize(int _new_dx, int _new_dy); + void Resize(int _new_dx, int _new_dy, CImageBasis *_target); + + void LoadFromMemory(stbi_uc *_buffer, int len); + + ImageData* writeToMemoryAsJPG(const int quality = 90); + + esp_err_t SendJPGtoHTTP(httpd_req_t *req, const int quality = 90); + + uint8_t GetPixelColor(int x, int y, int ch); + + ~CImageBasis(); + + void SaveToFile(std::string _imageout); +}; + + +#endif + diff --git a/code/components/jomjol_image_proc/CMakeLists.txt b/code/components/jomjol_image_proc/CMakeLists.txt index df20b56b..806966b1 100644 --- a/code/components/jomjol_image_proc/CMakeLists.txt +++ b/code/components/jomjol_image_proc/CMakeLists.txt @@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*) idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "." - REQUIRES jomjol_helper jomjol_logfile) + REQUIRES jomjol_helper jomjol_logfile esp_http_server) diff --git a/code/components/jomjol_image_proc/CRotateImage.cpp b/code/components/jomjol_image_proc/CRotateImage.cpp new file mode 100644 index 00000000..53edbf43 --- /dev/null +++ b/code/components/jomjol_image_proc/CRotateImage.cpp @@ -0,0 +1,171 @@ +#include "CRotateImage.h" + + +CRotateImage::CRotateImage(CImageBasis *_org, CImageBasis *_temp) +{ + rgb_image = _org->rgb_image; + channels = _org->channels; + width = _org->width; + height = _org->height; + bpp = _org->bpp; + externalImage = true; + ImageTMP = _temp; +} + +void CRotateImage::Mirror(){ + int memsize = width * height * channels; + uint8_t* odata; + if (ImageTMP) + { + odata = ImageTMP->rgb_image; + } + else + { + odata = (unsigned char*)GET_MEMORY(memsize); + } + + + int x_source, y_source; + stbi_uc* p_target; + stbi_uc* p_source; + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + p_target = odata + (channels * (y * width + x)); + + x_source = width - x; + y_source = y; + + p_source = rgb_image + (channels * (y_source * width + x_source)); + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = p_source[_channels]; + } + + // memcpy(rgb_image, odata, memsize); + memCopy(odata, rgb_image, memsize); + if (!ImageTMP) + { + stbi_image_free(odata); + } +} + +void CRotateImage::Rotate(float _angle, int _centerx, int _centery) +{ + float m[2][3]; + + float x_center = _centerx; + float y_center = _centery; + _angle = _angle / 180 * M_PI; + + m[0][0] = cos(_angle); + m[0][1] = sin(_angle); + m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center; + + m[1][0] = -m[0][1]; + m[1][1] = m[0][0]; + m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center; + + int memsize = width * height * channels; + uint8_t* odata; + if (ImageTMP) + { + odata = ImageTMP->rgb_image; + } + else + { + odata = (unsigned char*)GET_MEMORY(memsize); + } + + + int x_source, y_source; + stbi_uc* p_target; + stbi_uc* p_source; + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + p_target = odata + (channels * (y * width + x)); + + x_source = int(m[0][0] * x + m[0][1] * y); + y_source = int(m[1][0] * x + m[1][1] * y); + + x_source += int(m[0][2]); + y_source += int(m[1][2]); + + if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height)) + { + p_source = rgb_image + (channels * (y_source * width + x_source)); + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = p_source[_channels]; + } + else + { + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = 255; + } + } + + // memcpy(rgb_image, odata, memsize); + memCopy(odata, rgb_image, memsize); + + if (!ImageTMP) + { + stbi_image_free(odata); + } +} + +void CRotateImage::Rotate(float _angle) +{ +// printf("width %d, height %d\n", width, height); + Rotate(_angle, width / 2, height / 2); +} + +void CRotateImage::Translate(int _dx, int _dy) +{ + int memsize = width * height * channels; + uint8_t* odata; + if (ImageTMP) + { + odata = ImageTMP->rgb_image; + } + else + { + odata = (unsigned char*)GET_MEMORY(memsize); + } + + + + int x_source, y_source; + stbi_uc* p_target; + stbi_uc* p_source; + + for (int x = 0; x < width; ++x) + for (int y = 0; y < height; ++y) + { + p_target = odata + (channels * (y * width + x)); + + x_source = x - _dx; + y_source = y - _dy; + + if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height)) + { + p_source = rgb_image + (channels * (y_source * width + x_source)); + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = p_source[_channels]; + } + else + { + for (int _channels = 0; _channels < channels; ++_channels) + p_target[_channels] = 255; + } + } + + // memcpy(rgb_image, odata, memsize); + memCopy(odata, rgb_image, memsize); + if (!ImageTMP) + { + stbi_image_free(odata); + } +} + diff --git a/code/components/jomjol_image_proc/CRotateImage.h b/code/components/jomjol_image_proc/CRotateImage.h new file mode 100644 index 00000000..ccd362b4 --- /dev/null +++ b/code/components/jomjol_image_proc/CRotateImage.h @@ -0,0 +1,16 @@ +#include "CImageBasis.h" + + +class CRotateImage: public CImageBasis +{ + public: + CImageBasis *ImageTMP; + CRotateImage(std::string _image) : CImageBasis(_image) {ImageTMP = NULL;}; + CRotateImage(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL;}; + CRotateImage(CImageBasis *_org, CImageBasis *_temp); + + void Rotate(float _angle); + void Rotate(float _angle, int _centerx, int _centery); + void Translate(int _dx, int _dy); + void Mirror(); +}; diff --git a/code/components/jomjol_logfile/ClassLogFile.cpp b/code/components/jomjol_logfile/ClassLogFile.cpp index d134448b..ad525fd5 100644 --- a/code/components/jomjol_logfile/ClassLogFile.cpp +++ b/code/components/jomjol_logfile/ClassLogFile.cpp @@ -10,6 +10,48 @@ static const char *TAG = "log"; ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt"); +void ClassLogFile::WriteHeapInfo(std::string _id) +{ + std::string _zw; + _zw = "\t" + _id + "\t" + getESPHeapInfo(); + WriteToFile(_zw); +} + + +std::string ClassLogFile::getESPHeapInfo(){ + string espInfoResultStr = ""; + char aMsgBuf[80]; + + multi_heap_info_t aMultiHead_info ; + heap_caps_get_info (&aMultiHead_info,MALLOC_CAP_8BIT); + size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t aMinFreeHeadSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT); + size_t aMinFreeHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT); + size_t aHeapLargestFreeBlockSize = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT); + sprintf(aMsgBuf,"Free Heap Size: \t%ld", (long) aFreeHeapSize); + size_t aFreeSPIHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_SPIRAM); + size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL); + size_t aMinFreeInternalHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL); + + sprintf(aMsgBuf,"\tHeap:\t%ld", (long) aFreeHeapSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf,"\tMin Free:\t%ld", (long) aMinFreeHeapSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf,"\tlarg. Block: \t%ld", (long) aHeapLargestFreeBlockSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf,"\tSPI Heap:\t%ld", (long) aFreeSPIHeapSize); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf,"\tMin Free Heap Size:\t%ld", (long) aMinFreeHeadSize); + sprintf(aMsgBuf,"\tNOT_SPI Heap:\t%ld", (long) (aFreeHeapSize - aFreeSPIHeapSize)); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf,"\tlargest Block Size: \t%ld", (long) aHeapLargestFreeBlockSize); + sprintf(aMsgBuf,"\tInternal Heap:\t%ld", (long) (aFreeInternalHeapSize)); + espInfoResultStr += string(aMsgBuf); + sprintf(aMsgBuf,"\tInternal Min Heap free:\t%ld", (long) (aMinFreeInternalHeapSize)); + espInfoResultStr += string(aMsgBuf); + return espInfoResultStr; +} + void ClassLogFile::WriteToDedicatedFile(std::string _fn, std::string info, bool _time) { FILE* pFile; @@ -19,7 +61,9 @@ void ClassLogFile::WriteToDedicatedFile(std::string _fn, std::string info, bool return; } - pFile = OpenFileAndWait(_fn.c_str(), "a+"); +// pFile = OpenFileAndWait(_fn.c_str(), "a"); + pFile = fopen(_fn.c_str(), "a+"); + printf("Logfile opened: %s\n", _fn.c_str()); if (pFile!=NULL) { if (_time) @@ -55,6 +99,7 @@ void ClassLogFile::SetRetention(unsigned short _retentionInDays){ void ClassLogFile::WriteToFile(std::string info, bool _time) { +/* struct stat path_stat; if (stat(logroot.c_str(), &path_stat) != 0) { ESP_LOGI(TAG, "Create log folder: %s", logroot.c_str()); @@ -62,7 +107,7 @@ void ClassLogFile::WriteToFile(std::string info, bool _time) ESP_LOGI(TAG, "Can't create log foolder"); } } - +*/ time_t rawtime; struct tm* timeinfo; char buffer[30]; @@ -80,12 +125,12 @@ std::string ClassLogFile::GetCurrentFileName() { time_t rawtime; struct tm* timeinfo; - char buffer[30]; + char buffer[60]; time(&rawtime); timeinfo = localtime(&rawtime); - strftime(buffer, 30, logfile.c_str(), timeinfo); + strftime(buffer, 60, logfile.c_str(), timeinfo); std::string logpath = logroot + "/" + buffer; return logpath; diff --git a/code/components/jomjol_logfile/ClassLogFile.h b/code/components/jomjol_logfile/ClassLogFile.h index 8f7841ba..b4a3429c 100644 --- a/code/components/jomjol_logfile/ClassLogFile.h +++ b/code/components/jomjol_logfile/ClassLogFile.h @@ -12,6 +12,10 @@ private: public: ClassLogFile(std::string _logpath, std::string _logfile); + std::string getESPHeapInfo(); + + void WriteHeapInfo(std::string _id); + void SwitchOnOff(bool _doLogFile); void SetRetention(unsigned short _retentionInDays); diff --git a/code/components/jomjol_tfliteclass/CTfLiteClass.cpp b/code/components/jomjol_tfliteclass/CTfLiteClass.cpp index 14458d38..ed7db106 100644 --- a/code/components/jomjol_tfliteclass/CTfLiteClass.cpp +++ b/code/components/jomjol_tfliteclass/CTfLiteClass.cpp @@ -1,9 +1,8 @@ #include "CTfLiteClass.h" -#include "bitmap_image.hpp" +// #include "bitmap_image.hpp" #include "ClassLogFile.h" - #include "Helper.h" #include @@ -21,19 +20,16 @@ float CTfLiteClass::GetOutputValue(int nr) return output2->data.f[nr]; } - -int CTfLiteClass::GetClassFromImage(std::string _fn) +int CTfLiteClass::GetClassFromImageBasis(CImageBasis *rs) { // printf("Before Load image %s\n", _fn.c_str()); - if (!LoadInputImage(_fn)) + if (!LoadInputImageBasis(rs)) return -1000; -// printf("After Load image %s\n", _fn.c_str()); Invoke(); - printf("After Invoke %s\n", _fn.c_str()); + printf("After Invoke \n"); return GetOutClassification(); -// return 0; } int CTfLiteClass::GetOutClassification() @@ -113,17 +109,14 @@ void CTfLiteClass::Invoke() } -bool CTfLiteClass::LoadInputImage(std::string _fn) + +bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs) { - std::string zw = "ClassFlowAnalog::doNeuralNetwork nach Load Image: " + _fn; -// LogFile.WriteToFile(zw); - bitmap_image image(_fn); - if (debugdetailtflite) LogFile.WriteToFile(zw); + std::string zw = "ClassFlowAnalog::doNeuralNetwork nach LoadInputResizeImage: "; - unsigned int w = image.width(); - unsigned int h = image.height(); + unsigned int w = rs->width; + unsigned int h = rs->height; unsigned char red, green, blue; - // printf("Image: %s size: %d x %d\n", _fn.c_str(), w, h); input_i = 0; @@ -132,18 +125,15 @@ bool CTfLiteClass::LoadInputImage(std::string _fn) for (int y = 0; y < h; ++y) for (int x = 0; x < w; ++x) { - red = image.red_channel(x, y); - green = image.green_channel(x, y); - blue = image.blue_channel(x, y); + red = rs->GetPixelColor(x, y, 0); + green = rs->GetPixelColor(x, y, 1); + blue = rs->GetPixelColor(x, y, 2); *(input_data_ptr) = (float) red; input_data_ptr++; *(input_data_ptr) = (float) green; input_data_ptr++; *(input_data_ptr) = (float) blue; input_data_ptr++; - -// printf("BMP: %f %f %f\n", (float) red, (float) green, (float) blue); - } if (debugdetailtflite) LogFile.WriteToFile("Nach dem Laden in input"); @@ -154,7 +144,6 @@ bool CTfLiteClass::LoadInputImage(std::string _fn) void CTfLiteClass::MakeAllocate() { -// static tflite::ops::micro::AllOpsResolver resolver; static tflite::AllOpsResolver resolver; this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter); @@ -164,7 +153,6 @@ void CTfLiteClass::MakeAllocate() this->GetInputDimension(); return; } - // printf("Allocate Done.\n"); } @@ -172,8 +160,6 @@ void CTfLiteClass::GetInputTensorSize(){ float *zw = this->input; int test = sizeof(zw); printf("Input Tensor Dimension: %d\n", test); - - printf("Input Tensor Dimension: %d\n", test); } long CTfLiteClass::GetFileSize(std::string filename) @@ -188,7 +174,7 @@ unsigned char* CTfLiteClass::ReadFileToCharArray(std::string _fn) { long size; - size = this->GetFileSize(_fn); + size = GetFileSize(_fn); if (size == -1) { @@ -196,16 +182,25 @@ unsigned char* CTfLiteClass::ReadFileToCharArray(std::string _fn) return NULL; } - unsigned char *result = (unsigned char*) malloc(size); + int anz = 1; + TickType_t xDelay; + while (!result && (anz < 6)) // maximal 5x versuchen (= 5s) + { + printf("Speicher ist voll - Versuche es erneut: %d.\n", anz); + xDelay = 1000 / portTICK_PERIOD_MS; + result = (unsigned char*) malloc(size); + anz++; + } + - if(result != NULL) { + if(result != NULL) { // printf("\nSpeicher ist reserviert\n"); FILE* f = OpenFileAndWait(_fn.c_str(), "rb"); // vorher nur "r" fread(result, 1, size, f); fclose(f); - }else { - printf("\nKein freier Speicher vorhanden.\n"); + }else { + printf("\nKein freier Speicher vorhanden.\n"); } @@ -221,14 +216,11 @@ void CTfLiteClass::LoadModel(std::string _fn){ #endif unsigned char *rd; - rd = this->ReadFileToCharArray(_fn.c_str()); -// printf("loadedfile: %d", (int) rd); + rd = ReadFileToCharArray(_fn.c_str()); this->model = tflite::GetModel(rd); free(rd); TFLITE_MINIMAL_CHECK(model != nullptr); -// printf("tfile Loaded.\n"); - } @@ -239,7 +231,7 @@ CTfLiteClass::CTfLiteClass() this->interpreter = nullptr; this->input = nullptr; this->output = nullptr; - this->kTensorArenaSize = 600 * 1024; + this->kTensorArenaSize = 150 * 1024; /// laut testfile: 108000 - bisher 600 this->tensor_arena = new uint8_t[kTensorArenaSize]; } @@ -257,6 +249,6 @@ namespace tflite { return 0; } -} // namespace tflite +} diff --git a/code/components/jomjol_tfliteclass/CTfLiteClass.h b/code/components/jomjol_tfliteclass/CTfLiteClass.h index 1350a86a..c4bd057e 100644 --- a/code/components/jomjol_tfliteclass/CTfLiteClass.h +++ b/code/components/jomjol_tfliteclass/CTfLiteClass.h @@ -14,6 +14,8 @@ #include "esp_err.h" #include "esp_log.h" +#include "CImageBasis.h" + #define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE @@ -39,7 +41,6 @@ class CTfLiteClass const tflite::Model* model; tflite::MicroInterpreter* interpreter; TfLiteTensor* output = nullptr; -// static tflite::ops::micro::AllOpsResolver *resolver; static tflite::AllOpsResolver resolver; int kTensorArenaSize; @@ -58,11 +59,11 @@ class CTfLiteClass void LoadModel(std::string _fn); void MakeAllocate(); void GetInputTensorSize(); - bool LoadInputImage(std::string _fn); + bool LoadInputImageBasis(CImageBasis *rs); void Invoke(); void GetOutPut(); int GetOutClassification(); - int GetClassFromImage(std::string _fn); + int GetClassFromImageBasis(CImageBasis *rs); float GetOutputValue(int nr); void GetInputDimension(bool silent); diff --git a/code/components/jomjol_tfliteclass/server_tflite.cpp b/code/components/jomjol_tfliteclass/server_tflite.cpp index efe6ab21..5d4e76e3 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.cpp +++ b/code/components/jomjol_tfliteclass/server_tflite.cpp @@ -24,11 +24,32 @@ TaskHandle_t xHandleblink_task_doFlow = NULL; TaskHandle_t xHandletask_autodoFlow = NULL; + + bool flowisrunning = false; long auto_intervall = 0; bool auto_isrunning = false; + +int countRounds = 0; + +int getCountFlowRounds() { + return countRounds; +} + + + +esp_err_t GetJPG(std::string _filename, httpd_req_t *req) +{ + return tfliteflow.GetJPGStream(_filename, req); +} + +esp_err_t GetRawJPG(httpd_req_t *req) +{ + return tfliteflow.SendRawJPG(req); +} + bool isSetupModusActive() { return tfliteflow.getStatusSetupModus(); return false; @@ -91,6 +112,8 @@ void blink_task_doFlow(void *pvParameter) esp_err_t handler_init(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_init - Start"); + LogFile.WriteToFile("handler_init"); printf("handler_doinit uri:\n"); printf(req->uri); printf("\n"); @@ -104,11 +127,15 @@ esp_err_t handler_init(httpd_req_t *req) /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_init - Done"); + return ESP_OK; }; esp_err_t handler_doflow(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_doflow - Start"); + LogFile.WriteToFile("handler_doflow"); char* resp_str; @@ -127,7 +154,9 @@ esp_err_t handler_doflow(httpd_req_t *req) 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); + httpd_resp_send_chunk(req, NULL, 0); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_doflow - Done"); + return ESP_OK; }; @@ -136,6 +165,8 @@ esp_err_t handler_doflow(httpd_req_t *req) esp_err_t handler_wasserzaehler(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_wasserzaehler - Start"); + LogFile.WriteToFile("handler_wasserzaehler"); bool _rawValue = false; bool _noerror = false; @@ -171,7 +202,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req) { string txt, zw; - txt = "

Aligned Image:

\n"; + txt = "

Aligned Image:

\n"; txt = txt + "Digital Counter:

"; httpd_resp_sendstr_chunk(req, txt.c_str()); @@ -205,7 +236,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req) httpd_resp_sendstr_chunk(req, txt.c_str()); delete htmlinfo[i]; } - htmlinfo.clear(); + htmlinfo.clear(); } @@ -217,12 +248,15 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req) /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_sendstr_chunk(req, NULL); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_wasserzaehler - Done"); + return ESP_OK; }; esp_err_t handler_editflow(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_editflow - Start"); LogFile.WriteToFile("handler_editflow"); printf("handler_editflow uri: "); printf(req->uri); printf("\n"); @@ -324,6 +358,7 @@ esp_err_t handler_editflow(httpd_req_t *req) zw = "CutImage Done"; httpd_resp_sendstr_chunk(req, zw.c_str()); + } if (_task.compare("test_take") == 0) @@ -378,6 +413,7 @@ esp_err_t handler_editflow(httpd_req_t *req) /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_sendstr_chunk(req, NULL); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_editflow - Done"); return ESP_OK; }; @@ -385,6 +421,8 @@ esp_err_t handler_editflow(httpd_req_t *req) esp_err_t handler_prevalue(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_prevalue - Start"); + LogFile.WriteToFile("handler_prevalue"); const char* resp_str; string zw; @@ -414,6 +452,8 @@ esp_err_t handler_prevalue(httpd_req_t *req) /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); + if (debug_detail_heap) LogFile.WriteHeapInfo("handler_prevalue - Start"); + return ESP_OK; }; @@ -434,7 +474,8 @@ void task_autodoFlow(void *pvParameter) while (auto_isrunning) { - LogFile.WriteToFile("task_autodoFlow - next round"); + std::string _zw = "task_autodoFlow - next round - Round #" + std::to_string(++countRounds); + LogFile.WriteToFile(_zw); printf("Autoflow: start\n"); fr_start = esp_timer_get_time(); diff --git a/code/components/jomjol_tfliteclass/server_tflite.h b/code/components/jomjol_tfliteclass/server_tflite.h index 68fc1dbc..da778839 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.h +++ b/code/components/jomjol_tfliteclass/server_tflite.h @@ -1,6 +1,7 @@ #include #include +#include "CImageBasis.h" //#include "ClassControllCamera.h" @@ -12,4 +13,10 @@ void KillTFliteTasks(); void TFliteDoAutoStart(); -bool isSetupModusActive(); \ No newline at end of file +bool isSetupModusActive(); + +esp_err_t GetJPG(std::string _filename, httpd_req_t *req); + +esp_err_t GetRawJPG(httpd_req_t *req); + +extern bool debug_detail_heap; \ No newline at end of file diff --git a/code/components/jomjol_time_sntp/time_sntp.cpp b/code/components/jomjol_time_sntp/time_sntp.cpp index da746ebd..4be9b8f2 100644 --- a/code/components/jomjol_time_sntp/time_sntp.cpp +++ b/code/components/jomjol_time_sntp/time_sntp.cpp @@ -1,11 +1,5 @@ #include "time_sntp.h" -/* LwIP SNTP example - This example code is in the Public Domain (or CC0 licensed, at your option.) - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ #include #include #include @@ -17,25 +11,19 @@ #include "esp_log.h" #include "esp_attr.h" #include "esp_sleep.h" -// #include "nvs_flash.h" -// #include "protocol_examples_common.h" #include "esp_sntp.h" #include "ClassLogFile.h" static const char *TAG = "sntp"; -RTC_DATA_ATTR int boot_count = 0; - bool setTimeAlwaysOnReboot = true; static void obtain_time(void); static void initialize_sntp(void); - void time_sync_notification_cb(struct timeval *tv) { -// LogFile.WriteToFile("Notification of a time synchronization event"); ESP_LOGI(TAG, "Notification of a time synchronization event"); } @@ -54,9 +42,6 @@ std::string gettimestring(const char * frm) void setup_time() { - ++boot_count; - ESP_LOGI(TAG, "Boot count: %d", boot_count); - time_t now; struct tm timeinfo; time(&now); @@ -72,8 +57,6 @@ void setup_time() char strftime_buf[64]; setTimeZone("CET-1CEST,M3.5.0,M10.5.0/3"); -// setTimeZone("Europe/Berlin"); -// setTimeZone("Asia/Tokyo"); localtime_r(&now, &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); @@ -97,9 +80,6 @@ void setTimeZone(std::string _tzstring) static void obtain_time(void) { -// initialize_sntp(); - - // wait for time to be set time_t now = 0; struct tm timeinfo = {}; int retry = 0; @@ -110,18 +90,23 @@ static void obtain_time(void) ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); vTaskDelay(2000 / portTICK_PERIOD_MS); } - if (retry == retry_count) { -// LogFile.WriteToFile("Time Synchzronisation nicht erfolgreich ..."); - } - else - { -// LogFile.WriteToFile("Time erfolgreich ..."); - } time(&now); localtime_r(&now, &timeinfo); } +void reset_servername(std::string _servername) +{ + printf("Set SNTP-Server: %s\n", _servername.c_str()); + sntp_stop(); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, _servername.c_str()); + sntp_init(); + obtain_time(); + std::string zw = gettimestring("%Y%m%d-%H%M%S"); + printf("Time ist %s\n", zw.c_str()); +} + static void initialize_sntp(void) { ESP_LOGI(TAG, "Initializing SNTP"); diff --git a/code/components/jomjol_time_sntp/time_sntp.h b/code/components/jomjol_time_sntp/time_sntp.h index 3238e68a..930bfa35 100644 --- a/code/components/jomjol_time_sntp/time_sntp.h +++ b/code/components/jomjol_time_sntp/time_sntp.h @@ -15,4 +15,5 @@ void setup_time(void); std::string gettimestring(const char * frm); -void setTimeZone(std::string _tzstring); \ No newline at end of file +void setTimeZone(std::string _tzstring); +void reset_servername(std::string _servername); \ No newline at end of file diff --git a/code/main/main.cpp b/code/main/main.cpp index b44e58c3..d3af8b91 100644 --- a/code/main/main.cpp +++ b/code/main/main.cpp @@ -28,6 +28,9 @@ static const char *TAGMAIN = "connect_wlan_main"; + +bool debug_detail_heap = false; + #define FLASH_GPIO GPIO_NUM_4 void Init_NVS_SDCard() @@ -44,10 +47,15 @@ void Init_NVS_SDCard() // sdmmc_host_t host = SDMMC_HOST_SLOT_1(); // host.flags = SDMMC_HOST_FLAG_1BIT; sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + slot_config.width = 1; // 1 line SD mode + esp_vfs_fat_sdmmc_mount_config_t mount_config = { }; mount_config.format_if_mount_failed = false; mount_config.max_files = 5; + gpio_set_pull_mode((gpio_num_t) 15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes + gpio_set_pull_mode((gpio_num_t) 2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes + sdmmc_card_t* card; ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card); if (ret != ESP_OK) { @@ -116,7 +124,9 @@ extern "C" void app_main(void) vTaskDelay( xDelay ); // LogFile.WriteToFile("Startsequence 07"); setup_time(); - LogFile.WriteToFile("============================== Main Started ======================================="); + LogFile.WriteToFile("============================================================================================="); + LogFile.WriteToFile("=================================== Main Started ============================================"); + LogFile.WriteToFile("============================================================================================="); LogFile.SwitchOnOff(false); std::string zw = gettimestring("%Y%m%d-%H%M%S"); diff --git a/code/main/server_main.cpp b/code/main/server_main.cpp index 084dca5d..c71e6e2c 100644 --- a/code/main/server_main.cpp +++ b/code/main/server_main.cpp @@ -18,13 +18,14 @@ httpd_handle_t server = NULL; - std::string starttime = ""; /* An HTTP GET handler */ esp_err_t info_get_handler(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("info_get_handler - Start"); + LogFile.WriteToFile("info_get_handler"); char _query[200]; char _valuechar[30]; @@ -125,25 +126,31 @@ esp_err_t info_get_handler(httpd_req_t *req) return ESP_OK; } + if (debug_detail_heap) LogFile.WriteHeapInfo("info_get_handler - Done"); return ESP_OK; } esp_err_t starttime_get_handler(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("starttime_get_handler - Start"); httpd_resp_send(req, starttime.c_str(), strlen(starttime.c_str())); /* Respond with an empty chunk to signal HTTP response completion */ - httpd_resp_send_chunk(req, NULL, 0); + httpd_resp_send_chunk(req, NULL, 0); + + if (debug_detail_heap) LogFile.WriteHeapInfo("starttime_get_handler - Done"); return ESP_OK; } esp_err_t hello_main_handler(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("hello_main_handler - Start"); + char filepath[50]; - struct stat file_stat; printf("uri: %s\n", req->uri); int _pos; + esp_err_t res; char *base_path = (char*) req->user_ctx; std::string filetosend(base_path); @@ -182,60 +189,35 @@ esp_err_t hello_main_handler(httpd_req_t *req) httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long"); return ESP_FAIL; } - if (stat(filetosend.c_str(), &file_stat) == -1) { - /* If file not present on SPIFFS check if URI - * corresponds to one of the hardcoded paths */ - ESP_LOGE(TAG, "Failed to stat file : %s", filetosend.c_str()); - /* Respond with 404 Not Found */ - httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist"); - return ESP_FAIL; - } - esp_err_t res; - res = httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - if (res != ESP_OK) - return res; - res = send_file(req, filetosend, &file_stat); + res = send_file(req, filetosend); if (res != ESP_OK) return res; /* Respond with an empty chunk to signal HTTP response completion */ httpd_resp_send_chunk(req, NULL, 0); + + if (debug_detail_heap) LogFile.WriteHeapInfo("hello_main_handler - Stop"); + return ESP_OK; } esp_err_t img_tmp_handler(httpd_req_t *req) { char filepath[50]; - struct stat file_stat; printf("uri: %s\n", req->uri); char *base_path = (char*) req->user_ctx; std::string filetosend(base_path); const char *filename = get_path_from_uri(filepath, base_path, - req->uri + sizeof("/img_tmp") - 1, sizeof(filepath)); + req->uri + sizeof("/img_tmp/") - 1, sizeof(filepath)); printf("1 uri: %s, filename: %s, filepath: %s\n", req->uri, filename, filepath); filetosend = filetosend + "/img_tmp/" + std::string(filename); printf("File to upload: %s\n", filetosend.c_str()); - if (!filename) { - ESP_LOGE(TAG, "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; - } - if (stat(filetosend.c_str(), &file_stat) == -1) { - /* If file not present on SPIFFS check if URI - * corresponds to one of the hardcoded paths */ - ESP_LOGE(TAG, "Failed to stat file : %s", filetosend.c_str()); - /* Respond with 404 Not Found */ - httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist"); - return ESP_FAIL; - } - - esp_err_t res = send_file(req, filetosend, &file_stat); + esp_err_t res = send_file(req, filetosend); if (res != ESP_OK) return res; @@ -244,8 +226,47 @@ esp_err_t img_tmp_handler(httpd_req_t *req) return ESP_OK; } +esp_err_t img_tmp_virtual_handler(httpd_req_t *req) +{ + if (debug_detail_heap) LogFile.WriteHeapInfo("img_tmp_virtual_handler - Start"); + char filepath[50]; + + printf("uri: %s\n", req->uri); + + char *base_path = (char*) req->user_ctx; + std::string filetosend(base_path); + + const char *filename = get_path_from_uri(filepath, base_path, + req->uri + sizeof("/img_tmp/") - 1, sizeof(filepath)); + printf("1 uri: %s, filename: %s, filepath: %s\n", req->uri, filename, filepath); + + filetosend = std::string(filename); + printf("File to upload: %s\n", filetosend.c_str()); + + if (filetosend == "raw.jpg") + { + return GetRawJPG(req); + } + + esp_err_t zw = GetJPG(filetosend, req); + + if (zw == ESP_OK) + return ESP_OK; + + // File wird nicht intern bereit gestellt --> klassischer weg: + if (debug_detail_heap) LogFile.WriteHeapInfo("img_tmp_virtual_handler - Done"); + + return img_tmp_handler(req); +} + + + + + esp_err_t sysinfo_handler(httpd_req_t *req) { + if (debug_detail_heap) LogFile.WriteHeapInfo("sysinfo_handler - Start"); + const char* resp_str; std::string zw; std::string cputemp = std::to_string(temperatureRead()); @@ -279,7 +300,9 @@ esp_err_t sysinfo_handler(httpd_req_t *req) httpd_resp_set_type(req, "application/json"); 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); + httpd_resp_send_chunk(req, NULL, 0); + + if (debug_detail_heap) LogFile.WriteHeapInfo("sysinfo_handler - Done"); return ESP_OK; } @@ -314,7 +337,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path) httpd_uri_t img_tmp_handle = { .uri = "/img_tmp/*", // Match all URIs of type /path/to/file .method = HTTP_GET, - .handler = img_tmp_handler, + .handler = img_tmp_virtual_handler, .user_ctx = (void*) base_path // Pass server data as context }; httpd_register_uri_handler(server, &img_tmp_handle); diff --git a/code/main/server_main.h b/code/main/server_main.h index 16a851ed..bab0665e 100644 --- a/code/main/server_main.h +++ b/code/main/server_main.h @@ -22,9 +22,7 @@ httpd_handle_t start_webserver(void); void register_server_main_uri(httpd_handle_t server, const char *base_path); - -//void disconnect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); -//void connect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); +extern bool debug_detail_heap; #endif diff --git a/code/main/version.cpp b/code/main/version.cpp index 74c9015a..9b392b66 100644 --- a/code/main/version.cpp +++ b/code/main/version.cpp @@ -1,4 +1,4 @@ -const char* GIT_REV="793f928"; +const char* GIT_REV="6e521f0"; const char* GIT_TAG=""; -const char* GIT_BRANCH="rolling"; -const char* BUILD_TIME="2020-12-07 20:40"; \ No newline at end of file +const char* GIT_BRANCH="rolling-reduce-sd-use"; +const char* BUILD_TIME="2020-12-28 15:38"; \ No newline at end of file diff --git a/code/sdkconfig b/code/sdkconfig index dd11c44e..7028733c 100644 --- a/code/sdkconfig +++ b/code/sdkconfig @@ -537,8 +537,8 @@ CONFIG_FATFS_MAX_LFN=255 CONFIG_FATFS_API_ENCODING_ANSI_OEM=y # CONFIG_FATFS_API_ENCODING_UTF_16 is not set # CONFIG_FATFS_API_ENCODING_UTF_8 is not set -CONFIG_FATFS_FS_LOCK=5 -CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_FS_LOCK=10 +CONFIG_FATFS_TIMEOUT_MS=5000 CONFIG_FATFS_PER_FILE_CACHE=y CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # end of FAT Filesystem support @@ -965,7 +965,7 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y # # Virtual file system # -CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT is not set CONFIG_VFS_SUPPORT_TERMIOS=y # @@ -1166,6 +1166,6 @@ CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set -CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT is not set CONFIG_SUPPORT_TERMIOS=y # End of deprecated options diff --git a/code/sdkconfig.old b/code/sdkconfig.old index 88827b07..f8a0f2c5 100644 --- a/code/sdkconfig.old +++ b/code/sdkconfig.old @@ -83,11 +83,11 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set CONFIG_ESPTOOLPY_FLASHFREQ="40m" # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="2MB" +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y CONFIG_ESPTOOLPY_BEFORE_RESET=y # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set @@ -315,8 +315,8 @@ CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 # CONFIG_ESP32_ULP_COPROC_ENABLED is not set CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 -# CONFIG_ESP32_PANIC_PRINT_HALT is not set -CONFIG_ESP32_PANIC_PRINT_REBOOT=y +CONFIG_ESP32_PANIC_PRINT_HALT=y +# CONFIG_ESP32_PANIC_PRINT_REBOOT is not set # CONFIG_ESP32_PANIC_SILENT_REBOOT is not set # CONFIG_ESP32_PANIC_GDBSTUB is not set CONFIG_ESP32_DEBUG_OCDAWARE=y @@ -537,8 +537,8 @@ CONFIG_FATFS_MAX_LFN=255 CONFIG_FATFS_API_ENCODING_ANSI_OEM=y # CONFIG_FATFS_API_ENCODING_UTF_16 is not set # CONFIG_FATFS_API_ENCODING_UTF_8 is not set -CONFIG_FATFS_FS_LOCK=5 -CONFIG_FATFS_TIMEOUT_MS=10000 +CONFIG_FATFS_FS_LOCK=10 +CONFIG_FATFS_TIMEOUT_MS=5000 CONFIG_FATFS_PER_FILE_CACHE=y CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # end of FAT Filesystem support @@ -965,7 +965,7 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y # # Virtual file system # -CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT is not set CONFIG_VFS_SUPPORT_TERMIOS=y # @@ -1166,6 +1166,6 @@ CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set -CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y +# CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT is not set CONFIG_SUPPORT_TERMIOS=y # End of deprecated options diff --git a/code/version.cpp b/code/version.cpp index 74c9015a..9b392b66 100644 --- a/code/version.cpp +++ b/code/version.cpp @@ -1,4 +1,4 @@ -const char* GIT_REV="793f928"; +const char* GIT_REV="6e521f0"; const char* GIT_TAG=""; -const char* GIT_BRANCH="rolling"; -const char* BUILD_TIME="2020-12-07 20:40"; \ No newline at end of file +const char* GIT_BRANCH="rolling-reduce-sd-use"; +const char* BUILD_TIME="2020-12-28 15:38"; \ No newline at end of file diff --git a/firmware/bootloader.bin b/firmware/bootloader.bin index dc68b2b7..c8b1fb30 100644 Binary files a/firmware/bootloader.bin and b/firmware/bootloader.bin differ diff --git a/firmware/firmware.bin b/firmware/firmware.bin index c81a80d6..cef9643b 100644 Binary files a/firmware/firmware.bin and b/firmware/firmware.bin differ diff --git a/firmware/html.zip b/firmware/html.zip index 9d1ae20c..6ced1d3a 100644 Binary files a/firmware/html.zip and b/firmware/html.zip differ diff --git a/sd-card/html/edit_config_param.html b/sd-card/html/edit_config_param.html index 1b995808..8383c18f 100644 --- a/sd-card/html/edit_config_param.html +++ b/sd-card/html/edit_config_param.html @@ -123,7 +123,7 @@ textarea { @@ -570,16 +570,16 @@ textarea { - - - - TimeUpdateIntervall + - + TimeServer + + + - Intervall for synchronizing the time with the time server (in hours) + Time server to synchronize system time (default: "pool.ntp.org" - used if nothing is specified) @@ -717,7 +717,7 @@ function UpdateInput() { WriteParameter(param, "Debug", "LogfileRetentionInDays", true); WriteParameter(param, "System", "TimeZone", true); - WriteParameter(param, "System", "TimeUpdateIntervall", true); + WriteParameter(param, "System", "TimeServer", true); } function WriteConfig(){ @@ -762,7 +762,7 @@ function WriteConfig(){ ReadParameter(param, "Debug", "LogfileRetentionInDays", true); ReadParameter(param, "System", "TimeZone", true); - ReadParameter(param, "System", "TimeUpdateIntervall", true); + ReadParameter(param, "System", "TimeServer", true); FormatDecimalValue(param, "PostProcessing", "MaxRateValue"); diff --git a/sd-card/html/edit_reference.html b/sd-card/html/edit_reference.html index 34e02678..0ea705dd 100644 --- a/sd-card/html/edit_reference.html +++ b/sd-card/html/edit_reference.html @@ -87,7 +87,7 @@ table { } function loadRawImage(){ - url = basepath + "/fileserver/img_tmp/raw.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1); + url = basepath + "/img_tmp/raw.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1); document.getElementById("finerotate").value = 0; document.getElementById("prerotateangle").value = getPreRotate(); document.getElementById("mirror").checked = getMirror(); diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index ddd5903e..9c31994d 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -72,9 +72,9 @@ function ParseConfig() { var catname = "System"; param[catname] = new Object(); ParamAddValue(param, catname, "TimeZone"); + ParamAddValue(param, catname, "TimeServer"); ParamAddValue(param, catname, "AutoAdjustSummertime"); - ParamAddValue(param, catname, "TimeUpdateIntervall"); - ParamAddValue(param, catname, "SetupMode"); + ParamAddValue(param, catname, "SetupMode"); while (aktline < config_split.length){ if (config_split[aktline].trim().toUpperCase() == "[MAKEIMAGE]") { @@ -149,6 +149,7 @@ function ParseConfigParamSystem(_aktline){ var linesplit = ZerlegeZeile(input, " ="); ParamExtractValue(param, linesplit, catname, "TimeZone", _aktline, isCom); + ParamExtractValue(param, linesplit, catname, "TimeServer", _aktline, isCom); ParamExtractValue(param, linesplit, catname, "AutoAdjustSummertime", _aktline, isCom); ParamExtractValue(param, linesplit, catname, "TimeUpdateIntervall", _aktline, isCom); ParamExtractValue(param, linesplit, catname, "SetupMode", _aktline, isCom); diff --git a/sd-card/html/version.txt b/sd-card/html/version.txt index 4a36342f..fcdb2e10 100644 --- a/sd-card/html/version.txt +++ b/sd-card/html/version.txt @@ -1 +1 @@ -3.0.0 +4.0.0