From f1129930c0575eaa56dd2b321b27b591181cd6b2 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Mon, 6 May 2024 12:26:55 +1000 Subject: [PATCH 01/20] Add support for OV5640 camera --- .../ClassControllCamera.cpp | 206 +++++++++++------- .../ClassControllCamera.h | 1 + code/sdkconfig.defaults | 3 +- sd-card/html/edit_reference.html | 8 +- 4 files changed, 135 insertions(+), 83 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 5095cb16a..8528ea5a0 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -151,6 +151,9 @@ esp_err_t CCamera::InitCam(void) case OV3660_PID: ESP_LOGI(TAG, "OV3660 camera module detected"); break; + case OV5640_PID: + ESP_LOGI(TAG, "OV5640 camera module detected"); + break; default: ESP_LOGE(TAG, "Camera module is unknown and not properly supported!"); CCstatus.CameraInitSuccessful = false; @@ -325,97 +328,129 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) } } + +void CCamera::SanitizeZoomOffset(int frameSizeX, int frameSizeY, int imageWidth, int imageHeight, int &zoomOffsetX, int &zoomOffsetY) +{ + int _offsetx = zoomOffsetX; + int _offsety = zoomOffsetY; + int _maxX = 0; + int _maxY = 0; + + _maxX = frameSizeX - imageWidth; + _maxY = frameSizeY - imageHeight; + + if ((abs(_offsetx) * 2) > _maxX) + { + if (_offsetx > 0) + { + _offsetx = _maxX; + } + else + { + _offsetx = 0; + } + } + else + { + if (_offsetx > 0) + { + // wenn der Wert von _offsetx nicht durch 8 teilbar ist, + // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) + _offsetx = ((_maxX / 2) + _offsetx); + } + else + { + // wenn der Wert von _offsetx nicht durch 8 teilbar ist, + // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) + _offsetx = ((_maxX / 2) + _offsetx); + } + } + + if ((abs(_offsety) * 2) > _maxY) + { + if (_offsety > 0) + { + _offsety = _maxY; + } + else + { + _offsety = 0; + } + } + else + { + if (_offsety > 0) + { + // wenn der Wert von _offsety nicht durch 8 teilbar ist, + // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) + _offsety = ((_maxY / 2) + _offsety); + } + else + { + // wenn der Wert von _offsety nicht durch 8 teilbar ist, + // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) + _offsety = ((_maxY / 2) + _offsety); + } + } + + zoomOffsetX = _offsetx; + zoomOffsetY = _offsety; +} + + void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) { sensor_t *s = esp_camera_sensor_get(); if (s != NULL) { - if (zoomEnabled) + camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); + if (zoomEnabled && (sensor_info != NULL)) { - // ov2640_sensor_mode_t _mode = OV2640_MODE_UXGA; // 1600x1200 - // ov2640_sensor_mode_t _mode = OV2640_MODE_SVGA; // 800x600 - // ov2640_sensor_mode_t _mode = OV2640_MODE_CIF; // 400x296 - int _mode = 0; - int _offsetx = zoomOffsetX; int _offsety = zoomOffsetY; - int _imageSize_temp = 0; - int _maxX = 0; - int _maxY = 0; - - if (imageSize < 29) + if (sensor_info->model == CAMERA_OV5640) { - _imageSize_temp = (29 - imageSize); - } + int frameSizeX = 2560; + int frameSizeY = 1920; + SanitizeZoomOffset(frameSizeX, frameSizeY, CCstatus.ImageWidth, CCstatus.ImageHeight, _offsetx, _offsety); - // This works only if the aspect ratio of 4:3 is preserved in the window size. - // use values divisible by 8 without remainder - int _imageWidth = CCstatus.ImageWidth + (_imageSize_temp * 4 * 8); - int _imageHeight = CCstatus.ImageHeight + (_imageSize_temp * 3 * 8); + s->set_res_raw(s, _offsetx, _offsety, _offsetx + CCstatus.ImageWidth, _offsety + CCstatus.ImageHeight, 0, 0, frameSizeX, frameSizeY, CCstatus.ImageWidth, CCstatus.ImageHeight, false, false); - _maxX = 1600 - _imageWidth; - _maxY = 1200 - _imageHeight; - - if ((abs(_offsetx) * 2) > _maxX) - { - if (_offsetx > 0) - { - _offsetx = _maxX; - } - else - { - _offsetx = 0; - } } - else + else if (sensor_info->model == CAMERA_OV2640) { - if (_offsetx > 0) - { - // wenn der Wert von _offsetx nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsetx = ((_maxX / 2) + _offsetx); - } - else - { - // wenn der Wert von _offsetx nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsetx = ((_maxX / 2) + _offsetx); - } - } + // ov2640_sensor_mode_t _mode = OV2640_MODE_UXGA; // 1600x1200 + // ov2640_sensor_mode_t _mode = OV2640_MODE_SVGA; // 800x600 + // ov2640_sensor_mode_t _mode = OV2640_MODE_CIF; // 400x296 + int _mode = 0; - if ((abs(_offsety) * 2) > _maxY) - { - if (_offsety > 0) - { - _offsety = _maxY; - } - else + int frameSizeX = 1600; + int frameSizeY = 1200; + int _imageSize_temp = 0; + + if (imageSize < 29) { - _offsety = 0; + _imageSize_temp = (29 - imageSize); } + + // This works only if the aspect ratio of 4:3 is preserved in the window size. + // use values divisible by 8 without remainder + int _imageWidth = CCstatus.ImageWidth + (_imageSize_temp * 4 * 8); + int _imageHeight = CCstatus.ImageHeight + (_imageSize_temp * 3 * 8); + SanitizeZoomOffset(frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + + // _mode sets the sensor resolution (3 options available), + // _offsetx and _offsety set the start of the ROI, + // _imageWidth and _imageHeight set the size of the ROI, + // CCstatus.ImageWidth and CCstatus.ImageHeight set the output window size. + SetCamWindow(s, _mode, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + } else { - if (_offsety > 0) - { - // wenn der Wert von _offsety nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsety = ((_maxY / 2) + _offsety); - } - else - { - // wenn der Wert von _offsety nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsety = ((_maxY / 2) + _offsety); - } + s->set_framesize(s, CCstatus.ImageFrameSize); } - - // _mode sets the sensor resolution (3 options available), - // _offsetx and _offsety set the start of the ROI, - // _imageWidth and _imageHeight set the size of the ROI, - // CCstatus.ImageWidth and CCstatus.ImageHeight set the output window size. - SetCamWindow(s, _mode, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); } else { @@ -451,15 +486,30 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) if (s != NULL) { - // post processing - if (_autoSharpnessEnabled) + camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); + if (sensor_info != NULL) { - s->set_sharpness(s, 0); - ov2640_enable_auto_sharpness(s); - } - else - { - ov2640_set_sharpness(s, _sharpnessLevel); + // post processing + if (_autoSharpnessEnabled) + { + if (sensor_info->model == CAMERA_OV2640) + { + ov2640_enable_auto_sharpness(s); + } else { + s->set_sharpness(s, 0); + } + } + else + { + if (sensor_info->model == CAMERA_OV2640) + { + ov2640_set_sharpness(s, _sharpnessLevel); + } + else + { + s->set_sharpness(s, _sharpnessLevel); + } + } } } else diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index b674ead3f..0cbf8e9ca 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -81,6 +81,7 @@ class CCamera long GetFileSize(std::string filename); void SetCamWindow(sensor_t *s, int resolution, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); void SetImageWidthHeightFromResolution(framesize_t resol); + void SanitizeZoomOffset(int frameSizeX, int frameSizeY, int imageWidth, int imageHeight, int &zoomOffsetX, int &zoomOffsetY); public: CCamera(void); diff --git a/code/sdkconfig.defaults b/code/sdkconfig.defaults index e41514a16..0fe530363 100644 --- a/code/sdkconfig.defaults +++ b/code/sdkconfig.defaults @@ -135,7 +135,8 @@ CONFIG_OV7670_SUPPORT=n CONFIG_OV7725_SUPPORT=n CONFIG_NT99141_SUPPORT=n CONFIG_OV3660_SUPPORT=n -CONFIG_OV5640_SUPPORT=n +CONFIG_OV2640_SUPPORT=y +CONFIG_OV5640_SUPPORT=y CONFIG_GC2145_SUPPORT=n CONFIG_GC032A_SUPPORT=n CONFIG_GC0308_SUPPORT=n diff --git a/sd-card/html/edit_reference.html b/sd-card/html/edit_reference.html index d6359bd42..0d3bb1d43 100644 --- a/sd-card/html/edit_reference.html +++ b/sd-card/html/edit_reference.html @@ -184,8 +184,8 @@

Reference Image and Camera Settings

- + $TOOLTIP_TakeImage_CamZoomOffsetX @@ -204,8 +204,8 @@

Reference Image and Camera Settings

- + $TOOLTIP_TakeImage_CamZoomOffsetY From d6741fefad9b064f30f07acb7c22f6406c3cd8a5 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Thu, 9 May 2024 12:54:09 +1000 Subject: [PATCH 02/20] clean up sharpness handling --- .../ClassControllCamera.cpp | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 8528ea5a0..25268f99e 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -480,34 +480,39 @@ void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) { - _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); - sensor_t *s = esp_camera_sensor_get(); if (s != NULL) { + _sharpnessLevel = min(3, max(-3, _sharpnessLevel)); + camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); + if (sensor_info != NULL) { - // post processing - if (_autoSharpnessEnabled) + if (sensor_info->model == CAMERA_OV5640) { - if (sensor_info->model == CAMERA_OV2640) + if (_autoSharpnessEnabled) { - ov2640_enable_auto_sharpness(s); - } else { + // autoSharpness is not supported, default to zero s->set_sharpness(s, 0); } + else + { + s->set_sharpness(s, _sharpnessLevel); + } } else { - if (sensor_info->model == CAMERA_OV2640) + // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. + if (_autoSharpnessEnabled) { - ov2640_set_sharpness(s, _sharpnessLevel); + s->set_sharpness(s, 0); + ov2640_enable_auto_sharpness(s); } else { - s->set_sharpness(s, _sharpnessLevel); + ov2640_set_sharpness(s, _sharpnessLevel); } } } From 8a0da95305fd368f5137444742ae643cde8e9f87 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Thu, 9 May 2024 22:07:30 +1000 Subject: [PATCH 03/20] limit sharpness range to -2 and +2 --- code/components/jomjol_controlcamera/ClassControllCamera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 25268f99e..1581b69ad 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -484,7 +484,7 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) if (s != NULL) { - _sharpnessLevel = min(3, max(-3, _sharpnessLevel)); + _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); From b9c94f6fc0efd12d240b9f1fbeac6205130fc133 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Thu, 9 May 2024 22:08:56 +1000 Subject: [PATCH 04/20] refactor --- .../ClassControllCamera.cpp | 97 +++++++++++-------- .../ClassControllCamera.h | 2 +- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 1581b69ad..444a7b6b3 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -329,8 +329,12 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) } -void CCamera::SanitizeZoomOffset(int frameSizeX, int frameSizeY, int imageWidth, int imageHeight, int &zoomOffsetX, int &zoomOffsetY) +void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY) { + // This works only if the aspect ratio of 4:3 is preserved in the window size. + // use values divisible by 8 without remainder + int _imageWidth = imageWidth + (imageSize * 4 * 8); + int _imageHeight = imageHeight + (imageSize * 3 * 8); int _offsetx = zoomOffsetX; int _offsety = zoomOffsetY; int _maxX = 0; @@ -395,6 +399,8 @@ void CCamera::SanitizeZoomOffset(int frameSizeX, int frameSizeY, int imageWidth, zoomOffsetX = _offsetx; zoomOffsetY = _offsety; + imageWidth = _imageWidth; + imageHeight = _imageHeight; } @@ -407,18 +413,29 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); if (zoomEnabled && (sensor_info != NULL)) { + int _imageSize_temp = 0; + int _imageWidth = CCstatus.ImageWidth; + int _imageHeight = CCstatus.ImageHeight; int _offsetx = zoomOffsetX; int _offsety = zoomOffsetY; if (sensor_info->model == CAMERA_OV5640) { + int unused = 0; + int frameSizeX = 2560; int frameSizeY = 1920; - SanitizeZoomOffset(frameSizeX, frameSizeY, CCstatus.ImageWidth, CCstatus.ImageHeight, _offsetx, _offsety); - s->set_res_raw(s, _offsetx, _offsety, _offsetx + CCstatus.ImageWidth, _offsety + CCstatus.ImageHeight, 0, 0, frameSizeX, frameSizeY, CCstatus.ImageWidth, CCstatus.ImageHeight, false, false); + // imageSize is causing cam_hal: NO-EOI and FB-OVF issues + // if (imageSize < 79) + // { + // _imageSize_temp = (79 - imageSize); + // } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + + SetCamWindow(s, unused, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); } - else if (sensor_info->model == CAMERA_OV2640) + else { // ov2640_sensor_mode_t _mode = OV2640_MODE_UXGA; // 1600x1200 // ov2640_sensor_mode_t _mode = OV2640_MODE_SVGA; // 800x600 @@ -427,18 +444,12 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in int frameSizeX = 1600; int frameSizeY = 1200; - int _imageSize_temp = 0; if (imageSize < 29) { _imageSize_temp = (29 - imageSize); } - - // This works only if the aspect ratio of 4:3 is preserved in the window size. - // use values divisible by 8 without remainder - int _imageWidth = CCstatus.ImageWidth + (_imageSize_temp * 4 * 8); - int _imageHeight = CCstatus.ImageHeight + (_imageSize_temp * 3 * 8); - SanitizeZoomOffset(frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); // _mode sets the sensor resolution (3 options available), // _offsetx and _offsety set the start of the ROI, @@ -447,10 +458,6 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in SetCamWindow(s, _mode, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); } - else - { - s->set_framesize(s, CCstatus.ImageFrameSize); - } } else { @@ -527,43 +534,55 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) * resolution = 0 \\ OV2640_MODE_UXGA -> 1600 x 1200 * resolution = 1 \\ OV2640_MODE_SVGA -> 800 x 600 * resolution = 2 \\ OV2640_MODE_CIF -> 400 x 296 - * resolution = 3 \\ OV2640_MODE_MAX */ void CCamera::SetCamWindow(sensor_t *s, int resolution, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) { - // - (xOffset,yOffset) is the origin of the window in pixels and (xLength,yLength) is the size of the window in pixels. - // - (xOffset,yOffset) ist der Ursprung des Fensters in Pixel und (xLength,yLength) ist die Größe des Fensters in Pixel. + camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); + if (sensor_info != NULL) + { + if (sensor_info->model == CAMERA_OV5640) + { + int frameSizeX = 2560; + int frameSizeY = 1920; + s->set_res_raw(s, xOffset, yOffset, xOffset + xOutput, yOffset + yOutput, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, false, false); + } + else + { + // - (xOffset,yOffset) is the origin of the window in pixels and (xLength,yLength) is the size of the window in pixels. + // - (xOffset,yOffset) ist der Ursprung des Fensters in Pixel und (xLength,yLength) ist die Größe des Fensters in Pixel. - // - Be aware that changing the resolution will effectively overwrite these settings. - // - Beachten Sie, dass eine Änderung der Auflösung diese Einstellungen effektiv überschreibt. + // - Be aware that changing the resolution will effectively overwrite these settings. + // - Beachten Sie, dass eine Änderung der Auflösung diese Einstellungen effektiv überschreibt. - // - This works only if the aspect ratio of 4:3 is preserved in the window size. - // - Dies funktioniert nur, wenn das Seitenverhältnis von 4:3 in der Fenstergröße beibehalten wird. + // - This works only if the aspect ratio of 4:3 is preserved in the window size. + // - Dies funktioniert nur, wenn das Seitenverhältnis von 4:3 in der Fenstergröße beibehalten wird. - // - total_x and total_y defines the size on the sensor - // - total_x und total_y definieren die Größe des Sensors + // - total_x and total_y defines the size on the sensor + // - total_x und total_y definieren die Größe des Sensors - // - width and height defines the resulting image(may be smaller than the size on the sensor) - // - width und height definieren das resultierende Bild (kann kleiner sein als die Größe des Sensor) + // - width and height defines the resulting image(may be smaller than the size on the sensor) + // - width und height definieren das resultierende Bild (kann kleiner sein als die Größe des Sensor) - // - keep the aspect total_x : total_y == width : height - // - Behalten Sie den Aspekt total_x : total_y == width : height bei + // - keep the aspect total_x : total_y == width : height + // - Behalten Sie den Aspekt total_x : total_y == width : height bei - // - use values divisible by 8 without remainder - // - Verwenden Sie Werte, die ohne Rest durch 8 teilbar sind + // - use values divisible by 8 without remainder + // - Verwenden Sie Werte, die ohne Rest durch 8 teilbar sind - // - start with total_x = width and total_y = height, reduce both values by eg.32 pixels - // - Beginnen Sie mit total_x = width und total_y = height und reduzieren Sie beide Werte um z.B.32 Pixel + // - start with total_x = width and total_y = height, reduce both values by eg.32 pixels + // - Beginnen Sie mit total_x = width und total_y = height und reduzieren Sie beide Werte um z.B.32 Pixel - // - next try moving with offset_x or offset_y by 8 pixels - // - Versuchen Sie als Nächstes, mit offset_x oder offset_y um 8 Pixel zu verschieben + // - next try moving with offset_x or offset_y by 8 pixels + // - Versuchen Sie als Nächstes, mit offset_x oder offset_y um 8 Pixel zu verschieben - // set_res_raw(sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning) - // set_window(sensor, (ov2640_sensor_mode_t)startX, offsetX, offsetY, totalX, totalY, outputX, outputY); - // set_window(sensor, mode, offset_x, offset_y, max_x, max_y, w, h); + // set_res_raw(sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning) + // set_window(sensor, (ov2640_sensor_mode_t)startX, offsetX, offsetY, totalX, totalY, outputX, outputY); + // set_window(sensor, mode, offset_x, offset_y, max_x, max_y, w, h); - int unused = 0; - s->set_res_raw(s, resolution, unused, unused, unused, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, unused, unused); + int unused = 0; + s->set_res_raw(s, resolution, unused, unused, unused, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, unused, unused); + } + } } static size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index 0cbf8e9ca..b357b40a3 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -81,7 +81,7 @@ class CCamera long GetFileSize(std::string filename); void SetCamWindow(sensor_t *s, int resolution, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); void SetImageWidthHeightFromResolution(framesize_t resol); - void SanitizeZoomOffset(int frameSizeX, int frameSizeY, int imageWidth, int imageHeight, int &zoomOffsetX, int &zoomOffsetY); + void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); public: CCamera(void); From 90994771c6aeb7362b7d64583b47ffebb67ab2a3 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Fri, 10 May 2024 01:20:02 +1000 Subject: [PATCH 05/20] Fix OV3660 sharpness handling --- code/components/jomjol_controlcamera/ClassControllCamera.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 444a7b6b3..63bcb0493 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -497,7 +497,7 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) if (sensor_info != NULL) { - if (sensor_info->model == CAMERA_OV5640) + if (sensor_info->model == CAMERA_OV5640 || sensor_info->model == CAMERA_OV3660) { if (_autoSharpnessEnabled) { @@ -509,7 +509,7 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) s->set_sharpness(s, _sharpnessLevel); } } - else + else if (sensor_info->model == CAMERA_OV2640) { // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. if (_autoSharpnessEnabled) From d093d50b74b4cba32502d5fea1e21b819766327b Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Fri, 10 May 2024 01:47:50 +1000 Subject: [PATCH 06/20] refactor sharpness handling --- .../jomjol_controlcamera/ClassControllCamera.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 63bcb0493..4b04d8c59 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -497,29 +497,29 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) if (sensor_info != NULL) { - if (sensor_info->model == CAMERA_OV5640 || sensor_info->model == CAMERA_OV3660) + if (sensor_info->model == CAMERA_OV2640) { + // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. if (_autoSharpnessEnabled) { - // autoSharpness is not supported, default to zero - s->set_sharpness(s, 0); + ov2640_enable_auto_sharpness(s); } else { - s->set_sharpness(s, _sharpnessLevel); + ov2640_set_sharpness(s, _sharpnessLevel); } } - else if (sensor_info->model == CAMERA_OV2640) + else { - // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. + // for CAMERA_OV5640 and CAMERA_OV3660 if (_autoSharpnessEnabled) { + // autoSharpness is not supported, default to zero s->set_sharpness(s, 0); - ov2640_enable_auto_sharpness(s); } else { - ov2640_set_sharpness(s, _sharpnessLevel); + s->set_sharpness(s, _sharpnessLevel); } } } From 1ecf8db007b0f66a7ab8a0f82d124effdeaceeff Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Fri, 10 May 2024 01:49:21 +1000 Subject: [PATCH 07/20] fix OV3660 zoom mode --- .../ClassControllCamera.cpp | 99 ++++++++++--------- .../ClassControllCamera.h | 2 +- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 4b04d8c59..6c4471433 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -413,50 +413,58 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); if (zoomEnabled && (sensor_info != NULL)) { + int unused = 0; + int _mode = 0; int _imageSize_temp = 0; int _imageWidth = CCstatus.ImageWidth; int _imageHeight = CCstatus.ImageHeight; int _offsetx = zoomOffsetX; int _offsety = zoomOffsetY; - if (sensor_info->model == CAMERA_OV5640) + int frameSizeX; + int frameSizeY; + switch (sensor_info->model) { - int unused = 0; - - int frameSizeX = 2560; - int frameSizeY = 1920; - - // imageSize is causing cam_hal: NO-EOI and FB-OVF issues - // if (imageSize < 79) - // { - // _imageSize_temp = (79 - imageSize); - // } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - - SetCamWindow(s, unused, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - - } - else - { - // ov2640_sensor_mode_t _mode = OV2640_MODE_UXGA; // 1600x1200 - // ov2640_sensor_mode_t _mode = OV2640_MODE_SVGA; // 800x600 - // ov2640_sensor_mode_t _mode = OV2640_MODE_CIF; // 400x296 - int _mode = 0; - - int frameSizeX = 1600; - int frameSizeY = 1200; - - if (imageSize < 29) - { - _imageSize_temp = (29 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - - // _mode sets the sensor resolution (3 options available), - // _offsetx and _offsety set the start of the ROI, - // _imageWidth and _imageHeight set the size of the ROI, - // CCstatus.ImageWidth and CCstatus.ImageHeight set the output window size. - SetCamWindow(s, _mode, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - + case CAMERA_OV5640: + frameSizeX = 2560; + frameSizeY = 1920; + // imageSize is causing cam_hal: NO-EOI and FB-OVF issues + // if (imageSize < 79) + // { + // _imageSize_temp = (79 - imageSize); + // } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, unused, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case CAMERA_OV3660: + frameSizeX = 2048; + frameSizeY = 1536; + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, unused, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case CAMERA_OV2640: + // ov2640_sensor_mode_t _mode = OV2640_MODE_UXGA; // 1600x1200 + // ov2640_sensor_mode_t _mode = OV2640_MODE_SVGA; // 800x600 + // ov2640_sensor_mode_t _mode = OV2640_MODE_CIF; // 400x296 + _mode = 0; + frameSizeX = 1600; + frameSizeY = 1200; + if (imageSize < 29) + { + _imageSize_temp = (29 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + // _mode sets the sensor resolution (3 options available), + // _offsetx and _offsety set the start of the ROI, + // _imageWidth and _imageHeight set the size of the ROI, + // CCstatus.ImageWidth and CCstatus.ImageHeight set the output window size. + SetCamWindow(s, _mode, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + default: + // do nothing + break; } } else @@ -535,18 +543,12 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) * resolution = 1 \\ OV2640_MODE_SVGA -> 800 x 600 * resolution = 2 \\ OV2640_MODE_CIF -> 400 x 296 */ -void CCamera::SetCamWindow(sensor_t *s, int resolution, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) +void CCamera::SetCamWindow(sensor_t *s, int resolution, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) { camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); if (sensor_info != NULL) { - if (sensor_info->model == CAMERA_OV5640) - { - int frameSizeX = 2560; - int frameSizeY = 1920; - s->set_res_raw(s, xOffset, yOffset, xOffset + xOutput, yOffset + yOutput, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, false, false); - } - else + if (sensor_info->model == CAMERA_OV2640) { // - (xOffset,yOffset) is the origin of the window in pixels and (xLength,yLength) is the size of the window in pixels. // - (xOffset,yOffset) ist der Ursprung des Fensters in Pixel und (xLength,yLength) ist die Größe des Fensters in Pixel. @@ -582,6 +584,11 @@ void CCamera::SetCamWindow(sensor_t *s, int resolution, int xOffset, int yOffset int unused = 0; s->set_res_raw(s, resolution, unused, unused, unused, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, unused, unused); } + else + { + // for CAMERA_OV5640 and CAMERA_OV3660 + s->set_res_raw(s, xOffset, yOffset, xOffset + xOutput, yOffset + yOutput, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, false, false); + } } } diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index b357b40a3..96c2d6a1d 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -79,7 +79,7 @@ class CCamera void ledc_init(void); bool loadNextDemoImage(camera_fb_t *fb); long GetFileSize(std::string filename); - void SetCamWindow(sensor_t *s, int resolution, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); + void SetCamWindow(sensor_t *s, int resolution, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); void SetImageWidthHeightFromResolution(framesize_t resol); void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); From 9189a2a5ad03d82af004401c6a1aa89b7c534d1e Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Fri, 10 May 2024 10:47:05 +1000 Subject: [PATCH 08/20] reinstate aspect ratio via imageSize --- .../ClassControllCamera.cpp | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 6c4471433..047f34b90 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -425,13 +425,12 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in switch (sensor_info->model) { case CAMERA_OV5640: - frameSizeX = 2560; - frameSizeY = 1920; - // imageSize is causing cam_hal: NO-EOI and FB-OVF issues - // if (imageSize < 79) - // { - // _imageSize_temp = (79 - imageSize); - // } + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 + // 59 = ((2560 - 640) / 8 / 4) - 1 + if (imageSize < 59) + { + _imageSize_temp = (59 - imageSize); + } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); SetCamWindow(s, unused, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); break; @@ -439,6 +438,12 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in case CAMERA_OV3660: frameSizeX = 2048; frameSizeY = 1536; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 43 = ((2048 - 640) / 8 / 4) - 1 + if (imageSize < 43) + { + _imageSize_temp = (43 - imageSize); + } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); SetCamWindow(s, unused, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); break; @@ -450,6 +455,8 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _mode = 0; frameSizeX = 1600; frameSizeY = 1200; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 29 = ((1600 - 640) / 8 / 4) - 1 if (imageSize < 29) { _imageSize_temp = (29 - imageSize); From 19faf30b923827d811935063661b31798f80e5f1 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Fri, 10 May 2024 10:47:42 +1000 Subject: [PATCH 09/20] Changed OV5640 full frame size to match datasheet --- code/components/jomjol_controlcamera/ClassControllCamera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 047f34b90..c7ad31e6a 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -425,6 +425,8 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in switch (sensor_info->model) { case CAMERA_OV5640: + frameSizeX = 2592; + frameSizeY = 1944; // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 // 59 = ((2560 - 640) / 8 / 4) - 1 if (imageSize < 59) From 1fd3f6ac3e3fb9da68c5517d26a76344c127d04d Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Mon, 13 May 2024 02:54:41 +1000 Subject: [PATCH 10/20] various fixes --- .../ClassControllCamera.cpp | 201 +++++++----------- .../ClassControllCamera.h | 2 +- sd-card/html/edit_config_template.html | 14 +- sd-card/html/edit_reference.html | 4 +- 4 files changed, 81 insertions(+), 140 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index c7ad31e6a..44391247e 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -329,78 +329,65 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) } +// - It always zooms to the image center when offsets are zero +// - if imageSize = 0 then the image is not zoomed +// - if imageSize = max value, then the image is fully zoomed in +// - a zoom step is >>> Width + 32 px / Height + 24 px void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY) { - // This works only if the aspect ratio of 4:3 is preserved in the window size. - // use values divisible by 8 without remainder - int _imageWidth = imageWidth + (imageSize * 4 * 8); - int _imageHeight = imageHeight + (imageSize * 3 * 8); - int _offsetx = zoomOffsetX; - int _offsety = zoomOffsetY; - int _maxX = 0; - int _maxY = 0; + // for OV2640, This works only if the aspect ratio of 4:3 is preserved in the window size. + // use only values divisible by 8 without remainder + imageWidth = CCstatus.ImageWidth + (imageSize * 4 * 8); + imageHeight = CCstatus.ImageHeight + (imageSize * 3 * 8); - _maxX = frameSizeX - imageWidth; - _maxY = frameSizeY - imageHeight; + int _maxX = frameSizeX - imageWidth; + int _maxY = frameSizeY - imageHeight; - if ((abs(_offsetx) * 2) > _maxX) + if ((abs(zoomOffsetX) * 2) > _maxX) { - if (_offsetx > 0) + if (zoomOffsetX > 0) { - _offsetx = _maxX; + zoomOffsetX = _maxX; } else { - _offsetx = 0; + zoomOffsetX = 0; } } else { - if (_offsetx > 0) + if (zoomOffsetX > 0) { - // wenn der Wert von _offsetx nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsetx = ((_maxX / 2) + _offsetx); + zoomOffsetX = ((_maxX / 2) + zoomOffsetX); } else { - // wenn der Wert von _offsetx nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsetx = ((_maxX / 2) + _offsetx); + zoomOffsetX = ((_maxX / 2) + zoomOffsetX); } } - if ((abs(_offsety) * 2) > _maxY) + if ((abs(zoomOffsetY) * 2) > _maxY) { - if (_offsety > 0) + if (zoomOffsetY > 0) { - _offsety = _maxY; + zoomOffsetY = _maxY; } else { - _offsety = 0; + zoomOffsetY = 0; } } else { - if (_offsety > 0) + if (zoomOffsetY > 0) { - // wenn der Wert von _offsety nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsety = ((_maxY / 2) + _offsety); + zoomOffsetY = ((_maxY / 2) + zoomOffsetY); } else { - // wenn der Wert von _offsety nicht durch 8 teilbar ist, - // werden die Farben sehr oft vertauscht(insbesondere Rot mit Blau) - _offsety = ((_maxY / 2) + _offsety); + zoomOffsetY = ((_maxY / 2) + zoomOffsetY); } } - - zoomOffsetX = _offsetx; - zoomOffsetY = _offsety; - imageWidth = _imageWidth; - imageHeight = _imageHeight; } @@ -410,11 +397,8 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in if (s != NULL) { - camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); - if (zoomEnabled && (sensor_info != NULL)) + if (zoomEnabled) { - int unused = 0; - int _mode = 0; int _imageSize_temp = 0; int _imageWidth = CCstatus.ImageWidth; int _imageHeight = CCstatus.ImageHeight; @@ -422,9 +406,10 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in int _offsety = zoomOffsetY; int frameSizeX; int frameSizeY; - switch (sensor_info->model) + + switch (s->id.PID) { - case CAMERA_OV5640: + case OV5640_PID: frameSizeX = 2592; frameSizeY = 1944; // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 @@ -434,10 +419,10 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _imageSize_temp = (59 - imageSize); } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, unused, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); break; - case CAMERA_OV3660: + case OV3660_PID: frameSizeX = 2048; frameSizeY = 1536; // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 @@ -447,14 +432,10 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _imageSize_temp = (43 - imageSize); } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, unused, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); break; - case CAMERA_OV2640: - // ov2640_sensor_mode_t _mode = OV2640_MODE_UXGA; // 1600x1200 - // ov2640_sensor_mode_t _mode = OV2640_MODE_SVGA; // 800x600 - // ov2640_sensor_mode_t _mode = OV2640_MODE_CIF; // 400x296 - _mode = 0; + case OV2640_PID: frameSizeX = 1600; frameSizeY = 1200; // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 @@ -464,11 +445,7 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _imageSize_temp = (29 - imageSize); } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - // _mode sets the sensor resolution (3 options available), - // _offsetx and _offsety set the start of the ROI, - // _imageWidth and _imageHeight set the size of the ROI, - // CCstatus.ImageWidth and CCstatus.ImageHeight set the output window size. - SetCamWindow(s, _mode, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); break; default: @@ -485,11 +462,19 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) { - qual = min(63, max(8, qual)); // Limit quality from 8..63 (values lower than 8 tent to be unstable) + sensor_t *s = esp_camera_sensor_get(); + + if (s->id.PID == OV5640_PID) + { + qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) + } + else + { + qual = min(63, max(6, qual)); // Limit quality from 6..63 (values lower than 8 tent to be unstable) + } SetImageWidthHeightFromResolution(resol); - sensor_t *s = esp_camera_sensor_get(); if (s != NULL) { @@ -510,34 +495,29 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) { _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); - camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); - - if (sensor_info != NULL) + if (s->id.PID == OV2640_PID) + { + // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. + if (_autoSharpnessEnabled) + { + ov2640_enable_auto_sharpness(s); + } + else + { + ov2640_set_sharpness(s, _sharpnessLevel); + } + } + else { - if (sensor_info->model == CAMERA_OV2640) + // for CAMERA_OV5640 and CAMERA_OV3660 + if (_autoSharpnessEnabled) { - // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. - if (_autoSharpnessEnabled) - { - ov2640_enable_auto_sharpness(s); - } - else - { - ov2640_set_sharpness(s, _sharpnessLevel); - } + // autoSharpness is not supported, default to zero + s->set_sharpness(s, 0); } else { - // for CAMERA_OV5640 and CAMERA_OV3660 - if (_autoSharpnessEnabled) - { - // autoSharpness is not supported, default to zero - s->set_sharpness(s, 0); - } - else - { - s->set_sharpness(s, _sharpnessLevel); - } + s->set_sharpness(s, _sharpnessLevel); } } } @@ -547,57 +527,18 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) } } -/* - * resolution = 0 \\ OV2640_MODE_UXGA -> 1600 x 1200 - * resolution = 1 \\ OV2640_MODE_SVGA -> 800 x 600 - * resolution = 2 \\ OV2640_MODE_CIF -> 400 x 296 - */ -void CCamera::SetCamWindow(sensor_t *s, int resolution, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) +void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) { - camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id)); - if (sensor_info != NULL) + if (s->id.PID == OV2640_PID) { - if (sensor_info->model == CAMERA_OV2640) - { - // - (xOffset,yOffset) is the origin of the window in pixels and (xLength,yLength) is the size of the window in pixels. - // - (xOffset,yOffset) ist der Ursprung des Fensters in Pixel und (xLength,yLength) ist die Größe des Fensters in Pixel. - - // - Be aware that changing the resolution will effectively overwrite these settings. - // - Beachten Sie, dass eine Änderung der Auflösung diese Einstellungen effektiv überschreibt. - - // - This works only if the aspect ratio of 4:3 is preserved in the window size. - // - Dies funktioniert nur, wenn das Seitenverhältnis von 4:3 in der Fenstergröße beibehalten wird. - - // - total_x and total_y defines the size on the sensor - // - total_x und total_y definieren die Größe des Sensors - - // - width and height defines the resulting image(may be smaller than the size on the sensor) - // - width und height definieren das resultierende Bild (kann kleiner sein als die Größe des Sensor) - - // - keep the aspect total_x : total_y == width : height - // - Behalten Sie den Aspekt total_x : total_y == width : height bei - - // - use values divisible by 8 without remainder - // - Verwenden Sie Werte, die ohne Rest durch 8 teilbar sind - - // - start with total_x = width and total_y = height, reduce both values by eg.32 pixels - // - Beginnen Sie mit total_x = width und total_y = height und reduzieren Sie beide Werte um z.B.32 Pixel - - // - next try moving with offset_x or offset_y by 8 pixels - // - Versuchen Sie als Nächstes, mit offset_x oder offset_y um 8 Pixel zu verschieben - - // set_res_raw(sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning) - // set_window(sensor, (ov2640_sensor_mode_t)startX, offsetX, offsetY, totalX, totalY, outputX, outputY); - // set_window(sensor, mode, offset_x, offset_y, max_x, max_y, w, h); - - int unused = 0; - s->set_res_raw(s, resolution, unused, unused, unused, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, unused, unused); - } - else - { - // for CAMERA_OV5640 and CAMERA_OV3660 - s->set_res_raw(s, xOffset, yOffset, xOffset + xOutput, yOffset + yOutput, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, false, false); - } + s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); + } + else + { + // for CAMERA_OV5640 and CAMERA_OV3660 + bool scale = !(xOutput == xTotal && yOutput == yTotal); + bool binning = (xTotal >= (frameSizeX>>1)); + s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); } } diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index 96c2d6a1d..bd4fe7893 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -79,7 +79,7 @@ class CCamera void ledc_init(void); bool loadNextDemoImage(camera_fb_t *fb); long GetFileSize(std::string filename); - void SetCamWindow(sensor_t *s, int resolution, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); + void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); void SetImageWidthHeightFromResolution(framesize_t resol); void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); diff --git a/sd-card/html/edit_config_template.html b/sd-card/html/edit_config_template.html index 68b9cd134..d00ff6698 100644 --- a/sd-card/html/edit_config_template.html +++ b/sd-card/html/edit_config_template.html @@ -623,8 +623,8 @@

Configuration

Zoom Size - + $TOOLTIP_TakeImage_CamZoomSize @@ -634,8 +634,8 @@

Configuration

Zoom Offset X - Pixel + Pixel $TOOLTIP_TakeImage_CamZoomOffsetX @@ -645,11 +645,11 @@

Configuration

Zoom Offset Y - Pixel + Pixel $TOOLTIP_TakeImage_CamZoomOffsetY - + diff --git a/sd-card/html/edit_reference.html b/sd-card/html/edit_reference.html index 0d3bb1d43..8b0bb49a3 100644 --- a/sd-card/html/edit_reference.html +++ b/sd-card/html/edit_reference.html @@ -195,8 +195,8 @@

Reference Image and Camera Settings

- + $TOOLTIP_TakeImage_CamZoomSize From 82f9c3c09d0567e94ccd8c617ce8851e52cb0c96 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Tue, 14 May 2024 15:16:41 +1000 Subject: [PATCH 11/20] add denoise config and general clean up --- .../ClassControllCamera.cpp | 2349 +++--- .../ClassControllCamera.h | 224 +- .../ClassFlowTakeImage.cpp | 1124 ++- .../jomjol_flowcontroll/MainFlowControl.cpp | 3243 +++++---- .../jomjol_flowcontroll/MainFlowControl.h | 177 +- code/components/jomjol_helper/Helper.cpp | 23 + code/components/jomjol_helper/Helper.h | 4 + param-docs/expert-params.txt | 93 +- .../parameter-pages/TakeImage/CamAeLevel.md | 31 +- .../parameter-pages/TakeImage/CamDenoise.md | 22 +- sd-card/config/config.ini | 1 + sd-card/html/edit_config_template.html | 6331 +++++++++-------- sd-card/html/readconfigparam.js | 2286 +++--- 13 files changed, 7915 insertions(+), 7993 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 44391247e..d85a6cd20 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -1,1171 +1,1178 @@ -#include "ClassControllCamera.h" -#include "ClassLogFile.h" - -#include -#include "driver/gpio.h" -#include "esp_timer.h" -#include "esp_log.h" - -#include "Helper.h" -#include "statusled.h" -#include "CImageBasis.h" - -#include "server_ota.h" -#include "server_GPIO.h" - -#include "../../include/defines.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "esp_camera.h" - -#include "driver/ledc.h" -#include "MainFlowControl.h" - -#include "ov2640_sharpness.h" - -#if (ESP_IDF_VERSION_MAJOR >= 5) -#include "soc/periph_defs.h" -#include "esp_private/periph_ctrl.h" -#include "soc/gpio_sig_map.h" -#include "soc/gpio_periph.h" -#include "soc/io_mux_reg.h" -#include "esp_rom_gpio.h" -#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio -#define gpio_matrix_in(a, b, c) esp_rom_gpio_connect_in_signal(a, b, c) -#define gpio_matrix_out(a, b, c, d) esp_rom_gpio_connect_out_signal(a, b, c, d) -#define ets_delay_us(a) esp_rom_delay_us(a) -#endif - -CCamera Camera; -camera_controll_config_temp_t CCstatus; - -static const char *TAG = "CAM"; - -/* Camera live stream */ -#define PART_BOUNDARY "123456789000000000000987654321" -static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; -static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; -static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; - -uint8_t *demoImage = NULL; // Buffer holding the demo image in bytes -#define DEMO_IMAGE_SIZE 30000 // Max size of demo image in bytes - -// Camera module bus communications frequency. -// Originally: config.xclk_freq_mhz = 20000000, but this lead to visual artifacts on many modules. -// See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. -#if !defined(XCLK_FREQ_MHZ) -// int xclk = 8; -int xclk = 20; // Orginal value -#else -int xclk = XCLK_FREQ_MHZ; -#endif - -static camera_config_t camera_config = { - .pin_pwdn = CAM_PIN_PWDN, - .pin_reset = CAM_PIN_RESET, - .pin_xclk = CAM_PIN_XCLK, - .pin_sscb_sda = CAM_PIN_SIOD, - .pin_sscb_scl = CAM_PIN_SIOC, - - .pin_d7 = CAM_PIN_D7, - .pin_d6 = CAM_PIN_D6, - .pin_d5 = CAM_PIN_D5, - .pin_d4 = CAM_PIN_D4, - .pin_d3 = CAM_PIN_D3, - .pin_d2 = CAM_PIN_D2, - .pin_d1 = CAM_PIN_D1, - .pin_d0 = CAM_PIN_D0, - .pin_vsync = CAM_PIN_VSYNC, - .pin_href = CAM_PIN_HREF, - .pin_pclk = CAM_PIN_PCLK, - - .xclk_freq_hz = (xclk * 1000000), - .ledc_timer = LEDC_TIMER_0, // LEDC timer to be used for generating XCLK - .ledc_channel = LEDC_CHANNEL_0, // LEDC channel to be used for generating XCLK - - .pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,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 - .jpeg_quality = 6, // 0-63 lower number means higher quality - .fb_count = 1, // if more than one, i2s runs in continuous mode. Use only with JPEG - .fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */ - .grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version -}; - -typedef struct -{ - httpd_req_t *req; - size_t len; -} jpg_chunking_t; - -CCamera::CCamera(void) -{ -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "CreateClassCamera"); -#endif - CCstatus.WaitBeforePicture = 2; - - ledc_init(); -} - -esp_err_t CCamera::InitCam(void) -{ - ESP_LOGD(TAG, "Init Camera"); - - CCstatus.ImageQuality = camera_config.jpeg_quality; - CCstatus.ImageFrameSize = camera_config.frame_size; - - // initialize the camera - esp_camera_deinit(); // De-init in case it was already initialized - esp_err_t err = esp_camera_init(&camera_config); - - if (err != ESP_OK) - { - ESP_LOGE(TAG, "Camera Init Failed"); - return err; - } - - CCstatus.CameraInitSuccessful = true; - - // Get a reference to the sensor - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - // Dump camera module, warn for unsupported modules. - switch (s->id.PID) - { - case OV2640_PID: - ESP_LOGI(TAG, "OV2640 camera module detected"); - break; - case OV3660_PID: - ESP_LOGI(TAG, "OV3660 camera module detected"); - break; - case OV5640_PID: - ESP_LOGI(TAG, "OV5640 camera module detected"); - break; - default: - ESP_LOGE(TAG, "Camera module is unknown and not properly supported!"); - CCstatus.CameraInitSuccessful = false; - } - } - - if (CCstatus.CameraInitSuccessful) - { - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - -bool CCamera::testCamera(void) -{ - bool success; - camera_fb_t *fb = esp_camera_fb_get(); - - if (fb) - { - success = true; - } - else - { - success = false; - } - - esp_camera_fb_return(fb); - - return success; -} - -void CCamera::ledc_init(void) -{ -#ifdef USE_PWM_LEDFLASH - // Prepare and then apply the LEDC PWM timer configuration - ledc_timer_config_t ledc_timer = {}; - - ledc_timer.speed_mode = LEDC_MODE; - ledc_timer.timer_num = LEDC_TIMER; - ledc_timer.duty_resolution = LEDC_DUTY_RES; - ledc_timer.freq_hz = LEDC_FREQUENCY; // Set output frequency at 5 kHz - ledc_timer.clk_cfg = LEDC_AUTO_CLK; - - ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); - - // Prepare and then apply the LEDC PWM channel configuration - ledc_channel_config_t ledc_channel = {}; - - ledc_channel.speed_mode = LEDC_MODE; - ledc_channel.channel = LEDC_CHANNEL; - ledc_channel.timer_sel = LEDC_TIMER; - ledc_channel.intr_type = LEDC_INTR_DISABLE; - ledc_channel.gpio_num = LEDC_OUTPUT_IO; - ledc_channel.duty = 0; // Set duty to 0% - ledc_channel.hpoint = 0; - // ledc_channel.flags.output_invert = LEDC_OUTPUT_INVERT; - - ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); -#endif -} - -void CCamera::SetLEDIntensity(float _intrel) -{ - _intrel = min(_intrel, (float)100); - _intrel = max(_intrel, (float)0); - _intrel = _intrel / 100; - CCstatus.ImageLedIntensity = (int)(_intrel * 8191); - ESP_LOGD(TAG, "Set led_intensity to %d of 8191", CCstatus.ImageLedIntensity); -} - -bool CCamera::getCameraInitSuccessful(void) -{ - return CCstatus.CameraInitSuccessful; -} - -esp_err_t CCamera::setSensorDatenFromCCstatus(void) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - s->set_framesize(s, CCstatus.ImageFrameSize); - s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - - s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 - - s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 - s->set_contrast(s, CCstatus.ImageContrast); // -2 to 2 - s->set_saturation(s, CCstatus.ImageSaturation); // -2 to 2 - // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 - SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); - - s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable - s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 - s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 - - s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable - - s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable - s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 - - s->set_bpc(s, CCstatus.ImageBpc); // 0 = disable , 1 = enable - s->set_wpc(s, CCstatus.ImageWpc); // 0 = disable , 1 = enable - - s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable - - s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable - s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable - - s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable - - s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - s->set_awb_gain(s, CCstatus.ImageAwbGain); // 0 = disable , 1 = enable - s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable - - // special_effect muß als Letztes gesetzt werden, sonst geht es nicht - s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) - - TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; - vTaskDelay(xDelay2); - - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - -esp_err_t CCamera::getSensorDatenToCCstatus(void) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - CCstatus.ImageFrameSize = (framesize_t)s->status.framesize; - CCstatus.ImageGainceiling = (gainceiling_t)s->status.gainceiling; - - CCstatus.ImageQuality = s->status.quality; - CCstatus.ImageBrightness = s->status.brightness; - CCstatus.ImageContrast = s->status.contrast; - CCstatus.ImageSaturation = s->status.saturation; - // CCstatus.ImageSharpness = s->status.sharpness; // gibt -1 zurück, da es nicht unterstützt wird - CCstatus.ImageWbMode = s->status.wb_mode; - CCstatus.ImageAwb = s->status.awb; - CCstatus.ImageAwbGain = s->status.awb_gain; - CCstatus.ImageAec = s->status.aec; - CCstatus.ImageAec2 = s->status.aec2; - CCstatus.ImageAeLevel = s->status.ae_level; - CCstatus.ImageAecValue = s->status.aec_value; - CCstatus.ImageAgc = s->status.agc; - CCstatus.ImageAgcGain = s->status.agc_gain; - CCstatus.ImageBpc = s->status.bpc; - CCstatus.ImageWpc = s->status.wpc; - CCstatus.ImageRawGma = s->status.raw_gma; - CCstatus.ImageLenc = s->status.lenc; - CCstatus.ImageSpecialEffect = s->status.special_effect; - CCstatus.ImageHmirror = s->status.hmirror; - CCstatus.ImageVflip = s->status.vflip; - CCstatus.ImageDcw = s->status.dcw; - - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - - -// - It always zooms to the image center when offsets are zero -// - if imageSize = 0 then the image is not zoomed -// - if imageSize = max value, then the image is fully zoomed in -// - a zoom step is >>> Width + 32 px / Height + 24 px -void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY) -{ - // for OV2640, This works only if the aspect ratio of 4:3 is preserved in the window size. - // use only values divisible by 8 without remainder - imageWidth = CCstatus.ImageWidth + (imageSize * 4 * 8); - imageHeight = CCstatus.ImageHeight + (imageSize * 3 * 8); - - int _maxX = frameSizeX - imageWidth; - int _maxY = frameSizeY - imageHeight; - - if ((abs(zoomOffsetX) * 2) > _maxX) - { - if (zoomOffsetX > 0) - { - zoomOffsetX = _maxX; - } - else - { - zoomOffsetX = 0; - } - } - else - { - if (zoomOffsetX > 0) - { - zoomOffsetX = ((_maxX / 2) + zoomOffsetX); - } - else - { - zoomOffsetX = ((_maxX / 2) + zoomOffsetX); - } - } - - if ((abs(zoomOffsetY) * 2) > _maxY) - { - if (zoomOffsetY > 0) - { - zoomOffsetY = _maxY; - } - else - { - zoomOffsetY = 0; - } - } - else - { - if (zoomOffsetY > 0) - { - zoomOffsetY = ((_maxY / 2) + zoomOffsetY); - } - else - { - zoomOffsetY = ((_maxY / 2) + zoomOffsetY); - } - } -} - - -void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - if (zoomEnabled) - { - int _imageSize_temp = 0; - int _imageWidth = CCstatus.ImageWidth; - int _imageHeight = CCstatus.ImageHeight; - int _offsetx = zoomOffsetX; - int _offsety = zoomOffsetY; - int frameSizeX; - int frameSizeY; - - switch (s->id.PID) - { - case OV5640_PID: - frameSizeX = 2592; - frameSizeY = 1944; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 - // 59 = ((2560 - 640) / 8 / 4) - 1 - if (imageSize < 59) - { - _imageSize_temp = (59 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - case OV3660_PID: - frameSizeX = 2048; - frameSizeY = 1536; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 - // 43 = ((2048 - 640) / 8 / 4) - 1 - if (imageSize < 43) - { - _imageSize_temp = (43 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - case OV2640_PID: - frameSizeX = 1600; - frameSizeY = 1200; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 - // 29 = ((1600 - 640) / 8 / 4) - 1 - if (imageSize < 29) - { - _imageSize_temp = (29 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - default: - // do nothing - break; - } - } - else - { - s->set_framesize(s, CCstatus.ImageFrameSize); - } - } -} - -void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s->id.PID == OV5640_PID) - { - qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) - } - else - { - qual = min(63, max(6, qual)); // Limit quality from 6..63 (values lower than 8 tent to be unstable) - } - - SetImageWidthHeightFromResolution(resol); - - - if (s != NULL) - { - s->set_quality(s, qual); - SetZoomSize(zoomEnabled, zoomOffsetX, zoomOffsetY, imageSize); - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetQualityZoomSize, Failed to get Cam control structure"); - } -} - -void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); - - if (s->id.PID == OV2640_PID) - { - // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. - if (_autoSharpnessEnabled) - { - ov2640_enable_auto_sharpness(s); - } - else - { - ov2640_set_sharpness(s, _sharpnessLevel); - } - } - else - { - // for CAMERA_OV5640 and CAMERA_OV3660 - if (_autoSharpnessEnabled) - { - // autoSharpness is not supported, default to zero - s->set_sharpness(s, 0); - } - else - { - s->set_sharpness(s, _sharpnessLevel); - } - } - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetCamSharpness, Failed to get Cam control structure"); - } -} - -void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) -{ - if (s->id.PID == OV2640_PID) - { - s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); - } - else - { - // for CAMERA_OV5640 and CAMERA_OV3660 - bool scale = !(xOutput == xTotal && yOutput == yTotal); - bool binning = (xTotal >= (frameSizeX>>1)); - s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); - } -} - -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) - { - j->len = 0; - } - - if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) - { - return 0; - } - - j->len += len; - - return len; -} - -esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - Start"); -#endif - - _Image->EmptyImage(); // Delete previous stored raw image -> black image - - LEDOnOff(true); // Status-LED on - - if (delay > 0) - { - LightOnOff(true); // Flash-LED on - const TickType_t xDelay = delay / portTICK_PERIOD_MS; - vTaskDelay(xDelay); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - After LightOn"); -#endif - - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CaptureToBasisImage) - most probably caused " - "by a hardware problem (instablility, ...). System will reboot."); - doReboot(); - - return ESP_FAIL; - } - - if (CCstatus.DemoMode) - { - // Use images stored on SD-Card instead of camera image - /* Replace Framebuffer with image from SD-Card */ - loadNextDemoImage(fb); - } - - CImageBasis *_zwImage = new CImageBasis("zwImage"); - - if (_zwImage) - { - _zwImage->LoadFromMemory(fb->buf, fb->len); - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToBasisImage: Can't allocate _zwImage"); - } - - esp_camera_fb_return(fb); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - After fb_get"); -#endif - - LEDOnOff(false); // Status-LED off - - if (delay > 0) - { - LightOnOff(false); // Flash-LED off - } - - // TickType_t xDelay = 1000 / portTICK_PERIOD_MS; - // vTaskDelay( xDelay ); // wait for power to recover - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - After LoadFromMemory"); -#endif - - if (_zwImage == NULL) - { - return ESP_OK; - } - - stbi_uc *p_target; - stbi_uc *p_source; - int channels = 3; - int width = CCstatus.ImageWidth; - int height = CCstatus.ImageHeight; - -#ifdef DEBUG_DETAIL_ON - std::string _zw = "Targetimage: " + std::to_string((int)_Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height); - _zw = _zw + " _zwImage: " + std::to_string((int)_zwImage->rgb_image) + " Size: " + std::to_string(_zwImage->width) + ", " + std::to_string(_zwImage->height); - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw); -#endif - - 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 = _zwImage->rgb_image + (channels * (y * width + x)); - - for (int c = 0; c < channels; c++) - { - p_target[c] = p_source[c]; - } - } - } - - delete _zwImage; - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - Done"); -#endif - - return ESP_OK; -} - -esp_err_t CCamera::CaptureToFile(std::string nm, int delay) -{ - string ftype; - - LEDOnOff(true); // Status-LED on - - if (delay > 0) - { - LightOnOff(true); // Flash-LED on - const TickType_t xDelay = delay / portTICK_PERIOD_MS; - vTaskDelay(xDelay); - } - - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " - "Check camera module and/or proper electrical connection"); - // doReboot(); - - return ESP_FAIL; - } - - LEDOnOff(false); // Status-LED off - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "w %d, h %d, size %d", fb->width, fb->height, fb->len); -#endif - - nm = FormatFileName(nm); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Save Camera to: %s", nm.c_str()); -#endif - - ftype = toUpper(getFileType(nm)); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Filetype: %s", ftype.c_str()); -#endif - - uint8_t *buf = NULL; - size_t buf_len = 0; - bool converted = false; - - if (ftype.compare("BMP") == 0) - { - frame2bmp(fb, &buf, &buf_len); - converted = true; - } - - if (ftype.compare("JPG") == 0) - { - if (fb->format != PIXFORMAT_JPEG) - { - bool jpeg_converted = frame2jpg(fb, CCstatus.ImageQuality, &buf, &buf_len); - converted = true; - - if (!jpeg_converted) - { - ESP_LOGE(TAG, "JPEG compression failed"); - } - } - else - { - buf_len = fb->len; - buf = fb->buf; - } - } - - FILE *fp = fopen(nm.c_str(), "wb"); - - if (fp == NULL) - { - // If an error occurs during the file creation - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Failed to open file " + nm); - } - else - { - fwrite(buf, sizeof(uint8_t), buf_len, fp); - fclose(fp); - } - - if (converted) - { - free(buf); - } - - esp_camera_fb_return(fb); - - if (delay > 0) - { - LightOnOff(false); // Flash-LED off - } - - return ESP_OK; -} - -esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) -{ - esp_err_t res = ESP_OK; - size_t fb_len = 0; - int64_t fr_start = esp_timer_get_time(); - - LEDOnOff(true); // Status-LED on - - if (delay > 0) - { - LightOnOff(true); // Flash-LED on - const TickType_t xDelay = delay / portTICK_PERIOD_MS; - vTaskDelay(xDelay); - } - - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " - "Check camera module and/or proper electrical connection"); - httpd_resp_send_500(req); - // doReboot(); - - return ESP_FAIL; - } - - LEDOnOff(false); // Status-LED off - res = httpd_resp_set_type(req, "image/jpeg"); - - if (res == ESP_OK) - { - res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=raw.jpg"); - } - - if (res == ESP_OK) - { - if (CCstatus.DemoMode) - { - // Use images stored on SD-Card instead of camera image - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using Demo image!"); - /* Replace Framebuffer with image from SD-Card */ - loadNextDemoImage(fb); - - res = httpd_resp_send(req, (const char *)fb->buf, fb->len); - } - else - { - if (fb->format == PIXFORMAT_JPEG) - { - fb_len = fb->len; - res = httpd_resp_send(req, (const char *)fb->buf, fb->len); - } - else - { - jpg_chunking_t jchunk = {req, 0}; - res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; - httpd_resp_send_chunk(req, NULL, 0); - fb_len = jchunk.len; - } - } - } - - esp_camera_fb_return(fb); - int64_t fr_end = esp_timer_get_time(); - - ESP_LOGI(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); - - if (delay > 0) - { - LightOnOff(false); // Flash-LED off - } - - return res; -} - -esp_err_t CCamera::CaptureToStream(httpd_req_t *req, bool FlashlightOn) -{ - esp_err_t res = ESP_OK; - size_t fb_len = 0; - int64_t fr_start; - char *part_buf[64]; - - // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden - if (CFstatus.changedCameraSettings) - { - Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); - CFstatus.changedCameraSettings = false; - } - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream started"); - - if (FlashlightOn) - { - LEDOnOff(true); // Status-LED on - LightOnOff(true); // Flash-LED on - } - - // httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //stream is blocking web interface, only serving to local - - httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); - httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); - - while (1) - { - fr_start = esp_timer_get_time(); - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToStream: Camera framebuffer not available"); - break; - } - - fb_len = fb->len; - - if (res == ESP_OK) - { - size_t hlen = snprintf((char *)part_buf, sizeof(part_buf), _STREAM_PART, fb_len); - res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); - } - - if (res == ESP_OK) - { - res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb_len); - } - - if (res == ESP_OK) - { - res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); - } - - esp_camera_fb_return(fb); - - int64_t fr_end = esp_timer_get_time(); - ESP_LOGD(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); - - if (res != ESP_OK) - { - // Exit loop, e.g. also when closing the webpage - break; - } - - int64_t fr_delta_ms = (fr_end - fr_start) / 1000; - - if (CAM_LIVESTREAM_REFRESHRATE > fr_delta_ms) - { - const TickType_t xDelay = (CAM_LIVESTREAM_REFRESHRATE - fr_delta_ms) / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "Stream: sleep for: %ldms", (long)xDelay * 10); - vTaskDelay(xDelay); - } - } - - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream stopped"); - - return res; -} - -void CCamera::LightOnOff(bool status) -{ - GpioHandler *gpioHandler = gpio_handler_get(); - - if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) - { - ESP_LOGD(TAG, "Use gpioHandler to trigger flashlight"); - gpioHandler->flashLightEnable(status); - } - else - { -#ifdef USE_PWM_LEDFLASH - if (status) - { - ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", CCstatus.ImageLedIntensity); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, CCstatus.ImageLedIntensity)); - // Update duty to apply the new value - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); - } - else - { - ESP_LOGD(TAG, "Internal Flash-LED turn off PWM"); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0)); - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); - } -#else - // Init the GPIO - gpio_pad_select_gpio(FLASH_GPIO); - - // Set the GPIO as a push/pull output - gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); - - if (status) - { - gpio_set_level(FLASH_GPIO, 1); - } - else - { - gpio_set_level(FLASH_GPIO, 0); - } -#endif - } -} - -void CCamera::LEDOnOff(bool status) -{ - if (xHandle_task_StatusLED == NULL) - { - // Init the GPIO - gpio_pad_select_gpio(BLINK_GPIO); - - /* Set the GPIO as a push/pull output */ - gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); - - if (!status) - { - gpio_set_level(BLINK_GPIO, 1); - } - else - { - gpio_set_level(BLINK_GPIO, 0); - } - } -} - -void CCamera::SetImageWidthHeightFromResolution(framesize_t resol) -{ - if (resol == FRAMESIZE_QVGA) - { - CCstatus.ImageHeight = 240; - CCstatus.ImageWidth = 320; - } - else if (resol == FRAMESIZE_VGA) - { - CCstatus.ImageHeight = 480; - CCstatus.ImageWidth = 640; - } - else if (resol == FRAMESIZE_SVGA) - { - CCstatus.ImageHeight = 600; - CCstatus.ImageWidth = 800; - } - else if (resol == FRAMESIZE_XGA) - { - CCstatus.ImageHeight = 768; - CCstatus.ImageWidth = 1024; - } - else if (resol == FRAMESIZE_HD) - { - CCstatus.ImageHeight = 720; - CCstatus.ImageWidth = 1280; - } - else if (resol == FRAMESIZE_SXGA) - { - CCstatus.ImageHeight = 1024; - CCstatus.ImageWidth = 1280; - } - else if (resol == FRAMESIZE_UXGA) - { - CCstatus.ImageHeight = 1200; - CCstatus.ImageWidth = 1600; - } -} - -framesize_t CCamera::TextToFramesize(const char *_size) -{ - if (strcmp(_size, "QVGA") == 0) - { - return FRAMESIZE_QVGA; // 320x240 - } - else if (strcmp(_size, "VGA") == 0) - { - return FRAMESIZE_VGA; // 640x480 - } - else if (strcmp(_size, "SVGA") == 0) - { - return FRAMESIZE_SVGA; // 800x600 - } - else if (strcmp(_size, "XGA") == 0) - { - return FRAMESIZE_XGA; // 1024x768 - } - else if (strcmp(_size, "SXGA") == 0) - { - return FRAMESIZE_SXGA; // 1280x1024 - } - else if (strcmp(_size, "UXGA") == 0) - { - return FRAMESIZE_UXGA; // 1600x1200 - } - - return CCstatus.ImageFrameSize; -} - -std::vector demoFiles; - -void CCamera::useDemoMode(void) -{ - char line[50]; - - FILE *fd = fopen("/sdcard/demo/files.txt", "r"); - - if (!fd) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can not start Demo mode, the folder '/sdcard/demo/' does not contain the needed files!"); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "See Details on https://jomjol.github.io/AI-on-the-edge-device-docs/Demo-Mode!"); - return; - } - - demoImage = (uint8_t *)malloc(DEMO_IMAGE_SIZE); - - if (demoImage == NULL) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to acquire required memory for demo image!"); - return; - } - - while (fgets(line, sizeof(line), fd) != NULL) - { - line[strlen(line) - 1] = '\0'; - demoFiles.push_back(line); - } - - fclose(fd); - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Using Demo mode (" + std::to_string(demoFiles.size()) + " files) instead of real camera image!"); - - for (auto file : demoFiles) - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, file); - } - - CCstatus.DemoMode = true; -} - -bool CCamera::loadNextDemoImage(camera_fb_t *fb) -{ - char filename[50]; - int readBytes; - long fileSize; - - snprintf(filename, sizeof(filename), "/sdcard/demo/%s", demoFiles[getCountFlowRounds() % demoFiles.size()].c_str()); - - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using " + std::string(filename) + " as demo image"); - - /* Inject saved image */ - - FILE *fp = fopen(filename, "rb"); - - if (!fp) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filename) + "!"); - return false; - } - - fileSize = GetFileSize(filename); - - if (fileSize > DEMO_IMAGE_SIZE) - { - char buf[100]; - snprintf(buf, sizeof(buf), "Demo Image (%d bytes) is larger than provided buffer (%d bytes)!", (int)fileSize, DEMO_IMAGE_SIZE); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string(buf)); - return false; - } - - readBytes = fread(demoImage, 1, DEMO_IMAGE_SIZE, fp); - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "read " + std::to_string(readBytes) + " bytes"); - fclose(fp); - - fb->buf = demoImage; // Update pointer - fb->len = readBytes; - // ToDo do we also need to set height, width, format and timestamp? - - return true; -} - -long CCamera::GetFileSize(std::string filename) -{ - struct stat stat_buf; - long rc = stat(filename.c_str(), &stat_buf); - return rc == 0 ? stat_buf.st_size : -1; -} +#include "ClassControllCamera.h" +#include "ClassLogFile.h" + +#include +#include "driver/gpio.h" +#include "esp_timer.h" +#include "esp_log.h" + +#include "Helper.h" +#include "statusled.h" +#include "CImageBasis.h" + +#include "server_ota.h" +#include "server_GPIO.h" + +#include "../../include/defines.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_camera.h" + +#include "driver/ledc.h" +#include "MainFlowControl.h" + +#include "ov2640_sharpness.h" + +#if (ESP_IDF_VERSION_MAJOR >= 5) +#include "soc/periph_defs.h" +#include "esp_private/periph_ctrl.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_periph.h" +#include "soc/io_mux_reg.h" +#include "esp_rom_gpio.h" +#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio +#define gpio_matrix_in(a, b, c) esp_rom_gpio_connect_in_signal(a, b, c) +#define gpio_matrix_out(a, b, c, d) esp_rom_gpio_connect_out_signal(a, b, c, d) +#define ets_delay_us(a) esp_rom_delay_us(a) +#endif + +CCamera Camera; +camera_controll_config_temp_t CCstatus; + +static const char *TAG = "CAM"; + +/* Camera live stream */ +#define PART_BOUNDARY "123456789000000000000987654321" +static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; +static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; +static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; + +uint8_t *demoImage = NULL; // Buffer holding the demo image in bytes +#define DEMO_IMAGE_SIZE 30000 // Max size of demo image in bytes + +// Camera module bus communications frequency. +// Originally: config.xclk_freq_mhz = 20000000, but this lead to visual artifacts on many modules. +// See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. +#if !defined(XCLK_FREQ_MHZ) +// int xclk = 8; +int xclk = 20; // Orginal value +#else +int xclk = XCLK_FREQ_MHZ; +#endif + +static camera_config_t camera_config = { + .pin_pwdn = CAM_PIN_PWDN, + .pin_reset = CAM_PIN_RESET, + .pin_xclk = CAM_PIN_XCLK, + .pin_sscb_sda = CAM_PIN_SIOD, + .pin_sscb_scl = CAM_PIN_SIOC, + + .pin_d7 = CAM_PIN_D7, + .pin_d6 = CAM_PIN_D6, + .pin_d5 = CAM_PIN_D5, + .pin_d4 = CAM_PIN_D4, + .pin_d3 = CAM_PIN_D3, + .pin_d2 = CAM_PIN_D2, + .pin_d1 = CAM_PIN_D1, + .pin_d0 = CAM_PIN_D0, + .pin_vsync = CAM_PIN_VSYNC, + .pin_href = CAM_PIN_HREF, + .pin_pclk = CAM_PIN_PCLK, + + .xclk_freq_hz = (xclk * 1000000), + .ledc_timer = LEDC_TIMER_0, // LEDC timer to be used for generating XCLK + .ledc_channel = LEDC_CHANNEL_0, // LEDC channel to be used for generating XCLK + + .pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,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 + .jpeg_quality = 6, // 0-63 lower number means higher quality + .fb_count = 1, // if more than one, i2s runs in continuous mode. Use only with JPEG + .fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */ + .grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version +}; + +typedef struct +{ + httpd_req_t *req; + size_t len; +} jpg_chunking_t; + +CCamera::CCamera(void) +{ +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "CreateClassCamera"); +#endif + CCstatus.WaitBeforePicture = 2; + + ledc_init(); +} + +esp_err_t CCamera::InitCam(void) +{ + ESP_LOGD(TAG, "Init Camera"); + + CCstatus.ImageQuality = camera_config.jpeg_quality; + CCstatus.ImageFrameSize = camera_config.frame_size; + + // initialize the camera + esp_camera_deinit(); // De-init in case it was already initialized + esp_err_t err = esp_camera_init(&camera_config); + + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Camera Init Failed"); + return err; + } + + CCstatus.CameraInitSuccessful = true; + + // Get a reference to the sensor + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + CCstatus.CamSensor_id = s->id.PID; + + // Dump camera module, warn for unsupported modules. + switch (CCstatus.CamSensor_id) + { + case OV2640_PID: + ESP_LOGI(TAG, "OV2640 camera module detected"); + break; + case OV3660_PID: + ESP_LOGI(TAG, "OV3660 camera module detected"); + break; + case OV5640_PID: + ESP_LOGI(TAG, "OV5640 camera module detected"); + break; + default: + ESP_LOGE(TAG, "Camera module is unknown and not properly supported!"); + CCstatus.CameraInitSuccessful = false; + } + } + + if (CCstatus.CameraInitSuccessful) + { + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + +bool CCamera::testCamera(void) +{ + bool success; + camera_fb_t *fb = esp_camera_fb_get(); + + if (fb) + { + success = true; + } + else + { + success = false; + } + + esp_camera_fb_return(fb); + + return success; +} + +void CCamera::ledc_init(void) +{ +#ifdef USE_PWM_LEDFLASH + // Prepare and then apply the LEDC PWM timer configuration + ledc_timer_config_t ledc_timer = {}; + + ledc_timer.speed_mode = LEDC_MODE; + ledc_timer.timer_num = LEDC_TIMER; + ledc_timer.duty_resolution = LEDC_DUTY_RES; + ledc_timer.freq_hz = LEDC_FREQUENCY; // Set output frequency at 5 kHz + ledc_timer.clk_cfg = LEDC_AUTO_CLK; + + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + // Prepare and then apply the LEDC PWM channel configuration + ledc_channel_config_t ledc_channel = {}; + + ledc_channel.speed_mode = LEDC_MODE; + ledc_channel.channel = LEDC_CHANNEL; + ledc_channel.timer_sel = LEDC_TIMER; + ledc_channel.intr_type = LEDC_INTR_DISABLE; + ledc_channel.gpio_num = LEDC_OUTPUT_IO; + ledc_channel.duty = 0; // Set duty to 0% + ledc_channel.hpoint = 0; + // ledc_channel.flags.output_invert = LEDC_OUTPUT_INVERT; + + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); +#endif +} + +void CCamera::SetLEDIntensity(float _intrel) +{ + _intrel = min(_intrel, (float)100); + _intrel = max(_intrel, (float)0); + _intrel = _intrel / 100; + CCstatus.ImageLedIntensity = (int)(_intrel * 8191); + ESP_LOGD(TAG, "Set led_intensity to %d of 8191", CCstatus.ImageLedIntensity); +} + +bool CCamera::getCameraInitSuccessful(void) +{ + return CCstatus.CameraInitSuccessful; +} + +esp_err_t CCamera::setSensorDatenFromCCstatus(void) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + s->set_framesize(s, CCstatus.ImageFrameSize); + s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + + s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 + + s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 + s->set_contrast(s, CCstatus.ImageContrast); // -2 to 2 + s->set_saturation(s, CCstatus.ImageSaturation); // -2 to 2 + // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 + SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); + + s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable + s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 + s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 + + s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable + + s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable + s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 + + s->set_bpc(s, CCstatus.ImageBpc); // 0 = disable , 1 = enable + s->set_wpc(s, CCstatus.ImageWpc); // 0 = disable , 1 = enable + + s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable + s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable + + s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable + s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable + + s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable + + s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_awb_gain(s, CCstatus.ImageAwbGain); // 0 = disable , 1 = enable + s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable + + s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + // special_effect muß als Letztes gesetzt werden, sonst geht es nicht + s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + + TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; + vTaskDelay(xDelay2); + + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + +esp_err_t CCamera::getSensorDatenToCCstatus(void) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + CCstatus.CamSensor_id = s->id.PID; + + CCstatus.ImageFrameSize = (framesize_t)s->status.framesize; + CCstatus.ImageGainceiling = (gainceiling_t)s->status.gainceiling; + + CCstatus.ImageQuality = s->status.quality; + CCstatus.ImageBrightness = s->status.brightness; + CCstatus.ImageContrast = s->status.contrast; + CCstatus.ImageSaturation = s->status.saturation; + // CCstatus.ImageSharpness = s->status.sharpness; // gibt -1 zurück, da es nicht unterstützt wird + CCstatus.ImageWbMode = s->status.wb_mode; + CCstatus.ImageAwb = s->status.awb; + CCstatus.ImageAwbGain = s->status.awb_gain; + CCstatus.ImageAec = s->status.aec; + CCstatus.ImageAec2 = s->status.aec2; + CCstatus.ImageAeLevel = s->status.ae_level; + CCstatus.ImageAecValue = s->status.aec_value; + CCstatus.ImageAgc = s->status.agc; + CCstatus.ImageAgcGain = s->status.agc_gain; + CCstatus.ImageBpc = s->status.bpc; + CCstatus.ImageWpc = s->status.wpc; + CCstatus.ImageRawGma = s->status.raw_gma; + CCstatus.ImageLenc = s->status.lenc; + CCstatus.ImageSpecialEffect = s->status.special_effect; + CCstatus.ImageHmirror = s->status.hmirror; + CCstatus.ImageVflip = s->status.vflip; + CCstatus.ImageDcw = s->status.dcw; + CCstatus.ImageDenoiseLevel = s->status.denoise; + + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + + +// - It always zooms to the image center when offsets are zero +// - if imageSize = 0 then the image is not zoomed +// - if imageSize = max value, then the image is fully zoomed in +// - a zoom step is >>> Width + 32 px / Height + 24 px +void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY) +{ + // for OV2640, This works only if the aspect ratio of 4:3 is preserved in the window size. + // use only values divisible by 8 without remainder + imageWidth = CCstatus.ImageWidth + (imageSize * 4 * 8); + imageHeight = CCstatus.ImageHeight + (imageSize * 3 * 8); + + int _maxX = frameSizeX - imageWidth; + int _maxY = frameSizeY - imageHeight; + + if ((abs(zoomOffsetX) * 2) > _maxX) + { + if (zoomOffsetX > 0) + { + zoomOffsetX = _maxX; + } + else + { + zoomOffsetX = 0; + } + } + else + { + if (zoomOffsetX > 0) + { + zoomOffsetX = ((_maxX / 2) + zoomOffsetX); + } + else + { + zoomOffsetX = ((_maxX / 2) + zoomOffsetX); + } + } + + if ((abs(zoomOffsetY) * 2) > _maxY) + { + if (zoomOffsetY > 0) + { + zoomOffsetY = _maxY; + } + else + { + zoomOffsetY = 0; + } + } + else + { + if (zoomOffsetY > 0) + { + zoomOffsetY = ((_maxY / 2) + zoomOffsetY); + } + else + { + zoomOffsetY = ((_maxY / 2) + zoomOffsetY); + } + } +} + + +void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + if (zoomEnabled) + { + int _imageSize_temp = 0; + int _imageWidth = CCstatus.ImageWidth; + int _imageHeight = CCstatus.ImageHeight; + int _offsetx = zoomOffsetX; + int _offsety = zoomOffsetY; + int frameSizeX; + int frameSizeY; + + switch (CCstatus.CamSensor_id) + { + case OV5640_PID: + frameSizeX = 2592; + frameSizeY = 1944; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 + // 59 = ((2560 - 640) / 8 / 4) - 1 + if (imageSize < 59) + { + _imageSize_temp = (59 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case OV3660_PID: + frameSizeX = 2048; + frameSizeY = 1536; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 43 = ((2048 - 640) / 8 / 4) - 1 + if (imageSize < 43) + { + _imageSize_temp = (43 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case OV2640_PID: + frameSizeX = 1600; + frameSizeY = 1200; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 29 = ((1600 - 640) / 8 / 4) - 1 + if (imageSize < 29) + { + _imageSize_temp = (29 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + default: + // do nothing + break; + } + } + else + { + s->set_framesize(s, CCstatus.ImageFrameSize); + } + } +} + +void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (CCstatus.CamSensor_id == OV5640_PID) + { + qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) + } + else + { + qual = min(63, max(8, qual)); // Limit quality from 8..63 (values lower than 8 tent to be unstable) + } + + SetImageWidthHeightFromResolution(resol); + + + if (s != NULL) + { + s->set_quality(s, qual); + SetZoomSize(zoomEnabled, zoomOffsetX, zoomOffsetY, imageSize); + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetQualityZoomSize, Failed to get Cam control structure"); + } +} + +void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + if (CCstatus.CamSensor_id == OV2640_PID) + { + _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); + // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. + if (_autoSharpnessEnabled) + { + ov2640_enable_auto_sharpness(s); + } + else + { + ov2640_set_sharpness(s, _sharpnessLevel); + } + } + else + { + _sharpnessLevel = min(3, max(-3, _sharpnessLevel)); + // for CAMERA_OV5640 and CAMERA_OV3660 + if (_autoSharpnessEnabled) + { + // autoSharpness is not supported, default to zero + s->set_sharpness(s, 0); + } + else + { + s->set_sharpness(s, _sharpnessLevel); + } + } + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetCamSharpness, Failed to get Cam control structure"); + } +} + +void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) +{ + if (CCstatus.CamSensor_id == OV2640_PID) + { + s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); + } + else + { + // for CAMERA_OV5640 and CAMERA_OV3660 + bool scale = !(xOutput == xTotal && yOutput == yTotal); + bool binning = (xTotal >= (frameSizeX>>1)); + s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); + } +} + +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) + { + j->len = 0; + } + + if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) + { + return 0; + } + + j->len += len; + + return len; +} + +esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - Start"); +#endif + + _Image->EmptyImage(); // Delete previous stored raw image -> black image + + LEDOnOff(true); // Status-LED on + + if (delay > 0) + { + LightOnOff(true); // Flash-LED on + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay(xDelay); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - After LightOn"); +#endif + + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CaptureToBasisImage) - most probably caused " + "by a hardware problem (instablility, ...). System will reboot."); + doReboot(); + + return ESP_FAIL; + } + + if (CCstatus.DemoMode) + { + // Use images stored on SD-Card instead of camera image + /* Replace Framebuffer with image from SD-Card */ + loadNextDemoImage(fb); + } + + CImageBasis *_zwImage = new CImageBasis("zwImage"); + + if (_zwImage) + { + _zwImage->LoadFromMemory(fb->buf, fb->len); + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToBasisImage: Can't allocate _zwImage"); + } + + esp_camera_fb_return(fb); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - After fb_get"); +#endif + + LEDOnOff(false); // Status-LED off + + if (delay > 0) + { + LightOnOff(false); // Flash-LED off + } + + // TickType_t xDelay = 1000 / portTICK_PERIOD_MS; + // vTaskDelay( xDelay ); // wait for power to recover + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - After LoadFromMemory"); +#endif + + if (_zwImage == NULL) + { + return ESP_OK; + } + + stbi_uc *p_target; + stbi_uc *p_source; + int channels = 3; + int width = CCstatus.ImageWidth; + int height = CCstatus.ImageHeight; + +#ifdef DEBUG_DETAIL_ON + std::string _zw = "Targetimage: " + std::to_string((int)_Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height); + _zw = _zw + " _zwImage: " + std::to_string((int)_zwImage->rgb_image) + " Size: " + std::to_string(_zwImage->width) + ", " + std::to_string(_zwImage->height); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw); +#endif + + 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 = _zwImage->rgb_image + (channels * (y * width + x)); + + for (int c = 0; c < channels; c++) + { + p_target[c] = p_source[c]; + } + } + } + + delete _zwImage; + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - Done"); +#endif + + return ESP_OK; +} + +esp_err_t CCamera::CaptureToFile(std::string nm, int delay) +{ + string ftype; + + LEDOnOff(true); // Status-LED on + + if (delay > 0) + { + LightOnOff(true); // Flash-LED on + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay(xDelay); + } + + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " + "Check camera module and/or proper electrical connection"); + // doReboot(); + + return ESP_FAIL; + } + + LEDOnOff(false); // Status-LED off + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "w %d, h %d, size %d", fb->width, fb->height, fb->len); +#endif + + nm = FormatFileName(nm); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Save Camera to: %s", nm.c_str()); +#endif + + ftype = toUpper(getFileType(nm)); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Filetype: %s", ftype.c_str()); +#endif + + uint8_t *buf = NULL; + size_t buf_len = 0; + bool converted = false; + + if (ftype.compare("BMP") == 0) + { + frame2bmp(fb, &buf, &buf_len); + converted = true; + } + + if (ftype.compare("JPG") == 0) + { + if (fb->format != PIXFORMAT_JPEG) + { + bool jpeg_converted = frame2jpg(fb, CCstatus.ImageQuality, &buf, &buf_len); + converted = true; + + if (!jpeg_converted) + { + ESP_LOGE(TAG, "JPEG compression failed"); + } + } + else + { + buf_len = fb->len; + buf = fb->buf; + } + } + + FILE *fp = fopen(nm.c_str(), "wb"); + + if (fp == NULL) + { + // If an error occurs during the file creation + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Failed to open file " + nm); + } + else + { + fwrite(buf, sizeof(uint8_t), buf_len, fp); + fclose(fp); + } + + if (converted) + { + free(buf); + } + + esp_camera_fb_return(fb); + + if (delay > 0) + { + LightOnOff(false); // Flash-LED off + } + + return ESP_OK; +} + +esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) +{ + esp_err_t res = ESP_OK; + size_t fb_len = 0; + int64_t fr_start = esp_timer_get_time(); + + LEDOnOff(true); // Status-LED on + + if (delay > 0) + { + LightOnOff(true); // Flash-LED on + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay(xDelay); + } + + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " + "Check camera module and/or proper electrical connection"); + httpd_resp_send_500(req); + // doReboot(); + + return ESP_FAIL; + } + + LEDOnOff(false); // Status-LED off + res = httpd_resp_set_type(req, "image/jpeg"); + + if (res == ESP_OK) + { + res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=raw.jpg"); + } + + if (res == ESP_OK) + { + if (CCstatus.DemoMode) + { + // Use images stored on SD-Card instead of camera image + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using Demo image!"); + /* Replace Framebuffer with image from SD-Card */ + loadNextDemoImage(fb); + + res = httpd_resp_send(req, (const char *)fb->buf, fb->len); + } + else + { + if (fb->format == PIXFORMAT_JPEG) + { + fb_len = fb->len; + res = httpd_resp_send(req, (const char *)fb->buf, fb->len); + } + else + { + jpg_chunking_t jchunk = {req, 0}; + res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; + httpd_resp_send_chunk(req, NULL, 0); + fb_len = jchunk.len; + } + } + } + + esp_camera_fb_return(fb); + int64_t fr_end = esp_timer_get_time(); + + ESP_LOGI(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); + + if (delay > 0) + { + LightOnOff(false); // Flash-LED off + } + + return res; +} + +esp_err_t CCamera::CaptureToStream(httpd_req_t *req, bool FlashlightOn) +{ + esp_err_t res = ESP_OK; + size_t fb_len = 0; + int64_t fr_start; + char *part_buf[64]; + + // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden + if (CFstatus.changedCameraSettings) + { + Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + CFstatus.changedCameraSettings = false; + } + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream started"); + + if (FlashlightOn) + { + LEDOnOff(true); // Status-LED on + LightOnOff(true); // Flash-LED on + } + + // httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //stream is blocking web interface, only serving to local + + httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); + httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); + + while (1) + { + fr_start = esp_timer_get_time(); + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToStream: Camera framebuffer not available"); + break; + } + + fb_len = fb->len; + + if (res == ESP_OK) + { + size_t hlen = snprintf((char *)part_buf, sizeof(part_buf), _STREAM_PART, fb_len); + res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); + } + + if (res == ESP_OK) + { + res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb_len); + } + + if (res == ESP_OK) + { + res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); + } + + esp_camera_fb_return(fb); + + int64_t fr_end = esp_timer_get_time(); + ESP_LOGD(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); + + if (res != ESP_OK) + { + // Exit loop, e.g. also when closing the webpage + break; + } + + int64_t fr_delta_ms = (fr_end - fr_start) / 1000; + + if (CAM_LIVESTREAM_REFRESHRATE > fr_delta_ms) + { + const TickType_t xDelay = (CAM_LIVESTREAM_REFRESHRATE - fr_delta_ms) / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "Stream: sleep for: %ldms", (long)xDelay * 10); + vTaskDelay(xDelay); + } + } + + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream stopped"); + + return res; +} + +void CCamera::LightOnOff(bool status) +{ + GpioHandler *gpioHandler = gpio_handler_get(); + + if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) + { + ESP_LOGD(TAG, "Use gpioHandler to trigger flashlight"); + gpioHandler->flashLightEnable(status); + } + else + { +#ifdef USE_PWM_LEDFLASH + if (status) + { + ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", CCstatus.ImageLedIntensity); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, CCstatus.ImageLedIntensity)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); + } + else + { + ESP_LOGD(TAG, "Internal Flash-LED turn off PWM"); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0)); + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); + } +#else + // Init the GPIO + gpio_pad_select_gpio(FLASH_GPIO); + + // Set the GPIO as a push/pull output + gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); + + if (status) + { + gpio_set_level(FLASH_GPIO, 1); + } + else + { + gpio_set_level(FLASH_GPIO, 0); + } +#endif + } +} + +void CCamera::LEDOnOff(bool status) +{ + if (xHandle_task_StatusLED == NULL) + { + // Init the GPIO + gpio_pad_select_gpio(BLINK_GPIO); + + /* Set the GPIO as a push/pull output */ + gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); + + if (!status) + { + gpio_set_level(BLINK_GPIO, 1); + } + else + { + gpio_set_level(BLINK_GPIO, 0); + } + } +} + +void CCamera::SetImageWidthHeightFromResolution(framesize_t resol) +{ + if (resol == FRAMESIZE_QVGA) + { + CCstatus.ImageHeight = 240; + CCstatus.ImageWidth = 320; + } + else if (resol == FRAMESIZE_VGA) + { + CCstatus.ImageHeight = 480; + CCstatus.ImageWidth = 640; + } + else if (resol == FRAMESIZE_SVGA) + { + CCstatus.ImageHeight = 600; + CCstatus.ImageWidth = 800; + } + else if (resol == FRAMESIZE_XGA) + { + CCstatus.ImageHeight = 768; + CCstatus.ImageWidth = 1024; + } + else if (resol == FRAMESIZE_HD) + { + CCstatus.ImageHeight = 720; + CCstatus.ImageWidth = 1280; + } + else if (resol == FRAMESIZE_SXGA) + { + CCstatus.ImageHeight = 1024; + CCstatus.ImageWidth = 1280; + } + else if (resol == FRAMESIZE_UXGA) + { + CCstatus.ImageHeight = 1200; + CCstatus.ImageWidth = 1600; + } +} + +framesize_t CCamera::TextToFramesize(const char *_size) +{ + if (strcmp(_size, "QVGA") == 0) + { + return FRAMESIZE_QVGA; // 320x240 + } + else if (strcmp(_size, "VGA") == 0) + { + return FRAMESIZE_VGA; // 640x480 + } + else if (strcmp(_size, "SVGA") == 0) + { + return FRAMESIZE_SVGA; // 800x600 + } + else if (strcmp(_size, "XGA") == 0) + { + return FRAMESIZE_XGA; // 1024x768 + } + else if (strcmp(_size, "SXGA") == 0) + { + return FRAMESIZE_SXGA; // 1280x1024 + } + else if (strcmp(_size, "UXGA") == 0) + { + return FRAMESIZE_UXGA; // 1600x1200 + } + + return CCstatus.ImageFrameSize; +} + +std::vector demoFiles; + +void CCamera::useDemoMode(void) +{ + char line[50]; + + FILE *fd = fopen("/sdcard/demo/files.txt", "r"); + + if (!fd) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can not start Demo mode, the folder '/sdcard/demo/' does not contain the needed files!"); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "See Details on https://jomjol.github.io/AI-on-the-edge-device-docs/Demo-Mode!"); + return; + } + + demoImage = (uint8_t *)malloc(DEMO_IMAGE_SIZE); + + if (demoImage == NULL) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to acquire required memory for demo image!"); + return; + } + + while (fgets(line, sizeof(line), fd) != NULL) + { + line[strlen(line) - 1] = '\0'; + demoFiles.push_back(line); + } + + fclose(fd); + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Using Demo mode (" + std::to_string(demoFiles.size()) + " files) instead of real camera image!"); + + for (auto file : demoFiles) + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, file); + } + + CCstatus.DemoMode = true; +} + +bool CCamera::loadNextDemoImage(camera_fb_t *fb) +{ + char filename[50]; + int readBytes; + long fileSize; + + snprintf(filename, sizeof(filename), "/sdcard/demo/%s", demoFiles[getCountFlowRounds() % demoFiles.size()].c_str()); + + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using " + std::string(filename) + " as demo image"); + + /* Inject saved image */ + + FILE *fp = fopen(filename, "rb"); + + if (!fp) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filename) + "!"); + return false; + } + + fileSize = GetFileSize(filename); + + if (fileSize > DEMO_IMAGE_SIZE) + { + char buf[100]; + snprintf(buf, sizeof(buf), "Demo Image (%d bytes) is larger than provided buffer (%d bytes)!", (int)fileSize, DEMO_IMAGE_SIZE); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string(buf)); + return false; + } + + readBytes = fread(demoImage, 1, DEMO_IMAGE_SIZE, fp); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "read " + std::to_string(readBytes) + " bytes"); + fclose(fp); + + fb->buf = demoImage; // Update pointer + fb->len = readBytes; + // ToDo do we also need to set height, width, format and timestamp? + + return true; +} + +long CCamera::GetFileSize(std::string filename) +{ + struct stat stat_buf; + long rc = stat(filename.c_str(), &stat_buf); + return rc == 0 ? stat_buf.st_size : -1; +} diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index bd4fe7893..fb284d3ca 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -1,115 +1,111 @@ -#pragma once - -#ifndef CLASSCONTROLLCAMERA_H -#define CLASSCONTROLLCAMERA_H - -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" - -#include "esp_camera.h" -#include -#include -#include "CImageBasis.h" -#include "../../include/defines.h" - -typedef enum -{ - OV2640_MODE_UXGA, - OV2640_MODE_SVGA, - OV2640_MODE_CIF -} ov2640_sensor_mode_t; - -typedef struct -{ - framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 - gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - - int ImageQuality; // 0 - 63 - int ImageBrightness; // (-2 to 2) - set brightness - int ImageContrast; //-2 - 2 - int ImageSaturation; //-2 - 2 - int ImageSharpness; //-2 - 2 - bool ImageAutoSharpness; - int ImageSpecialEffect; // 0 - 6 - int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - int ImageAwb; // white balance enable (0 or 1) - int ImageAwbGain; // Auto White Balance enable (0 or 1) - int ImageAec; // auto exposure off (1 or 0) - int ImageAec2; // automatic exposure sensor (0 or 1) - int ImageAeLevel; // auto exposure levels (-2 to 2) - int ImageAecValue; // set exposure manually (0-1200) - int ImageAgc; // auto gain off (1 or 0) - int ImageAgcGain; // set gain manually (0 - 30) - int ImageBpc; // black pixel correction - int ImageWpc; // white pixel correction - int ImageRawGma; // (1 or 0) - int ImageLenc; // lens correction (1 or 0) - int ImageHmirror; // (0 or 1) flip horizontally - int ImageVflip; // Invert image (0 or 1) - int ImageDcw; // downsize enable (1 or 0) - - int ImageWidth; - int ImageHeight; - - int ImageLedIntensity; - - bool ImageZoomEnabled; - int ImageZoomMode; - int ImageZoomOffsetX; - int ImageZoomOffsetY; - int ImageZoomSize; - - int WaitBeforePicture; - bool isImageSize; - - bool CameraInitSuccessful; - bool changedCameraSettings; - bool DemoMode; - bool SaveAllFiles; -} camera_controll_config_temp_t; - -extern camera_controll_config_temp_t CCstatus; - -class CCamera -{ -protected: - void ledc_init(void); - bool loadNextDemoImage(camera_fb_t *fb); - long GetFileSize(std::string filename); - void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); - void SetImageWidthHeightFromResolution(framesize_t resol); - void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); - -public: - CCamera(void); - esp_err_t InitCam(void); - - void LightOnOff(bool status); - void LEDOnOff(bool status); - - esp_err_t setSensorDatenFromCCstatus(void); - esp_err_t getSensorDatenToCCstatus(void); - - esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); - esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); - - void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); - void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); - void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel); - - void SetLEDIntensity(float _intrel); - bool testCamera(void); - bool getCameraInitSuccessful(void); - void useDemoMode(void); - - 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; +#pragma once + +#ifndef CLASSCONTROLLCAMERA_H +#define CLASSCONTROLLCAMERA_H + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/event_groups.h" + +#include "esp_camera.h" +#include +#include +#include "CImageBasis.h" +#include "../../include/defines.h" + +typedef struct +{ + uint16_t CamSensor_id; + + framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 + gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + + int ImageQuality; // 0 - 63 + int ImageBrightness; // (-2 to 2) - set brightness + int ImageContrast; //-2 - 2 + int ImageSaturation; //-2 - 2 + int ImageSharpness; //-2 - 2 + bool ImageAutoSharpness; + int ImageSpecialEffect; // 0 - 6 + int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + int ImageAwb; // white balance enable (0 or 1) + int ImageAwbGain; // Auto White Balance enable (0 or 1) + int ImageAec; // auto exposure off (1 or 0) + int ImageAec2; // automatic exposure sensor (0 or 1) + int ImageAeLevel; // auto exposure levels (-2 to 2) + int ImageAecValue; // set exposure manually (0-1200) + int ImageAgc; // auto gain off (1 or 0) + int ImageAgcGain; // set gain manually (0 - 30) + int ImageBpc; // black pixel correction + int ImageWpc; // white pixel correction + int ImageRawGma; // (1 or 0) + int ImageLenc; // lens correction (1 or 0) + int ImageHmirror; // (0 or 1) flip horizontally + int ImageVflip; // Invert image (0 or 1) + int ImageDcw; // downsize enable (1 or 0) + + int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + int ImageWidth; + int ImageHeight; + + int ImageLedIntensity; + + bool ImageZoomEnabled; + int ImageZoomOffsetX; + int ImageZoomOffsetY; + int ImageZoomSize; + + int WaitBeforePicture; + bool isImageSize; + + bool CameraInitSuccessful; + bool changedCameraSettings; + bool DemoMode; + bool SaveAllFiles; +} camera_controll_config_temp_t; + +extern camera_controll_config_temp_t CCstatus; + +class CCamera +{ +protected: + void ledc_init(void); + bool loadNextDemoImage(camera_fb_t *fb); + long GetFileSize(std::string filename); + void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); + void SetImageWidthHeightFromResolution(framesize_t resol); + void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); + +public: + CCamera(void); + esp_err_t InitCam(void); + + void LightOnOff(bool status); + void LEDOnOff(bool status); + + esp_err_t setSensorDatenFromCCstatus(void); + esp_err_t getSensorDatenToCCstatus(void); + + esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); + esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); + + void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); + void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); + void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel); + + void SetLEDIntensity(float _intrel); + bool testCamera(void); + bool getCameraInitSuccessful(void); + void useDemoMode(void); + + 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; #endif \ No newline at end of file diff --git a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp index 999296b13..a577061d6 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp @@ -1,599 +1,525 @@ -#include -#include -#include -#include - -#include "ClassFlowTakeImage.h" -#include "Helper.h" -#include "ClassLogFile.h" - -#include "CImageBasis.h" -#include "ClassControllCamera.h" -#include "MainFlowControl.h" - -#include "esp_wifi.h" -#include "esp_log.h" -#include "../../include/defines.h" -#include "psram.h" - -#include - -// #define DEBUG_DETAIL_ON -// #define WIFITURNOFF - -static const char *TAG = "TAKEIMAGE"; - -esp_err_t ClassFlowTakeImage::camera_capture(void) -{ - string nm = namerawimage; - Camera.CaptureToFile(nm); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - return ESP_OK; -} - -void ClassFlowTakeImage::takePictureWithFlash(int flash_duration) -{ - // in case the image is flipped, it must be reset here // - rawImage->width = CCstatus.ImageWidth; - rawImage->height = CCstatus.ImageHeight; - - ESP_LOGD(TAG, "flash_duration: %d", flash_duration); - - Camera.CaptureToBasisImage(rawImage, flash_duration); - - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - if (CCstatus.SaveAllFiles) - { - rawImage->SaveToFile(namerawimage); - } -} - -void ClassFlowTakeImage::SetInitialParameter(void) -{ - TimeImageTaken = 0; - rawImage = NULL; - disabled = false; - namerawimage = "/sdcard/img_tmp/raw.jpg"; -} - -// auslesen der Kameraeinstellungen aus der config.ini -// wird beim Start aufgerufen -bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) -{ - Camera.getSensorDatenToCCstatus(); // Kamera >>> CCstatus - - std::vector splitted; - - aktparamgraph = trim(aktparamgraph); - - if (aktparamgraph.size() == 0) - { - if (!this->GetNextParagraph(pfile, aktparamgraph)) - { - return false; - } - } - - if (aktparamgraph.compare("[TakeImage]") != 0) - { - // Paragraph does not fit TakeImage - return false; - } - - while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) - { - splitted = ZerlegeZeile(aktparamgraph); - - if ((toUpper(splitted[0]) == "RAWIMAGESLOCATION") && (splitted.size() > 1)) - { - imagesLocation = "/sdcard" + splitted[1]; - isLogImage = true; - } - - else if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1)) - { - this->imagesRetention = std::stod(splitted[1]); - } - - else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.SaveAllFiles = 1; - } - else - { - CCstatus.SaveAllFiles = 0; - } - } - - else if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1)) - { - int _WaitBeforePicture = std::stoi(splitted[1]); - if (_WaitBeforePicture != 0) - { - CCstatus.WaitBeforePicture = _WaitBeforePicture; - } - else - { - CCstatus.WaitBeforePicture = 2; - } - } - - else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1)) - { - std::string _ImageGainceiling = toUpper(splitted[1]); - if (_ImageGainceiling == "X4") - { - CCstatus.ImageGainceiling = GAINCEILING_4X; - } - else if (_ImageGainceiling == "X8") - { - CCstatus.ImageGainceiling = GAINCEILING_8X; - } - else if (_ImageGainceiling == "X16") - { - CCstatus.ImageGainceiling = GAINCEILING_16X; - } - else if (_ImageGainceiling == "X32") - { - CCstatus.ImageGainceiling = GAINCEILING_32X; - } - else if (_ImageGainceiling == "X64") - { - CCstatus.ImageGainceiling = GAINCEILING_64X; - } - else if (_ImageGainceiling == "X128") - { - CCstatus.ImageGainceiling = GAINCEILING_128X; - } - else - { - CCstatus.ImageGainceiling = GAINCEILING_2X; - } - } - - else if ((toUpper(splitted[0]) == "CAMQUALITY") && (splitted.size() > 1)) - { - int _ImageQuality = std::stoi(splitted[1]); - if ((_ImageQuality >= 0) && (_ImageQuality <= 63)) - { - CCstatus.ImageQuality = _ImageQuality; - } - } - - else if ((toUpper(splitted[0]) == "CAMBRIGHTNESS") && (splitted.size() > 1)) - { - int _ImageBrightness = std::stoi(splitted[1]); - if ((_ImageBrightness >= -2) && (_ImageBrightness <= 2)) - { - CCstatus.ImageBrightness = _ImageBrightness; - } - } - - else if ((toUpper(splitted[0]) == "CAMCONTRAST") && (splitted.size() > 1)) - { - int _ImageContrast = std::stoi(splitted[1]); - if ((_ImageContrast >= -2) && (_ImageContrast <= 2)) - { - CCstatus.ImageContrast = _ImageContrast; - } - } - - else if ((toUpper(splitted[0]) == "CAMSATURATION") && (splitted.size() > 1)) - { - int _ImageSaturation = std::stoi(splitted[1]); - if ((_ImageSaturation >= -2) && (_ImageSaturation <= 2)) - { - CCstatus.ImageSaturation = _ImageSaturation; - } - } - - else if ((toUpper(splitted[0]) == "CAMSHARPNESS") && (splitted.size() > 1)) - { - int _ImageSharpness = std::stoi(splitted[1]); - if ((_ImageSharpness >= -2) && (_ImageSharpness <= 2)) - { - CCstatus.ImageSharpness = _ImageSharpness; - } - } - - else if ((toUpper(splitted[0]) == "CAMAUTOSHARPNESS") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageAutoSharpness = 1; - } - else - { - CCstatus.ImageAutoSharpness = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMSPECIALEFFECT") && (splitted.size() > 1)) - { - std::string _ImageSpecialEffect = toUpper(splitted[1]); - if (_ImageSpecialEffect == "NEGATIVE") - { - CCstatus.ImageSpecialEffect = 1; - } - else if (_ImageSpecialEffect == "GRAYSCALE") - { - CCstatus.ImageSpecialEffect = 2; - } - else if (_ImageSpecialEffect == "RED") - { - CCstatus.ImageSpecialEffect = 3; - } - else if (_ImageSpecialEffect == "GREEN") - { - CCstatus.ImageSpecialEffect = 4; - } - else if (_ImageSpecialEffect == "BLUE") - { - CCstatus.ImageSpecialEffect = 5; - } - else if (_ImageSpecialEffect == "RETRO") - { - CCstatus.ImageSpecialEffect = 6; - } - else - { - CCstatus.ImageSpecialEffect = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMWBMODE") && (splitted.size() > 1)) - { - std::string _ImageWbMode = toUpper(splitted[1]); - if (_ImageWbMode == "SUNNY") - { - CCstatus.ImageWbMode = 1; - } - else if (_ImageWbMode == "CLOUDY") - { - CCstatus.ImageWbMode = 2; - } - else if (_ImageWbMode == "OFFICE") - { - CCstatus.ImageWbMode = 3; - } - else if (_ImageWbMode == "HOME") - { - CCstatus.ImageWbMode = 4; - } - else - { - CCstatus.ImageWbMode = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAWB") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageAwb = 1; - } - else - { - CCstatus.ImageAwb = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAWBGAIN") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageAwbGain = 1; - } - else - { - CCstatus.ImageAwbGain = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAEC") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageAec = 1; - } - else - { - CCstatus.ImageAec = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAEC2") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageAec2 = 1; - } - else - { - CCstatus.ImageAec2 = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAELEVEL") && (splitted.size() > 1)) - { - int _ImageAeLevel = std::stoi(splitted[1]); - if ((_ImageAeLevel >= -2) && (_ImageAeLevel <= 2)) - { - CCstatus.ImageAeLevel = _ImageAeLevel; - } - } - - else if ((toUpper(splitted[0]) == "CAMAECVALUE") && (splitted.size() > 1)) - { - int _ImageAecValue = std::stoi(splitted[1]); - if ((_ImageAecValue >= 0) && (_ImageAecValue <= 1200)) - { - CCstatus.ImageAecValue = _ImageAecValue; - } - } - - else if ((toUpper(splitted[0]) == "CAMAGC") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageAgc = 1; - } - else - { - CCstatus.ImageAgc = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAGCGAIN") && (splitted.size() > 1)) - { - int _ImageAgcGain = std::stoi(splitted[1]); - if ((_ImageAgcGain >= 0) && (_ImageAgcGain <= 30)) - { - CCstatus.ImageAgcGain = _ImageAgcGain; - } - } - - else if ((toUpper(splitted[0]) == "CAMBPC") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageBpc = 1; - } - else - { - CCstatus.ImageBpc = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMWPC") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageWpc = 1; - } - else - { - CCstatus.ImageWpc = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMRAWGMA") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageRawGma = 1; - } - else - { - CCstatus.ImageRawGma = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMLENC") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageLenc = 1; - } - else - { - CCstatus.ImageLenc = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMHMIRROR") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageHmirror = 1; - } - else - { - CCstatus.ImageHmirror = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMVFLIP") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageVflip = 1; - } - else - { - CCstatus.ImageVflip = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMDCW") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageDcw = 1; - } - else - { - CCstatus.ImageDcw = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMZOOM") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.ImageZoomEnabled = 1; - } - else - { - CCstatus.ImageZoomEnabled = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETX") && (splitted.size() > 1)) - { - CCstatus.ImageZoomOffsetX = std::stoi(splitted[1]); - } - - else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETY") && (splitted.size() > 1)) - { - CCstatus.ImageZoomOffsetY = std::stoi(splitted[1]); - } - - else if ((toUpper(splitted[0]) == "CAMZOOMSIZE") && (splitted.size() > 1)) - { - int _ImageZoomSize = std::stoi(splitted[1]); - if (_ImageZoomSize >= 0) - { - CCstatus.ImageZoomSize = _ImageZoomSize; - } - } - - else if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1)) - { - float ledintensity = std::stof(splitted[1]); - Camera.SetLEDIntensity(ledintensity); - } - - else if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1)) - { - if (toUpper(splitted[1]) == "TRUE") - { - CCstatus.DemoMode = true; - Camera.useDemoMode(); - } - else - { - CCstatus.DemoMode = false; - } - } - } - - Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); - - rawImage = new CImageBasis("rawImage"); - rawImage->CreateEmptyImage(CCstatus.ImageWidth, CCstatus.ImageHeight, 3); - - return true; -} - -ClassFlowTakeImage::ClassFlowTakeImage(std::vector *lfc) : ClassFlowImage(lfc, TAG) -{ - imagesLocation = "/log/source"; - imagesRetention = 5; - SetInitialParameter(); -} - -string ClassFlowTakeImage::getHTMLSingleStep(string host) -{ - string result; - result = "Raw Image:
\n\n"; - return result; -} - -// wird bei jeder Auswertrunde aufgerufen -bool ClassFlowTakeImage::doFlow(string zwtime) -{ - psram_init_shared_memory_for_take_image_step(); - - string logPath = CreateLogFolder(zwtime); - - int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash"); -#endif - -#ifdef WIFITURNOFF - esp_wifi_stop(); // to save power usage and -#endif - - // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden - if (CFstatus.changedCameraSettings) - { - Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); - CFstatus.changedCameraSettings = false; - } - - takePictureWithFlash(flash_duration); - -#ifdef WIFITURNOFF - esp_wifi_start(); -#endif - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash"); -#endif - - LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage); - - RemoveOldLogs(); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs"); -#endif - - psram_deinit_shared_memory_for_take_image_step(); - - return true; -} - -esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req) -{ - int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - return Camera.CaptureToHTTP(req, flash_duration); -} - -ImageData *ClassFlowTakeImage::SendRawImage(void) -{ - CImageBasis *zw = new CImageBasis("SendRawImage", rawImage); - ImageData *id; - int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); - Camera.CaptureToBasisImage(zw, flash_duration); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - id = zw->writeToMemoryAsJPG(); - delete zw; - return id; -} - -time_t ClassFlowTakeImage::getTimeImageTaken(void) -{ - return TimeImageTaken; -} - -ClassFlowTakeImage::~ClassFlowTakeImage(void) -{ - delete rawImage; -} +#include +#include +#include +#include + +#include "ClassFlowTakeImage.h" +#include "Helper.h" +#include "ClassLogFile.h" + +#include "CImageBasis.h" +#include "ClassControllCamera.h" +#include "MainFlowControl.h" + +#include "esp_wifi.h" +#include "esp_log.h" +#include "../../include/defines.h" +#include "psram.h" + +#include + +// #define DEBUG_DETAIL_ON +// #define WIFITURNOFF + +static const char *TAG = "TAKEIMAGE"; + +esp_err_t ClassFlowTakeImage::camera_capture(void) +{ + string nm = namerawimage; + Camera.CaptureToFile(nm); + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + return ESP_OK; +} + +void ClassFlowTakeImage::takePictureWithFlash(int flash_duration) +{ + // in case the image is flipped, it must be reset here // + rawImage->width = CCstatus.ImageWidth; + rawImage->height = CCstatus.ImageHeight; + + ESP_LOGD(TAG, "flash_duration: %d", flash_duration); + + Camera.CaptureToBasisImage(rawImage, flash_duration); + + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + if (CCstatus.SaveAllFiles) + { + rawImage->SaveToFile(namerawimage); + } +} + +void ClassFlowTakeImage::SetInitialParameter(void) +{ + TimeImageTaken = 0; + rawImage = NULL; + disabled = false; + namerawimage = "/sdcard/img_tmp/raw.jpg"; +} + +// auslesen der Kameraeinstellungen aus der config.ini +// wird beim Start aufgerufen +bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) +{ + Camera.getSensorDatenToCCstatus(); // Kamera >>> CCstatus + + std::vector splitted; + + aktparamgraph = trim(aktparamgraph); + + if (aktparamgraph.size() == 0) + { + if (!this->GetNextParagraph(pfile, aktparamgraph)) + { + return false; + } + } + + if (aktparamgraph.compare("[TakeImage]") != 0) + { + // Paragraph does not fit TakeImage + return false; + } + + while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) + { + splitted = ZerlegeZeile(aktparamgraph); + + if ((toUpper(splitted[0]) == "RAWIMAGESLOCATION") && (splitted.size() > 1)) + { + imagesLocation = "/sdcard" + splitted[1]; + isLogImage = true; + } + + else if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1)) + { + this->imagesRetention = std::stod(splitted[1]); + } + + else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) + { + CCstatus.SaveAllFiles = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1)) + { + int _WaitBeforePicture = std::stoi(splitted[1]); + if (_WaitBeforePicture != 0) + { + CCstatus.WaitBeforePicture = _WaitBeforePicture; + } + else + { + CCstatus.WaitBeforePicture = 2; + } + } + + else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1)) + { + std::string _ImageGainceiling = toUpper(splitted[1]); + if (_ImageGainceiling == "X4") + { + CCstatus.ImageGainceiling = GAINCEILING_4X; + } + else if (_ImageGainceiling == "X8") + { + CCstatus.ImageGainceiling = GAINCEILING_8X; + } + else if (_ImageGainceiling == "X16") + { + CCstatus.ImageGainceiling = GAINCEILING_16X; + } + else if (_ImageGainceiling == "X32") + { + CCstatus.ImageGainceiling = GAINCEILING_32X; + } + else if (_ImageGainceiling == "X64") + { + CCstatus.ImageGainceiling = GAINCEILING_64X; + } + else if (_ImageGainceiling == "X128") + { + CCstatus.ImageGainceiling = GAINCEILING_128X; + } + else + { + CCstatus.ImageGainceiling = GAINCEILING_2X; + } + } + + else if ((toUpper(splitted[0]) == "CAMQUALITY") && (splitted.size() > 1)) + { + int _ImageQuality = std::stoi(splitted[1]); + CCstatus.ImageQuality = clipInt(_ImageQuality, 63, 6); + } + + else if ((toUpper(splitted[0]) == "CAMBRIGHTNESS") && (splitted.size() > 1)) + { + int _ImageBrightness = std::stoi(splitted[1]); + CCstatus.ImageBrightness = clipInt(_ImageBrightness, 2, -2); + } + + else if ((toUpper(splitted[0]) == "CAMCONTRAST") && (splitted.size() > 1)) + { + int _ImageContrast = std::stoi(splitted[1]); + CCstatus.ImageContrast = clipInt(_ImageContrast, 2, -2); + } + + else if ((toUpper(splitted[0]) == "CAMSATURATION") && (splitted.size() > 1)) + { + int _ImageSaturation = std::stoi(splitted[1]); + CCstatus.ImageSaturation = clipInt(_ImageSaturation, 2, -2); + } + + else if ((toUpper(splitted[0]) == "CAMSHARPNESS") && (splitted.size() > 1)) + { + int _ImageSharpness = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageSharpness = clipInt(_ImageSharpness, 2, -2); + } + else + { + CCstatus.ImageSharpness = clipInt(_ImageSharpness, 3, -3); + } + } + + else if ((toUpper(splitted[0]) == "CAMAUTOSHARPNESS") && (splitted.size() > 1)) + { + CCstatus.ImageAutoSharpness = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMSPECIALEFFECT") && (splitted.size() > 1)) + { + std::string _ImageSpecialEffect = toUpper(splitted[1]); + if (_ImageSpecialEffect == "NEGATIVE") + { + CCstatus.ImageSpecialEffect = 1; + } + else if (_ImageSpecialEffect == "GRAYSCALE") + { + CCstatus.ImageSpecialEffect = 2; + } + else if (_ImageSpecialEffect == "RED") + { + CCstatus.ImageSpecialEffect = 3; + } + else if (_ImageSpecialEffect == "GREEN") + { + CCstatus.ImageSpecialEffect = 4; + } + else if (_ImageSpecialEffect == "BLUE") + { + CCstatus.ImageSpecialEffect = 5; + } + else if (_ImageSpecialEffect == "RETRO") + { + CCstatus.ImageSpecialEffect = 6; + } + else + { + CCstatus.ImageSpecialEffect = 0; + } + } + + else if ((toUpper(splitted[0]) == "CAMWBMODE") && (splitted.size() > 1)) + { + std::string _ImageWbMode = toUpper(splitted[1]); + if (_ImageWbMode == "SUNNY") + { + CCstatus.ImageWbMode = 1; + } + else if (_ImageWbMode == "CLOUDY") + { + CCstatus.ImageWbMode = 2; + } + else if (_ImageWbMode == "OFFICE") + { + CCstatus.ImageWbMode = 3; + } + else if (_ImageWbMode == "HOME") + { + CCstatus.ImageWbMode = 4; + } + else + { + CCstatus.ImageWbMode = 0; + } + } + + else if ((toUpper(splitted[0]) == "CAMAWB") && (splitted.size() > 1)) + { + CCstatus.ImageAwb = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAWBGAIN") && (splitted.size() > 1)) + { + CCstatus.ImageAwbGain = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAEC") && (splitted.size() > 1)) + { + CCstatus.ImageAec = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAEC2") && (splitted.size() > 1)) + { + CCstatus.ImageAec2 = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAELEVEL") && (splitted.size() > 1)) + { + int _ImageAeLevel = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 2, -2); + } + else + { + CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 5, -5); + } + } + + else if ((toUpper(splitted[0]) == "CAMAECVALUE") && (splitted.size() > 1)) + { + int _ImageAecValue = std::stoi(splitted[1]); + CCstatus.ImageAecValue = clipInt(_ImageAecValue, 1200, 0); + } + + else if ((toUpper(splitted[0]) == "CAMAGC") && (splitted.size() > 1)) + { + CCstatus.ImageAgc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAGCGAIN") && (splitted.size() > 1)) + { + int _ImageAgcGain = std::stoi(splitted[1]); + CCstatus.ImageAgcGain = clipInt(_ImageAgcGain, 30, 0); + } + + else if ((toUpper(splitted[0]) == "CAMBPC") && (splitted.size() > 1)) + { + CCstatus.ImageBpc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMWPC") && (splitted.size() > 1)) + { + CCstatus.ImageWpc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMRAWGMA") && (splitted.size() > 1)) + { + CCstatus.ImageRawGma = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMLENC") && (splitted.size() > 1)) + { + CCstatus.ImageLenc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMHMIRROR") && (splitted.size() > 1)) + { + CCstatus.ImageHmirror = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMVFLIP") && (splitted.size() > 1)) + { + CCstatus.ImageVflip = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMDCW") && (splitted.size() > 1)) + { + CCstatus.ImageDcw = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMSDENOISE") && (splitted.size() > 1)) + { + int _ImageDenoiseLevel = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageDenoiseLevel = 0; + } + else + { + CCstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0); + } + } + + else if ((toUpper(splitted[0]) == "CAMZOOM") && (splitted.size() > 1)) + { + CCstatus.ImageZoomEnabled = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETX") && (splitted.size() > 1)) + { + int _ImageZoomOffsetX = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960); + } + } + + else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETY") && (splitted.size() > 1)) + { + int _ImageZoomOffsetY = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720); + } + } + + else if ((toUpper(splitted[0]) == "CAMZOOMSIZE") && (splitted.size() > 1)) + { + int _ImageZoomSize = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0); + } + } + + else if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1)) + { + float ledintensity = std::stof(splitted[1]); + Camera.SetLEDIntensity(ledintensity); + } + + else if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1)) + { + CCstatus.DemoMode = stringToBoolean(toUpper(splitted[1])); + if (CCstatus.DemoMode) + { + Camera.useDemoMode(); + } + } + } + + Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + + rawImage = new CImageBasis("rawImage"); + rawImage->CreateEmptyImage(CCstatus.ImageWidth, CCstatus.ImageHeight, 3); + + return true; +} + +ClassFlowTakeImage::ClassFlowTakeImage(std::vector *lfc) : ClassFlowImage(lfc, TAG) +{ + imagesLocation = "/log/source"; + imagesRetention = 5; + SetInitialParameter(); +} + +string ClassFlowTakeImage::getHTMLSingleStep(string host) +{ + string result; + result = "Raw Image:
\n\n"; + return result; +} + +// wird bei jeder Auswertrunde aufgerufen +bool ClassFlowTakeImage::doFlow(string zwtime) +{ + psram_init_shared_memory_for_take_image_step(); + + string logPath = CreateLogFolder(zwtime); + + int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash"); +#endif + +#ifdef WIFITURNOFF + esp_wifi_stop(); // to save power usage and +#endif + + // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden + if (CFstatus.changedCameraSettings) + { + Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + CFstatus.changedCameraSettings = false; + } + + takePictureWithFlash(flash_duration); + +#ifdef WIFITURNOFF + esp_wifi_start(); +#endif + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash"); +#endif + + LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage); + + RemoveOldLogs(); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs"); +#endif + + psram_deinit_shared_memory_for_take_image_step(); + + return true; +} + +esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req) +{ + int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + return Camera.CaptureToHTTP(req, flash_duration); +} + +ImageData *ClassFlowTakeImage::SendRawImage(void) +{ + CImageBasis *zw = new CImageBasis("SendRawImage", rawImage); + ImageData *id; + int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); + Camera.CaptureToBasisImage(zw, flash_duration); + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + id = zw->writeToMemoryAsJPG(); + delete zw; + return id; +} + +time_t ClassFlowTakeImage::getTimeImageTaken(void) +{ + return TimeImageTaken; +} + +ClassFlowTakeImage::~ClassFlowTakeImage(void) +{ + delete rawImage; +} diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index 63eadac1e..f04a0c282 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -1,1653 +1,1590 @@ -#include "MainFlowControl.h" - -#include -#include -#include "string.h" -#include "esp_log.h" -#include - -#include -#include - -#include "../../include/defines.h" -#include "Helper.h" -#include "statusled.h" - -#include "esp_camera.h" -#include "time_sntp.h" -#include "ClassControllCamera.h" - -#include "ClassFlowControll.h" - -#include "ClassLogFile.h" -#include "server_GPIO.h" - -#include "server_file.h" - -#include "read_wlanini.h" -#include "connect_wlan.h" -#include "psram.h" - -// support IDF 5.x -#ifndef portTICK_RATE_MS -#define portTICK_RATE_MS portTICK_PERIOD_MS -#endif - -ClassFlowControll flowctrl; -camera_flow_config_temp_t CFstatus; - -TaskHandle_t xHandletask_autodoFlow = NULL; - -bool bTaskAutoFlowCreated = false; -bool flowisrunning = false; - -long auto_interval = 0; -bool autostartIsEnabled = false; - -int countRounds = 0; -bool isPlannedReboot = false; - -static const char *TAG = "MAINCTRL"; - -// #define DEBUG_DETAIL_ON - -void CheckIsPlannedReboot(void) -{ - FILE *pfile; - - if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) - { - // LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Initial boot or not a planned reboot"); - isPlannedReboot = false; - } - else - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot"); - DeleteFile("/sdcard/reboot.txt"); // Prevent Boot Loop!!! - isPlannedReboot = true; - } -} - -bool getIsPlannedReboot(void) -{ - return isPlannedReboot; -} - -int getCountFlowRounds(void) -{ - return countRounds; -} - -esp_err_t GetJPG(std::string _filename, httpd_req_t *req) -{ - return flowctrl.GetJPGStream(_filename, req); -} - -esp_err_t GetRawJPG(httpd_req_t *req) -{ - return flowctrl.SendRawJPG(req); -} - -bool isSetupModusActive(void) -{ - return flowctrl.getStatusSetupModus(); -} - -void DeleteMainFlowTask(void) -{ -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "DeleteMainFlowTask: xHandletask_autodoFlow: %ld", (long)xHandletask_autodoFlow); -#endif - - if (xHandletask_autodoFlow != NULL) - { - vTaskDelete(xHandletask_autodoFlow); - xHandletask_autodoFlow = NULL; - } - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Killed: xHandletask_autodoFlow"); -#endif -} - -void doInit(void) -{ -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Start flowctrl.InitFlow(config);"); -#endif - flowctrl.InitFlow(CONFIG_FILE); -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Finished flowctrl.InitFlow(config);"); -#endif - - /* GPIO handler has to be initialized before MQTT init to ensure proper topic subscription */ - gpio_handler_init(); - -#ifdef ENABLE_MQTT - flowctrl.StartMQTTService(); -#endif // ENABLE_MQTT -} - -bool doflow(void) -{ - std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); - ESP_LOGD(TAG, "doflow - start %s", zw_time.c_str()); - flowisrunning = true; - flowctrl.doFlow(zw_time); - flowisrunning = false; - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "doflow - end %s", zw_time.c_str()); -#endif - - return true; -} - -esp_err_t setCCstatusToCFstatus(void) -{ - CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; - CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; - - CFstatus.ImageQuality = CCstatus.ImageQuality; - CFstatus.ImageBrightness = CCstatus.ImageBrightness; - CFstatus.ImageContrast = CCstatus.ImageContrast; - CFstatus.ImageSaturation = CCstatus.ImageSaturation; - CFstatus.ImageSharpness = CCstatus.ImageSharpness; - CFstatus.ImageAutoSharpness = CCstatus.ImageAutoSharpness; - CFstatus.ImageWbMode = CCstatus.ImageWbMode; - CFstatus.ImageAwb = CCstatus.ImageAwb; - CFstatus.ImageAwbGain = CCstatus.ImageAwbGain; - CFstatus.ImageAec = CCstatus.ImageAec; - CFstatus.ImageAec2 = CCstatus.ImageAec2; - CFstatus.ImageAeLevel = CCstatus.ImageAeLevel; - CFstatus.ImageAecValue = CCstatus.ImageAecValue; - CFstatus.ImageAgc = CCstatus.ImageAgc; - CFstatus.ImageAgcGain = CCstatus.ImageAgcGain; - CFstatus.ImageBpc = CCstatus.ImageBpc; - CFstatus.ImageWpc = CCstatus.ImageWpc; - CFstatus.ImageRawGma = CCstatus.ImageRawGma; - CFstatus.ImageLenc = CCstatus.ImageLenc; - CFstatus.ImageSpecialEffect = CCstatus.ImageSpecialEffect; - CFstatus.ImageHmirror = CCstatus.ImageHmirror; - CFstatus.ImageVflip = CCstatus.ImageVflip; - CFstatus.ImageDcw = CCstatus.ImageDcw; - - CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; - - CFstatus.ImageZoomEnabled = CCstatus.ImageZoomEnabled; - CFstatus.ImageZoomMode = CCstatus.ImageZoomMode; - CFstatus.ImageZoomOffsetX = CCstatus.ImageZoomOffsetX; - CFstatus.ImageZoomOffsetY = CCstatus.ImageZoomOffsetY; - CFstatus.ImageZoomSize = CCstatus.ImageZoomSize; - - CFstatus.WaitBeforePicture = CCstatus.WaitBeforePicture; - - return ESP_OK; -} - -esp_err_t setCFstatusToCCstatus(void) -{ - CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; - CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; - - CCstatus.ImageQuality = CFstatus.ImageQuality; - CCstatus.ImageBrightness = CFstatus.ImageBrightness; - CCstatus.ImageContrast = CFstatus.ImageContrast; - CCstatus.ImageSaturation = CFstatus.ImageSaturation; - CCstatus.ImageSharpness = CFstatus.ImageSharpness; - CCstatus.ImageAutoSharpness = CFstatus.ImageAutoSharpness; - CCstatus.ImageWbMode = CFstatus.ImageWbMode; - CCstatus.ImageAwb = CFstatus.ImageAwb; - CCstatus.ImageAwbGain = CFstatus.ImageAwbGain; - CCstatus.ImageAec = CFstatus.ImageAec; - CCstatus.ImageAec2 = CFstatus.ImageAec2; - CCstatus.ImageAeLevel = CFstatus.ImageAeLevel; - CCstatus.ImageAecValue = CFstatus.ImageAecValue; - CCstatus.ImageAgc = CFstatus.ImageAgc; - CCstatus.ImageAgcGain = CFstatus.ImageAgcGain; - CCstatus.ImageBpc = CFstatus.ImageBpc; - CCstatus.ImageWpc = CFstatus.ImageWpc; - CCstatus.ImageRawGma = CFstatus.ImageRawGma; - CCstatus.ImageLenc = CFstatus.ImageLenc; - CCstatus.ImageSpecialEffect = CFstatus.ImageSpecialEffect; - CCstatus.ImageHmirror = CFstatus.ImageHmirror; - CCstatus.ImageVflip = CFstatus.ImageVflip; - CCstatus.ImageDcw = CFstatus.ImageDcw; - - CCstatus.ImageLedIntensity = CFstatus.ImageLedIntensity; - - CCstatus.ImageZoomEnabled = CFstatus.ImageZoomEnabled; - CCstatus.ImageZoomMode = CFstatus.ImageZoomMode; - CCstatus.ImageZoomOffsetX = CFstatus.ImageZoomOffsetX; - CCstatus.ImageZoomOffsetY = CFstatus.ImageZoomOffsetY; - CCstatus.ImageZoomSize = CFstatus.ImageZoomSize; - - CCstatus.WaitBeforePicture = CFstatus.WaitBeforePicture; - - return ESP_OK; -} - -esp_err_t setCFstatusToCam(void) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - s->set_framesize(s, CFstatus.ImageFrameSize); - s->set_gainceiling(s, CFstatus.ImageGainceiling); - - s->set_quality(s, CFstatus.ImageQuality); // 0 - 63 - - s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 - s->set_contrast(s, CFstatus.ImageContrast); // -2 to 2 - s->set_saturation(s, CFstatus.ImageSaturation); // -2 to 2 - // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 - Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); - - s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable - s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 - s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 - s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable - - s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable - s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 - - s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable - s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable - - s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable - - s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable - s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable - - s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable - - s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable - s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable - - // special_effect muß als Letztes gesetzt werden, sonst geht es nicht - s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) - - TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; - vTaskDelay(xDelay2); - - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - -esp_err_t handler_get_heap(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_get_heap - Start"); - ESP_LOGD(TAG, "handler_get_heap uri: %s", req->uri); -#endif - - std::string zw = "Heap info:
" + getESPHeapInfo(); - -#ifdef TASK_ANALYSIS_ON - char *pcTaskList = (char *)calloc_psram_heap(std::string(TAG) + "->pcTaskList", 1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - if (pcTaskList) - { - vTaskList(pcTaskList); - zw = zw + "

Task info:
Name | State | Prio | Lowest stacksize | Creation order | CPU (-1=NoAffinity)
" + std::string(pcTaskList) + "
"; - free_psram_heap(std::string(TAG) + "->pcTaskList", pcTaskList); - } - else - { - zw = zw + "

Task info:
ERROR - Allocation of TaskList buffer in PSRAM failed"; - } -#endif - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (zw.length() > 0) - { - httpd_resp_send(req, zw.c_str(), zw.length()); - } - else - { - httpd_resp_send(req, NULL, 0); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_get_heap - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_init(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_init - Start"); - ESP_LOGD(TAG, "handler_doinit uri: %s", req->uri); -#endif - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - const char *resp_str = "Init started
"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - - doInit(); - - resp_str = "Init done
"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_init - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_stream(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_stream - Start"); - ESP_LOGD(TAG, "handler_stream uri: %s", req->uri); -#endif - - char _query[50]; - char _value[10]; - bool flashlightOn = false; - - if (httpd_req_get_url_query_str(req, _query, 50) == ESP_OK) - { - // ESP_LOGD(TAG, "Query: %s", _query); - if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "flashlight is found%s", _value); -#endif - if (strlen(_value) > 0) - { - flashlightOn = true; - } - } - } - - Camera.CaptureToStream(req, flashlightOn); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_stream - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_flow_start(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_flow_start - Start"); -#endif - - ESP_LOGD(TAG, "handler_flow_start uri: %s", req->uri); - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (autostartIsEnabled) - { - xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by REST API /flow_start"); - const char *resp_str = "The flow is going to be started immediately or is already running"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - else - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by REST API, but flow is not active!"); - const char *resp_str = "WARNING: Flow start triggered by REST API, but flow is not active"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_flow_start - Done"); -#endif - - return ESP_OK; -} - -#ifdef ENABLE_MQTT -esp_err_t MQTTCtrlFlowStart(std::string _topic) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Start"); -#endif - - ESP_LOGD(TAG, "MQTTCtrlFlowStart: topic %s", _topic.c_str()); - - if (autostartIsEnabled) - { - xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by MQTT topic " + _topic); - } - else - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by MQTT topic " + _topic + ", but flow is not active!"); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Done"); -#endif - - return ESP_OK; -} -#endif // ENABLE_MQTT - -esp_err_t handler_json(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_json - Start"); -#endif - - ESP_LOGD(TAG, "handler_JSON uri: %s", req->uri); - - if (bTaskAutoFlowCreated) - { - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_set_type(req, "application/json"); - - std::string zw = flowctrl.getJSON(); - if (zw.length() > 0) - { - httpd_resp_send(req, zw.c_str(), zw.length()); - } - else - { - httpd_resp_send(req, NULL, 0); - } - } - else - { - httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /json not yet available!"); - return ESP_ERR_NOT_FOUND; - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_JSON - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_wasserzaehler(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler water counter - Start"); -#endif - - if (bTaskAutoFlowCreated) - { - bool _rawValue = false; - bool _noerror = false; - bool _all = false; - std::string _type = "value"; - string zw; - - ESP_LOGD(TAG, "handler water counter uri: %s", req->uri); - - char _query[100]; - char _size[10]; - - if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) - { - // ESP_LOGD(TAG, "Query: %s", _query); - if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "all is found%s", _size); -#endif - _all = true; - } - - if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "all is found: %s", _size); -#endif - _type = std::string(_size); - } - - if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "rawvalue is found: %s", _size); -#endif - _rawValue = true; - } - - if (httpd_query_key_value(_query, "noerror", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "noerror is found: %s", _size); -#endif - _noerror = true; - } - } - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (_all) - { - httpd_resp_set_type(req, "text/plain"); - ESP_LOGD(TAG, "TYPE: %s", _type.c_str()); - int _intype = READOUT_TYPE_VALUE; - - if (_type == "prevalue") - { - _intype = READOUT_TYPE_PREVALUE; - } - - if (_type == "raw") - { - _intype = READOUT_TYPE_RAWVALUE; - } - - if (_type == "error") - { - _intype = READOUT_TYPE_ERROR; - } - - zw = flowctrl.getReadoutAll(_intype); - ESP_LOGD(TAG, "ZW: %s", zw.c_str()); - - if (zw.length() > 0) - { - httpd_resp_send(req, zw.c_str(), zw.length()); - } - - return ESP_OK; - } - - std::string *status = flowctrl.getActStatus(); - string query = std::string(_query); - // ESP_LOGD(TAG, "Query: %s, query.c_str()); - - if (query.find("full") != std::string::npos) - { - string txt; - txt = ""; - - if ((countRounds <= 1) && (*status != std::string("Flow finished"))) - { - // First round not completed yet - txt += "

Please wait for the first round to complete!

Current state: " + *status + "

\n"; - } - else - { - txt += "

Value

"; - } - - httpd_resp_sendstr_chunk(req, txt.c_str()); - } - - zw = flowctrl.getReadout(_rawValue, _noerror, 0); - - if (zw.length() > 0) - { - httpd_resp_sendstr_chunk(req, zw.c_str()); - } - - if (query.find("full") != std::string::npos) - { - string txt, zw; - - if ((countRounds <= 1) && (*status != std::string("Flow finished"))) - { - // First round not completed yet - // Nothing to do - } - else - { - /* Digital ROIs */ - txt = ""; - txt += "

Recognized Digit ROIs (previous round)

\n"; - txt += "\n"; - - std::vector htmlinfodig; - htmlinfodig = flowctrl.GetAllDigital(); - - for (int i = 0; i < htmlinfodig.size(); ++i) - { - if (flowctrl.GetTypeDigital() == Digital) - { - if (htmlinfodig[i]->val >= 10) - { - zw = "NaN"; - } - else - { - zw = to_string((int)htmlinfodig[i]->val); - } - - txt += "\n"; - } - else - { - std::stringstream stream; - stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val; - zw = stream.str(); - - if (std::stod(zw) >= 10) - { - zw = "NaN"; - } - - txt += "\n"; - } - delete htmlinfodig[i]; - } - - htmlinfodig.clear(); - - txt += "

" + zw + "

filename + "\">

" + zw + "

filename + "\">

\n"; - httpd_resp_sendstr_chunk(req, txt.c_str()); - - /* Analog ROIs */ - txt = "

Recognized Analog ROIs (previous round)

\n"; - txt += "\n"; - - std::vector htmlinfoana; - htmlinfoana = flowctrl.GetAllAnalog(); - - for (int i = 0; i < htmlinfoana.size(); ++i) - { - std::stringstream stream; - stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val; - zw = stream.str(); - - if (std::stod(zw) >= 10) - { - zw = "NaN"; - } - - txt += "\n"; - delete htmlinfoana[i]; - } - - htmlinfoana.clear(); - - txt += "\n

" + zw + "

filename + "\">

\n"; - httpd_resp_sendstr_chunk(req, txt.c_str()); - - /* Full Image - * Only show it after the image got taken and aligned */ - txt = "

Aligned Image (current round)

\n"; - - if ((*status == std::string("Initialization")) || - (*status == std::string("Initialization (delayed)")) || - (*status == std::string("Take Image"))) - { - txt += "

Current state: " + *status + "

\n"; - } - else - { - txt += "\n"; - } - httpd_resp_sendstr_chunk(req, txt.c_str()); - } - } - - /* Respond with an empty chunk to signal HTTP response completion */ - httpd_resp_sendstr_chunk(req, NULL); - } - else - { - httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /value not available!"); - return ESP_ERR_NOT_FOUND; - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_wasserzaehler - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_editflow(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_editflow - Start"); -#endif - - ESP_LOGD(TAG, "handler_editflow uri: %s", req->uri); - - char _query[200]; - char _valuechar[30]; - string _task; - - if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) - { - if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "task is found: %s", _valuechar); -#endif - _task = string(_valuechar); - } - } - - if (_task.compare("namenumbers") == 0) - { - ESP_LOGD(TAG, "Get NUMBER list"); - return get_numbers_file_handler(req); - } - - if (_task.compare("data") == 0) - { - ESP_LOGD(TAG, "Get data list"); - return get_data_file_handler(req); - } - - if (_task.compare("tflite") == 0) - { - ESP_LOGD(TAG, "Get tflite list"); - return get_tflite_file_handler(req); - } - - if (_task.compare("copy") == 0) - { - string in, out, zw; - - httpd_query_key_value(_query, "in", _valuechar, 30); - in = string(_valuechar); - httpd_query_key_value(_query, "out", _valuechar, 30); - out = string(_valuechar); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "in: %s", in.c_str()); - ESP_LOGD(TAG, "out: %s", out.c_str()); -#endif - - in = "/sdcard" + in; - out = "/sdcard" + out; - - CopyFile(in, out); - zw = "Copy Done"; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), zw.length()); - } - - if (_task.compare("cutref") == 0) - { - string in, out, zw; - int x, y, dx, dy; - bool enhance = false; - - httpd_query_key_value(_query, "in", _valuechar, 30); - in = string(_valuechar); - - httpd_query_key_value(_query, "out", _valuechar, 30); - out = string(_valuechar); - - httpd_query_key_value(_query, "x", _valuechar, 30); - string _x = string(_valuechar); - x = stoi(_x); - - httpd_query_key_value(_query, "y", _valuechar, 30); - string _y = string(_valuechar); - y = stoi(_y); - - httpd_query_key_value(_query, "dx", _valuechar, 30); - string _dx = string(_valuechar); - dx = stoi(_dx); - - httpd_query_key_value(_query, "dy", _valuechar, 30); - string _dy = string(_valuechar); - dy = stoi(_dy); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "in: %s", in.c_str()); - ESP_LOGD(TAG, "out: %s", out.c_str()); - ESP_LOGD(TAG, "x: %s", _x.c_str()); - ESP_LOGD(TAG, "y: %s", _y.c_str()); - ESP_LOGD(TAG, "dx: %s", _dx.c_str()); - ESP_LOGD(TAG, "dy: %s", _dy.c_str()); -#endif - - if (httpd_query_key_value(_query, "enhance", _valuechar, 10) == ESP_OK) - { - string _enhance = string(_valuechar); - - if (_enhance.compare("true") == 0) - { - enhance = true; - } - } - - in = "/sdcard" + in; - out = "/sdcard" + out; - - string out2 = out.substr(0, out.length() - 4) + "_org.jpg"; - - if ((flowctrl.SetupModeActive || (*flowctrl.getActStatus() == std::string("Flow finished"))) && psram_init_shared_memory_for_take_image_step()) - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Taking image for Alignment Mark Update..."); - - CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in); - caic->CutAndSave(out2, x, y, dx, dy); - delete caic; - - CImageBasis *cim = new CImageBasis("cutref", out2); - - if (enhance) - { - cim->Contrast(90); - } - - cim->SaveToFile(out); - delete cim; - - psram_deinit_shared_memory_for_take_image_step(); - zw = "CutImage Done"; - } - else - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Taking image for Alignment Mark not possible while device") + " is busy with a round (Current State: '" + *flowctrl.getActStatus() + "')!"); - zw = "Device Busy"; - } - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), zw.length()); - } - - // wird beim Erstellen eines neuen Referenzbildes aufgerufen - std::string *sys_status = flowctrl.getActStatus(); - - if ((sys_status->c_str() != std::string("Take Image")) && (sys_status->c_str() != std::string("Aligning"))) - { - if ((_task.compare("test_take") == 0) || (_task.compare("cam_settings") == 0)) - { - std::string _host = ""; - - // laden der aktuellen Kameraeinstellungen(CCstatus) in den Zwischenspeicher(CFstatus) - setCCstatusToCFstatus(); // CCstatus >>> CFstatus - - if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) - { - _host = std::string(_valuechar); - } - - if (httpd_query_key_value(_query, "waitb", _valuechar, 30) == ESP_OK) - { - int _waitb = std::stoi(_valuechar); - if (_waitb != 0) - { - CFstatus.WaitBeforePicture = _waitb; - } - } - - if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) - { - int _qual = std::stoi(_valuechar); - if ((_qual >= 0) && (_qual <= 63)) - { - CFstatus.ImageQuality = _qual; - } - } - - if (httpd_query_key_value(_query, "bri", _valuechar, 30) == ESP_OK) - { - int _bri = std::stoi(_valuechar); - if ((_bri >= -2) && (_bri <= 2)) - { - CFstatus.ImageBrightness = _bri; - } - } - - if (httpd_query_key_value(_query, "con", _valuechar, 30) == ESP_OK) - { - int _con = std::stoi(_valuechar); - if ((_con >= -2) && (_con <= 2)) - { - CFstatus.ImageContrast = _con; - } - } - - if (httpd_query_key_value(_query, "sat", _valuechar, 30) == ESP_OK) - { - int _sat = std::stoi(_valuechar); - if ((_sat >= -2) && (_sat <= 2)) - { - CFstatus.ImageSaturation = _sat; - } - } - - if (httpd_query_key_value(_query, "shp", _valuechar, 30) == ESP_OK) - { - int _shp = std::stoi(_valuechar); - if ((_shp >= -2) && (_shp <= 2)) - { - CFstatus.ImageSharpness = _shp; - } - } - - if (httpd_query_key_value(_query, "ashp", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageAutoSharpness = 1; - } - else - { - CFstatus.ImageAutoSharpness = 0; - } - } - - if (httpd_query_key_value(_query, "spe", _valuechar, 30) == ESP_OK) - { - int _spe = std::stoi(_valuechar); - if ((_spe >= 0) && (_spe <= 6)) - { - CFstatus.ImageSpecialEffect = _spe; - } - } - - if (httpd_query_key_value(_query, "wbm", _valuechar, 30) == ESP_OK) - { - int _wbm = std::stoi(_valuechar); - if ((_wbm >= 0) && (_wbm <= 4)) - { - CFstatus.ImageWbMode = _wbm; - } - } - - if (httpd_query_key_value(_query, "awb", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageAwb = 1; - } - else - { - CFstatus.ImageAwb = 0; - } - } - - if (httpd_query_key_value(_query, "awbg", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageAwbGain = 1; - } - else - { - CFstatus.ImageAwbGain = 0; - } - } - - if (httpd_query_key_value(_query, "aec", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageAec = 1; - } - else - { - CFstatus.ImageAec = 0; - } - } - - if (httpd_query_key_value(_query, "aec2", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageAec2 = 1; - } - else - { - CFstatus.ImageAec2 = 0; - } - } - - if (httpd_query_key_value(_query, "ael", _valuechar, 30) == ESP_OK) - { - int _ael = std::stoi(_valuechar); - if ((_ael >= -2) && (_ael <= 2)) - { - CFstatus.ImageAeLevel = _ael; - } - } - - if (httpd_query_key_value(_query, "aecv", _valuechar, 30) == ESP_OK) - { - int _aecv = std::stoi(_valuechar); - if ((_aecv >= 0) && (_aecv <= 1200)) - { - CFstatus.ImageAecValue = _aecv; - } - } - - if (httpd_query_key_value(_query, "agc", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageAgc = 1; - } - else - { - CFstatus.ImageAgc = 0; - } - } - - if (httpd_query_key_value(_query, "agcg", _valuechar, 30) == ESP_OK) - { - int _agcg = std::stoi(_valuechar); - if ((_agcg >= 0) && (_agcg <= 30)) - { - CFstatus.ImageAgcGain = _agcg; - } - } - - if (httpd_query_key_value(_query, "bpc", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageBpc = 1; - } - else - { - CFstatus.ImageBpc = 0; - } - } - - if (httpd_query_key_value(_query, "wpc", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageWpc = 1; - } - else - { - CFstatus.ImageWpc = 0; - } - } - - if (httpd_query_key_value(_query, "rgma", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageRawGma = 1; - } - else - { - CFstatus.ImageRawGma = 0; - } - } - - if (httpd_query_key_value(_query, "lenc", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageLenc = 1; - } - else - { - CFstatus.ImageLenc = 0; - } - } - - if (httpd_query_key_value(_query, "mirror", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageHmirror = 1; - } - else - { - CFstatus.ImageHmirror = 0; - } - } - - if (httpd_query_key_value(_query, "flip", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageVflip = 1; - } - else - { - CFstatus.ImageVflip = 0; - } - } - - if (httpd_query_key_value(_query, "dcw", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageDcw = 1; - } - else - { - CFstatus.ImageDcw = 0; - } - } - - if (httpd_query_key_value(_query, "zoom", _valuechar, 30) == ESP_OK) - { - if (std::stoi(_valuechar) != 0) - { - CFstatus.ImageZoomEnabled = 1; - } - else - { - CFstatus.ImageZoomEnabled = 0; - } - } - - if (httpd_query_key_value(_query, "zoomx", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageZoomOffsetX = std::stoi(_valuechar); - } - - if (httpd_query_key_value(_query, "zoomy", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageZoomOffsetY = std::stoi(_valuechar); - } - - if (httpd_query_key_value(_query, "zooms", _valuechar, 30) == ESP_OK) - { - int _ImageZoomSize = std::stoi(_valuechar); - if (_ImageZoomSize >= 0) - { - CFstatus.ImageZoomSize = _ImageZoomSize; - } - } - - if (httpd_query_key_value(_query, "ledi", _valuechar, 30) == ESP_OK) - { - float _ImageLedIntensity = std::stof(_valuechar); - Camera.SetLEDIntensity(_ImageLedIntensity); - CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; - } - - if (_task.compare("cam_settings") == 0) - { - // wird aufgerufen, wenn das Referenzbild + Kameraeinstellungen gespeichert wurden - setCFstatusToCCstatus(); // CFstatus >>> CCstatus - - // Kameraeinstellungen wurden verädert - CFstatus.changedCameraSettings = true; - - ESP_LOGD(TAG, "Cam Settings set"); - std::string _zw = "CamSettingsSet"; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, _zw.c_str(), _zw.length()); - } - else - { - // wird aufgerufen, wenn ein neues Referenzbild erstellt oder aktualisiert wurde - // CFstatus >>> Kamera - setCFstatusToCam(); - - Camera.SetQualityZoomSize(CFstatus.ImageQuality, CFstatus.ImageFrameSize, CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); - // Camera.SetZoomSize(CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); - - // Kameraeinstellungen wurden verädert - CFstatus.changedCameraSettings = true; - - ESP_LOGD(TAG, "test_take - vor TakeImage"); - std::string image_temp = flowctrl.doSingleStep("[TakeImage]", _host); - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, image_temp.c_str(), image_temp.length()); - } - } - - if (_task.compare("test_align") == 0) - { - std::string _host = ""; - - if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) - { - _host = std::string(_valuechar); - } - - std::string zw = flowctrl.doSingleStep("[Alignment]", _host); - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), zw.length()); - } - } - else - { - std::string _zw = "DeviceIsBusy"; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, _zw.c_str(), _zw.length()); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_editflow - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_statusflow(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_statusflow - Start"); -#endif - - const char *resp_str; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (bTaskAutoFlowCreated) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "handler_statusflow: %s", req->uri); -#endif - - string *zw = flowctrl.getActStatusWithTime(); - resp_str = zw->c_str(); - - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - else - { - resp_str = "Flow task not yet created"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_statusflow - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_cputemp(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_cputemp - Start"); -#endif - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, std::to_string((int)temperatureRead()).c_str(), HTTPD_RESP_USE_STRLEN); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_cputemp - End"); -#endif - - return ESP_OK; -} - -esp_err_t handler_rssi(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_rssi - Start"); -#endif - - if (getWIFIisConnected()) - { - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, std::to_string(get_WIFI_RSSI()).c_str(), HTTPD_RESP_USE_STRLEN); - } - else - { - httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "WIFI not (yet) connected: REST API /rssi not available!"); - return ESP_ERR_NOT_FOUND; - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_rssi - End"); -#endif - - return ESP_OK; -} - -esp_err_t handler_uptime(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_uptime - Start"); -#endif - - std::string formatedUptime = getFormatedUptime(false); - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, formatedUptime.c_str(), formatedUptime.length()); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_uptime - End"); -#endif - - return ESP_OK; -} - -esp_err_t handler_prevalue(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_prevalue - Start"); - ESP_LOGD(TAG, "handler_prevalue: %s", req->uri); -#endif - - // Default usage message when handler gets called without any parameter - const std::string RESTUsageInfo = - "00: Handler usage:
" - "- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main
" - "- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678
" - "NOTE:
" - "value >= 0.0: Set PreValue to provided value
" - "value < 0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)"; - - // Default return error message when no return is programmed - std::string sReturnMessage = "E90: Uninitialized"; - - char _query[100]; - char _numbersname[50] = "default"; - char _value[20] = ""; - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Query: %s", _query); -#endif - - if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) - { - // If request is incomplete - sReturnMessage = "E91: Query parameter incomplete or not valid!
" - "Call /setPreValue to show REST API usage info and/or check documentation"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - - if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Value: %s", _value); -#endif - } - } - else - { - // if no parameter is provided, print handler usage - httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length()); - return ESP_OK; - } - - if (strlen(_value) == 0) - { - // If no value is povided --> return actual PreValue - sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); - - if (sReturnMessage.empty()) - { - sReturnMessage = "E92: Numbers name not found"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - } - else - { - // New value is positive: Set PreValue to provided value and return value - // New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) + ", value: " + std::string(_value)); - - if (!flowctrl.UpdatePrevalue(_value, _numbersname, true)) - { - sReturnMessage = "E93: Update request rejected. Please check device logs for more details"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - - sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); - - if (sReturnMessage.empty()) - { - sReturnMessage = "E94: Numbers name not found"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - } - - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_prevalue - End"); -#endif - - return ESP_OK; -} - -void task_autodoFlow(void *pvParameter) -{ - int64_t fr_start, fr_delta_ms; - - bTaskAutoFlowCreated = true; - - if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC)) - { - flowctrl.setActStatus("Initialization (delayed)"); - // #ifdef ENABLE_MQTT - // MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later - // #endif //ENABLE_MQTT - vTaskDelay(60 * 5000 / portTICK_PERIOD_MS); // Wait 5 minutes to give time to do an OTA update or fetch the log - } - - ESP_LOGD(TAG, "task_autodoFlow: start"); - doInit(); - - flowctrl.setAutoStartInterval(auto_interval); - autostartIsEnabled = flowctrl.getIsAutoStart(); - - if (isSetupModusActive()) - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "We are in Setup Mode -> Not starting Auto Flow!"); - autostartIsEnabled = false; - // 15.7.0 Setup Wizard cannot take a Reference Picture #2953 - // std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); - // flowctrl.doFlowTakeImageOnly(zw_time); - } - - if (autostartIsEnabled) - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Starting Flow..."); - } - else - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Autostart is not enabled -> Not starting Flow"); - } - - while (autostartIsEnabled) - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs - time_t roundStartTime = getUpTime(); - - std::string _zw = "Round #" + std::to_string(++countRounds) + " started"; - LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw); - - fr_start = esp_timer_get_time(); - - if (flowisrunning) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Autoflow: doFlow is already running!"); -#endif - } - else - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Autoflow: doFlow is started"); -#endif - flowisrunning = true; - doflow(); -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Remove older log files"); -#endif - LogFile.RemoveOldLogFile(); - LogFile.RemoveOldDataLog(); - } - - // Round finished -> Logfile - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) + " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)"); - - // CPU Temp -> Logfile - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C"); - - // WIFI Signal Strength (RSSI) -> Logfile - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm"); - - // Check if time is synchronized (if NTP is configured) - if (getUseNtp() && !getTimeIsSet()) - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time server is configured, but time is not yet set!"); - StatusLED(TIME_CHECK, 1, false); - } - -#if (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES) - wifiRoamingQuery(); -#endif - -// Scan channels and check if an AP with better RSSI is available, then disconnect and try to reconnect to AP with better RSSI -// NOTE: Keep this direct before the following task delay, because scan is done in blocking mode and this takes ca. 1,5 - 2s. -#ifdef WLAN_USE_ROAMING_BY_SCANNING - wifiRoamByScanning(); -#endif - - fr_delta_ms = (esp_timer_get_time() - fr_start) / 1000; - - if (auto_interval > fr_delta_ms) - { - const TickType_t xDelay = (auto_interval - fr_delta_ms) / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "Autoflow: sleep for: %ldms", (long)xDelay); - vTaskDelay(xDelay); - } - } - - while (1) - { - // Keep flow task running to handle necessary sub tasks like reboot handler, etc.. - vTaskDelay(2000 / portTICK_PERIOD_MS); - } - - vTaskDelete(NULL); // Delete this task if it exits from the loop above - xHandletask_autodoFlow = NULL; - - ESP_LOGD(TAG, "task_autodoFlow: end"); -} - -void InitializeFlowTask(void) -{ - BaseType_t xReturned; - - ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); - - uint32_t stackSize = 16 * 1024; - xReturned = xTaskCreatePinnedToCore(&task_autodoFlow, "task_autodoFlow", stackSize, NULL, tskIDLE_PRIORITY + 2, &xHandletask_autodoFlow, 0); - - if (xReturned != pdPASS) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Creation task_autodoFlow failed. Requested stack size:" + std::to_string(stackSize)); - LogFile.WriteHeapInfo("Creation task_autodoFlow failed"); - } - - ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); -} - -void register_server_main_flow_task_uri(httpd_handle_t server) -{ - ESP_LOGI(TAG, "server_main_flow_task - Registering URI handlers"); - - httpd_uri_t camuri = {}; - camuri.method = HTTP_GET; - - camuri.uri = "/doinit"; - camuri.handler = handler_init; - camuri.user_ctx = (void *)"Light On"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/setPreValue" - camuri.uri = "/setPreValue.html"; - camuri.handler = handler_prevalue; - camuri.user_ctx = (void *)"Prevalue"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/setPreValue"; - camuri.handler = handler_prevalue; - camuri.user_ctx = (void *)"Prevalue"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/flow_start"; - camuri.handler = handler_flow_start; - camuri.user_ctx = (void *)"Flow Start"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/statusflow.html"; - camuri.handler = handler_statusflow; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/statusflow"; - camuri.handler = handler_statusflow; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/cpu_temperature" - camuri.uri = "/cputemp.html"; - camuri.handler = handler_cputemp; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/cpu_temperature"; - camuri.handler = handler_cputemp; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/rssi" - camuri.uri = "/rssi.html"; - camuri.handler = handler_rssi; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/rssi"; - camuri.handler = handler_rssi; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/uptime"; - camuri.handler = handler_uptime; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/editflow"; - camuri.handler = handler_editflow; - camuri.user_ctx = (void *)"EditFlow"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/value" - camuri.uri = "/value.html"; - camuri.handler = handler_wasserzaehler; - camuri.user_ctx = (void *)"Value"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/value"; - camuri.handler = handler_wasserzaehler; - camuri.user_ctx = (void *)"Value"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/value" - camuri.uri = "/wasserzaehler.html"; - camuri.handler = handler_wasserzaehler; - camuri.user_ctx = (void *)"Wasserzaehler"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/json"; - camuri.handler = handler_json; - camuri.user_ctx = (void *)"JSON"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/heap"; - camuri.handler = handler_get_heap; - camuri.user_ctx = (void *)"Heap"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/stream"; - camuri.handler = handler_stream; - camuri.user_ctx = (void *)"stream"; - httpd_register_uri_handler(server, &camuri); -} +#include "MainFlowControl.h" + +#include +#include +#include "string.h" +#include "esp_log.h" +#include + +#include +#include + +#include "../../include/defines.h" +#include "Helper.h" +#include "statusled.h" + +#include "esp_camera.h" +#include "time_sntp.h" +#include "ClassControllCamera.h" + +#include "ClassFlowControll.h" + +#include "ClassLogFile.h" +#include "server_GPIO.h" + +#include "server_file.h" + +#include "read_wlanini.h" +#include "connect_wlan.h" +#include "psram.h" + +// support IDF 5.x +#ifndef portTICK_RATE_MS +#define portTICK_RATE_MS portTICK_PERIOD_MS +#endif + +ClassFlowControll flowctrl; +camera_flow_config_temp_t CFstatus; + +TaskHandle_t xHandletask_autodoFlow = NULL; + +bool bTaskAutoFlowCreated = false; +bool flowisrunning = false; + +long auto_interval = 0; +bool autostartIsEnabled = false; + +int countRounds = 0; +bool isPlannedReboot = false; + +static const char *TAG = "MAINCTRL"; + +// #define DEBUG_DETAIL_ON + +void CheckIsPlannedReboot(void) +{ + FILE *pfile; + + if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) + { + // LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Initial boot or not a planned reboot"); + isPlannedReboot = false; + } + else + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot"); + DeleteFile("/sdcard/reboot.txt"); // Prevent Boot Loop!!! + isPlannedReboot = true; + } +} + +bool getIsPlannedReboot(void) +{ + return isPlannedReboot; +} + +int getCountFlowRounds(void) +{ + return countRounds; +} + +esp_err_t GetJPG(std::string _filename, httpd_req_t *req) +{ + return flowctrl.GetJPGStream(_filename, req); +} + +esp_err_t GetRawJPG(httpd_req_t *req) +{ + return flowctrl.SendRawJPG(req); +} + +bool isSetupModusActive(void) +{ + return flowctrl.getStatusSetupModus(); +} + +void DeleteMainFlowTask(void) +{ +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "DeleteMainFlowTask: xHandletask_autodoFlow: %ld", (long)xHandletask_autodoFlow); +#endif + + if (xHandletask_autodoFlow != NULL) + { + vTaskDelete(xHandletask_autodoFlow); + xHandletask_autodoFlow = NULL; + } + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Killed: xHandletask_autodoFlow"); +#endif +} + +void doInit(void) +{ +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Start flowctrl.InitFlow(config);"); +#endif + flowctrl.InitFlow(CONFIG_FILE); +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Finished flowctrl.InitFlow(config);"); +#endif + + /* GPIO handler has to be initialized before MQTT init to ensure proper topic subscription */ + gpio_handler_init(); + +#ifdef ENABLE_MQTT + flowctrl.StartMQTTService(); +#endif // ENABLE_MQTT +} + +bool doflow(void) +{ + std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); + ESP_LOGD(TAG, "doflow - start %s", zw_time.c_str()); + flowisrunning = true; + flowctrl.doFlow(zw_time); + flowisrunning = false; + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "doflow - end %s", zw_time.c_str()); +#endif + + return true; +} + +esp_err_t setCCstatusToCFstatus(void) +{ + CFstatus.CamSensor_id = CCstatus.CamSensor_id; + + CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; + CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; + + CFstatus.ImageQuality = CCstatus.ImageQuality; + CFstatus.ImageBrightness = CCstatus.ImageBrightness; + CFstatus.ImageContrast = CCstatus.ImageContrast; + CFstatus.ImageSaturation = CCstatus.ImageSaturation; + CFstatus.ImageSharpness = CCstatus.ImageSharpness; + CFstatus.ImageAutoSharpness = CCstatus.ImageAutoSharpness; + CFstatus.ImageWbMode = CCstatus.ImageWbMode; + CFstatus.ImageAwb = CCstatus.ImageAwb; + CFstatus.ImageAwbGain = CCstatus.ImageAwbGain; + CFstatus.ImageAec = CCstatus.ImageAec; + CFstatus.ImageAec2 = CCstatus.ImageAec2; + CFstatus.ImageAeLevel = CCstatus.ImageAeLevel; + CFstatus.ImageAecValue = CCstatus.ImageAecValue; + CFstatus.ImageAgc = CCstatus.ImageAgc; + CFstatus.ImageAgcGain = CCstatus.ImageAgcGain; + CFstatus.ImageBpc = CCstatus.ImageBpc; + CFstatus.ImageWpc = CCstatus.ImageWpc; + CFstatus.ImageRawGma = CCstatus.ImageRawGma; + CFstatus.ImageLenc = CCstatus.ImageLenc; + CFstatus.ImageSpecialEffect = CCstatus.ImageSpecialEffect; + CFstatus.ImageHmirror = CCstatus.ImageHmirror; + CFstatus.ImageVflip = CCstatus.ImageVflip; + CFstatus.ImageDcw = CCstatus.ImageDcw; + CFstatus.ImageDenoiseLevel = CCstatus.ImageDenoiseLevel; + + CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; + + CFstatus.ImageZoomEnabled = CCstatus.ImageZoomEnabled; + CFstatus.ImageZoomOffsetX = CCstatus.ImageZoomOffsetX; + CFstatus.ImageZoomOffsetY = CCstatus.ImageZoomOffsetY; + CFstatus.ImageZoomSize = CCstatus.ImageZoomSize; + + CFstatus.WaitBeforePicture = CCstatus.WaitBeforePicture; + + return ESP_OK; +} + +esp_err_t setCFstatusToCCstatus(void) +{ + // CCstatus.CamSensor_id = CFstatus.CamSensor_id; + + CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; + CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; + + CCstatus.ImageQuality = CFstatus.ImageQuality; + CCstatus.ImageBrightness = CFstatus.ImageBrightness; + CCstatus.ImageContrast = CFstatus.ImageContrast; + CCstatus.ImageSaturation = CFstatus.ImageSaturation; + CCstatus.ImageSharpness = CFstatus.ImageSharpness; + CCstatus.ImageAutoSharpness = CFstatus.ImageAutoSharpness; + CCstatus.ImageWbMode = CFstatus.ImageWbMode; + CCstatus.ImageAwb = CFstatus.ImageAwb; + CCstatus.ImageAwbGain = CFstatus.ImageAwbGain; + CCstatus.ImageAec = CFstatus.ImageAec; + CCstatus.ImageAec2 = CFstatus.ImageAec2; + CCstatus.ImageAeLevel = CFstatus.ImageAeLevel; + CCstatus.ImageAecValue = CFstatus.ImageAecValue; + CCstatus.ImageAgc = CFstatus.ImageAgc; + CCstatus.ImageAgcGain = CFstatus.ImageAgcGain; + CCstatus.ImageBpc = CFstatus.ImageBpc; + CCstatus.ImageWpc = CFstatus.ImageWpc; + CCstatus.ImageRawGma = CFstatus.ImageRawGma; + CCstatus.ImageLenc = CFstatus.ImageLenc; + CCstatus.ImageSpecialEffect = CFstatus.ImageSpecialEffect; + CCstatus.ImageHmirror = CFstatus.ImageHmirror; + CCstatus.ImageVflip = CFstatus.ImageVflip; + CCstatus.ImageDcw = CFstatus.ImageDcw; + CCstatus.ImageDenoiseLevel = CFstatus.ImageDenoiseLevel; + + CCstatus.ImageLedIntensity = CFstatus.ImageLedIntensity; + + CCstatus.ImageZoomEnabled = CFstatus.ImageZoomEnabled; + CCstatus.ImageZoomOffsetX = CFstatus.ImageZoomOffsetX; + CCstatus.ImageZoomOffsetY = CFstatus.ImageZoomOffsetY; + CCstatus.ImageZoomSize = CFstatus.ImageZoomSize; + + CCstatus.WaitBeforePicture = CFstatus.WaitBeforePicture; + + return ESP_OK; +} + +esp_err_t setCFstatusToCam(void) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + s->set_framesize(s, CFstatus.ImageFrameSize); + s->set_gainceiling(s, CFstatus.ImageGainceiling); + + s->set_quality(s, CFstatus.ImageQuality); // 0 - 63 + + s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 + s->set_contrast(s, CFstatus.ImageContrast); // -2 to 2 + s->set_saturation(s, CFstatus.ImageSaturation); // -2 to 2 + // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 + Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); + + s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable + s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 + s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 + s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable + + s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable + s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 + + s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable + s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable + + s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable + s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable + + s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable + s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable + + s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable + + s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable + s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable + + s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + // special_effect muß als Letztes gesetzt werden, sonst geht es nicht + s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + + TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; + vTaskDelay(xDelay2); + + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + +esp_err_t handler_get_heap(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_get_heap - Start"); + ESP_LOGD(TAG, "handler_get_heap uri: %s", req->uri); +#endif + + std::string zw = "Heap info:
" + getESPHeapInfo(); + +#ifdef TASK_ANALYSIS_ON + char *pcTaskList = (char *)calloc_psram_heap(std::string(TAG) + "->pcTaskList", 1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + if (pcTaskList) + { + vTaskList(pcTaskList); + zw = zw + "

Task info:
Name | State | Prio | Lowest stacksize | Creation order | CPU (-1=NoAffinity)
" + std::string(pcTaskList) + "
"; + free_psram_heap(std::string(TAG) + "->pcTaskList", pcTaskList); + } + else + { + zw = zw + "

Task info:
ERROR - Allocation of TaskList buffer in PSRAM failed"; + } +#endif + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (zw.length() > 0) + { + httpd_resp_send(req, zw.c_str(), zw.length()); + } + else + { + httpd_resp_send(req, NULL, 0); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_get_heap - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_init(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_init - Start"); + ESP_LOGD(TAG, "handler_doinit uri: %s", req->uri); +#endif + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + const char *resp_str = "Init started
"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + + doInit(); + + resp_str = "Init done
"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_init - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_stream(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_stream - Start"); + ESP_LOGD(TAG, "handler_stream uri: %s", req->uri); +#endif + + char _query[50]; + char _value[10]; + bool flashlightOn = false; + + if (httpd_req_get_url_query_str(req, _query, 50) == ESP_OK) + { + // ESP_LOGD(TAG, "Query: %s", _query); + if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "flashlight is found%s", _value); +#endif + if (strlen(_value) > 0) + { + flashlightOn = true; + } + } + } + + Camera.CaptureToStream(req, flashlightOn); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_stream - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_flow_start(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_flow_start - Start"); +#endif + + ESP_LOGD(TAG, "handler_flow_start uri: %s", req->uri); + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (autostartIsEnabled) + { + xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by REST API /flow_start"); + const char *resp_str = "The flow is going to be started immediately or is already running"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + else + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by REST API, but flow is not active!"); + const char *resp_str = "WARNING: Flow start triggered by REST API, but flow is not active"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_flow_start - Done"); +#endif + + return ESP_OK; +} + +#ifdef ENABLE_MQTT +esp_err_t MQTTCtrlFlowStart(std::string _topic) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Start"); +#endif + + ESP_LOGD(TAG, "MQTTCtrlFlowStart: topic %s", _topic.c_str()); + + if (autostartIsEnabled) + { + xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by MQTT topic " + _topic); + } + else + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by MQTT topic " + _topic + ", but flow is not active!"); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Done"); +#endif + + return ESP_OK; +} +#endif // ENABLE_MQTT + +esp_err_t handler_json(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_json - Start"); +#endif + + ESP_LOGD(TAG, "handler_JSON uri: %s", req->uri); + + if (bTaskAutoFlowCreated) + { + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_type(req, "application/json"); + + std::string zw = flowctrl.getJSON(); + if (zw.length() > 0) + { + httpd_resp_send(req, zw.c_str(), zw.length()); + } + else + { + httpd_resp_send(req, NULL, 0); + } + } + else + { + httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /json not yet available!"); + return ESP_ERR_NOT_FOUND; + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_JSON - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_wasserzaehler(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler water counter - Start"); +#endif + + if (bTaskAutoFlowCreated) + { + bool _rawValue = false; + bool _noerror = false; + bool _all = false; + std::string _type = "value"; + string zw; + + ESP_LOGD(TAG, "handler water counter uri: %s", req->uri); + + char _query[100]; + char _size[10]; + + if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) + { + // ESP_LOGD(TAG, "Query: %s", _query); + if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "all is found%s", _size); +#endif + _all = true; + } + + if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "all is found: %s", _size); +#endif + _type = std::string(_size); + } + + if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "rawvalue is found: %s", _size); +#endif + _rawValue = true; + } + + if (httpd_query_key_value(_query, "noerror", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "noerror is found: %s", _size); +#endif + _noerror = true; + } + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (_all) + { + httpd_resp_set_type(req, "text/plain"); + ESP_LOGD(TAG, "TYPE: %s", _type.c_str()); + int _intype = READOUT_TYPE_VALUE; + + if (_type == "prevalue") + { + _intype = READOUT_TYPE_PREVALUE; + } + + if (_type == "raw") + { + _intype = READOUT_TYPE_RAWVALUE; + } + + if (_type == "error") + { + _intype = READOUT_TYPE_ERROR; + } + + zw = flowctrl.getReadoutAll(_intype); + ESP_LOGD(TAG, "ZW: %s", zw.c_str()); + + if (zw.length() > 0) + { + httpd_resp_send(req, zw.c_str(), zw.length()); + } + + return ESP_OK; + } + + std::string *status = flowctrl.getActStatus(); + string query = std::string(_query); + // ESP_LOGD(TAG, "Query: %s, query.c_str()); + + if (query.find("full") != std::string::npos) + { + string txt; + txt = ""; + + if ((countRounds <= 1) && (*status != std::string("Flow finished"))) + { + // First round not completed yet + txt += "

Please wait for the first round to complete!

Current state: " + *status + "

\n"; + } + else + { + txt += "

Value

"; + } + + httpd_resp_sendstr_chunk(req, txt.c_str()); + } + + zw = flowctrl.getReadout(_rawValue, _noerror, 0); + + if (zw.length() > 0) + { + httpd_resp_sendstr_chunk(req, zw.c_str()); + } + + if (query.find("full") != std::string::npos) + { + string txt, zw; + + if ((countRounds <= 1) && (*status != std::string("Flow finished"))) + { + // First round not completed yet + // Nothing to do + } + else + { + /* Digital ROIs */ + txt = ""; + txt += "

Recognized Digit ROIs (previous round)

\n"; + txt += "\n"; + + std::vector htmlinfodig; + htmlinfodig = flowctrl.GetAllDigital(); + + for (int i = 0; i < htmlinfodig.size(); ++i) + { + if (flowctrl.GetTypeDigital() == Digital) + { + if (htmlinfodig[i]->val >= 10) + { + zw = "NaN"; + } + else + { + zw = to_string((int)htmlinfodig[i]->val); + } + + txt += "\n"; + } + else + { + std::stringstream stream; + stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val; + zw = stream.str(); + + if (std::stod(zw) >= 10) + { + zw = "NaN"; + } + + txt += "\n"; + } + delete htmlinfodig[i]; + } + + htmlinfodig.clear(); + + txt += "

" + zw + "

filename + "\">

" + zw + "

filename + "\">

\n"; + httpd_resp_sendstr_chunk(req, txt.c_str()); + + /* Analog ROIs */ + txt = "

Recognized Analog ROIs (previous round)

\n"; + txt += "\n"; + + std::vector htmlinfoana; + htmlinfoana = flowctrl.GetAllAnalog(); + + for (int i = 0; i < htmlinfoana.size(); ++i) + { + std::stringstream stream; + stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val; + zw = stream.str(); + + if (std::stod(zw) >= 10) + { + zw = "NaN"; + } + + txt += "\n"; + delete htmlinfoana[i]; + } + + htmlinfoana.clear(); + + txt += "\n

" + zw + "

filename + "\">

\n"; + httpd_resp_sendstr_chunk(req, txt.c_str()); + + /* Full Image + * Only show it after the image got taken and aligned */ + txt = "

Aligned Image (current round)

\n"; + + if ((*status == std::string("Initialization")) || + (*status == std::string("Initialization (delayed)")) || + (*status == std::string("Take Image"))) + { + txt += "

Current state: " + *status + "

\n"; + } + else + { + txt += "\n"; + } + httpd_resp_sendstr_chunk(req, txt.c_str()); + } + } + + /* Respond with an empty chunk to signal HTTP response completion */ + httpd_resp_sendstr_chunk(req, NULL); + } + else + { + httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /value not available!"); + return ESP_ERR_NOT_FOUND; + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_wasserzaehler - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_editflow(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_editflow - Start"); +#endif + + ESP_LOGD(TAG, "handler_editflow uri: %s", req->uri); + + char _query[200]; + char _valuechar[30]; + string _task; + + if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) + { + if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "task is found: %s", _valuechar); +#endif + _task = string(_valuechar); + } + } + + if (_task.compare("namenumbers") == 0) + { + ESP_LOGD(TAG, "Get NUMBER list"); + return get_numbers_file_handler(req); + } + + if (_task.compare("data") == 0) + { + ESP_LOGD(TAG, "Get data list"); + return get_data_file_handler(req); + } + + if (_task.compare("tflite") == 0) + { + ESP_LOGD(TAG, "Get tflite list"); + return get_tflite_file_handler(req); + } + + if (_task.compare("copy") == 0) + { + string in, out, zw; + + httpd_query_key_value(_query, "in", _valuechar, 30); + in = string(_valuechar); + httpd_query_key_value(_query, "out", _valuechar, 30); + out = string(_valuechar); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "in: %s", in.c_str()); + ESP_LOGD(TAG, "out: %s", out.c_str()); +#endif + + in = "/sdcard" + in; + out = "/sdcard" + out; + + CopyFile(in, out); + zw = "Copy Done"; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, zw.c_str(), zw.length()); + } + + if (_task.compare("cutref") == 0) + { + string in, out, zw; + int x, y, dx, dy; + bool enhance = false; + + httpd_query_key_value(_query, "in", _valuechar, 30); + in = string(_valuechar); + + httpd_query_key_value(_query, "out", _valuechar, 30); + out = string(_valuechar); + + httpd_query_key_value(_query, "x", _valuechar, 30); + string _x = string(_valuechar); + x = stoi(_x); + + httpd_query_key_value(_query, "y", _valuechar, 30); + string _y = string(_valuechar); + y = stoi(_y); + + httpd_query_key_value(_query, "dx", _valuechar, 30); + string _dx = string(_valuechar); + dx = stoi(_dx); + + httpd_query_key_value(_query, "dy", _valuechar, 30); + string _dy = string(_valuechar); + dy = stoi(_dy); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "in: %s", in.c_str()); + ESP_LOGD(TAG, "out: %s", out.c_str()); + ESP_LOGD(TAG, "x: %s", _x.c_str()); + ESP_LOGD(TAG, "y: %s", _y.c_str()); + ESP_LOGD(TAG, "dx: %s", _dx.c_str()); + ESP_LOGD(TAG, "dy: %s", _dy.c_str()); +#endif + + if (httpd_query_key_value(_query, "enhance", _valuechar, 10) == ESP_OK) + { + string _enhance = string(_valuechar); + + if (_enhance.compare("true") == 0) + { + enhance = true; + } + } + + in = "/sdcard" + in; + out = "/sdcard" + out; + + string out2 = out.substr(0, out.length() - 4) + "_org.jpg"; + + if ((flowctrl.SetupModeActive || (*flowctrl.getActStatus() == std::string("Flow finished"))) && psram_init_shared_memory_for_take_image_step()) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Taking image for Alignment Mark Update..."); + + CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in); + caic->CutAndSave(out2, x, y, dx, dy); + delete caic; + + CImageBasis *cim = new CImageBasis("cutref", out2); + + if (enhance) + { + cim->Contrast(90); + } + + cim->SaveToFile(out); + delete cim; + + psram_deinit_shared_memory_for_take_image_step(); + zw = "CutImage Done"; + } + else + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Taking image for Alignment Mark not possible while device") + " is busy with a round (Current State: '" + *flowctrl.getActStatus() + "')!"); + zw = "Device Busy"; + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, zw.c_str(), zw.length()); + } + + // wird beim Erstellen eines neuen Referenzbildes aufgerufen + std::string *sys_status = flowctrl.getActStatus(); + + if ((sys_status->c_str() != std::string("Take Image")) && (sys_status->c_str() != std::string("Aligning"))) + { + if ((_task.compare("test_take") == 0) || (_task.compare("cam_settings") == 0)) + { + std::string _host = ""; + + // laden der aktuellen Kameraeinstellungen(CCstatus) in den Zwischenspeicher(CFstatus) + setCCstatusToCFstatus(); // CCstatus >>> CFstatus + + if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) + { + _host = std::string(_valuechar); + } + + if (httpd_query_key_value(_query, "waitb", _valuechar, 30) == ESP_OK) + { + int _waitb = std::stoi(_valuechar); + if (_waitb != 0) + { + CFstatus.WaitBeforePicture = _waitb; + } + } + + if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) + { + int _qual = std::stoi(_valuechar); + CFstatus.ImageQuality = clipInt(_qual, 63, 6); + } + + if (httpd_query_key_value(_query, "bri", _valuechar, 30) == ESP_OK) + { + int _bri = std::stoi(_valuechar); + CFstatus.ImageBrightness = clipInt(_bri, 2, -2); + } + + if (httpd_query_key_value(_query, "con", _valuechar, 30) == ESP_OK) + { + int _con = std::stoi(_valuechar); + CFstatus.ImageContrast = clipInt(_con, 2, -2); + } + + if (httpd_query_key_value(_query, "sat", _valuechar, 30) == ESP_OK) + { + int _sat = std::stoi(_valuechar); + CFstatus.ImageSaturation = clipInt(_sat, 2, -2); + } + + if (httpd_query_key_value(_query, "shp", _valuechar, 30) == ESP_OK) + { + int _shp = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageSharpness = clipInt(_shp, 2, -2); + } + else + { + CFstatus.ImageSharpness = clipInt(_shp, 3, -3); + } + } + + if (httpd_query_key_value(_query, "ashp", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAutoSharpness = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "spe", _valuechar, 30) == ESP_OK) + { + int _spe = std::stoi(_valuechar); + CFstatus.ImageSpecialEffect = clipInt(_spe, 6, 0); + } + + if (httpd_query_key_value(_query, "wbm", _valuechar, 30) == ESP_OK) + { + int _wbm = std::stoi(_valuechar); + CFstatus.ImageWbMode = clipInt(_wbm, 4, 0); + } + + if (httpd_query_key_value(_query, "awb", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAwb = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "awbg", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAwbGain = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "aec", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAec = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "aec2", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAec2 = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "ael", _valuechar, 30) == ESP_OK) + { + int _ael = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageAeLevel = clipInt(_ael, 2, -2); + } + else + { + CFstatus.ImageAeLevel = clipInt(_ael, 5, -5); + } + } + + if (httpd_query_key_value(_query, "aecv", _valuechar, 30) == ESP_OK) + { + int _aecv = std::stoi(_valuechar); + CFstatus.ImageAecValue = clipInt(_aecv, 1200, 0); + } + + if (httpd_query_key_value(_query, "agc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAgc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "agcg", _valuechar, 30) == ESP_OK) + { + int _agcg = std::stoi(_valuechar); + CFstatus.ImageAgcGain = clipInt(_agcg, 30, 0); + } + + if (httpd_query_key_value(_query, "bpc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageBpc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "wpc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageWpc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "rgma", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageRawGma = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "lenc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageLenc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "mirror", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageHmirror = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "flip", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageVflip = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "dcw", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageDcw = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "den", _valuechar, 30) == ESP_OK) + { + int _ImageDenoiseLevel = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageDenoiseLevel = 0; + } + else + { + CFstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0); + } + } + + if (httpd_query_key_value(_query, "zoom", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageZoomEnabled = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "zoomx", _valuechar, 30) == ESP_OK) + { + int _ImageZoomOffsetX = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960); + } + } + + if (httpd_query_key_value(_query, "zoomy", _valuechar, 30) == ESP_OK) + { + int _ImageZoomOffsetY = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720); + } + } + + if (httpd_query_key_value(_query, "zooms", _valuechar, 30) == ESP_OK) + { + int _ImageZoomSize = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0); + } + } + + if (httpd_query_key_value(_query, "ledi", _valuechar, 30) == ESP_OK) + { + float _ImageLedIntensity = std::stof(_valuechar); + Camera.SetLEDIntensity(_ImageLedIntensity); + CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; + } + + if (_task.compare("cam_settings") == 0) + { + // wird aufgerufen, wenn das Referenzbild + Kameraeinstellungen gespeichert wurden + setCFstatusToCCstatus(); // CFstatus >>> CCstatus + + // Kameraeinstellungen wurden verädert + CFstatus.changedCameraSettings = true; + + ESP_LOGD(TAG, "Cam Settings set"); + std::string _zw = "CamSettingsSet"; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, _zw.c_str(), _zw.length()); + } + else + { + // wird aufgerufen, wenn ein neues Referenzbild erstellt oder aktualisiert wurde + // CFstatus >>> Kamera + setCFstatusToCam(); + + Camera.SetQualityZoomSize(CFstatus.ImageQuality, CFstatus.ImageFrameSize, CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); + // Camera.SetZoomSize(CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); + + // Kameraeinstellungen wurden verädert + CFstatus.changedCameraSettings = true; + + ESP_LOGD(TAG, "test_take - vor TakeImage"); + std::string image_temp = flowctrl.doSingleStep("[TakeImage]", _host); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, image_temp.c_str(), image_temp.length()); + } + } + + if (_task.compare("test_align") == 0) + { + std::string _host = ""; + + if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) + { + _host = std::string(_valuechar); + } + + std::string zw = flowctrl.doSingleStep("[Alignment]", _host); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, zw.c_str(), zw.length()); + } + } + else + { + std::string _zw = "DeviceIsBusy"; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, _zw.c_str(), _zw.length()); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_editflow - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_statusflow(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_statusflow - Start"); +#endif + + const char *resp_str; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (bTaskAutoFlowCreated) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "handler_statusflow: %s", req->uri); +#endif + + string *zw = flowctrl.getActStatusWithTime(); + resp_str = zw->c_str(); + + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + else + { + resp_str = "Flow task not yet created"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_statusflow - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_cputemp(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_cputemp - Start"); +#endif + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, std::to_string((int)temperatureRead()).c_str(), HTTPD_RESP_USE_STRLEN); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_cputemp - End"); +#endif + + return ESP_OK; +} + +esp_err_t handler_rssi(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_rssi - Start"); +#endif + + if (getWIFIisConnected()) + { + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, std::to_string(get_WIFI_RSSI()).c_str(), HTTPD_RESP_USE_STRLEN); + } + else + { + httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "WIFI not (yet) connected: REST API /rssi not available!"); + return ESP_ERR_NOT_FOUND; + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_rssi - End"); +#endif + + return ESP_OK; +} + +esp_err_t handler_uptime(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_uptime - Start"); +#endif + + std::string formatedUptime = getFormatedUptime(false); + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, formatedUptime.c_str(), formatedUptime.length()); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_uptime - End"); +#endif + + return ESP_OK; +} + +esp_err_t handler_prevalue(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_prevalue - Start"); + ESP_LOGD(TAG, "handler_prevalue: %s", req->uri); +#endif + + // Default usage message when handler gets called without any parameter + const std::string RESTUsageInfo = + "00: Handler usage:
" + "- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main
" + "- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678
" + "NOTE:
" + "value >= 0.0: Set PreValue to provided value
" + "value < 0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)"; + + // Default return error message when no return is programmed + std::string sReturnMessage = "E90: Uninitialized"; + + char _query[100]; + char _numbersname[50] = "default"; + char _value[20] = ""; + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Query: %s", _query); +#endif + + if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) + { + // If request is incomplete + sReturnMessage = "E91: Query parameter incomplete or not valid!
" + "Call /setPreValue to show REST API usage info and/or check documentation"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + + if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Value: %s", _value); +#endif + } + } + else + { + // if no parameter is provided, print handler usage + httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length()); + return ESP_OK; + } + + if (strlen(_value) == 0) + { + // If no value is povided --> return actual PreValue + sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); + + if (sReturnMessage.empty()) + { + sReturnMessage = "E92: Numbers name not found"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + } + else + { + // New value is positive: Set PreValue to provided value and return value + // New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) + ", value: " + std::string(_value)); + + if (!flowctrl.UpdatePrevalue(_value, _numbersname, true)) + { + sReturnMessage = "E93: Update request rejected. Please check device logs for more details"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + + sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); + + if (sReturnMessage.empty()) + { + sReturnMessage = "E94: Numbers name not found"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + } + + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_prevalue - End"); +#endif + + return ESP_OK; +} + +void task_autodoFlow(void *pvParameter) +{ + int64_t fr_start, fr_delta_ms; + + bTaskAutoFlowCreated = true; + + if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC)) + { + flowctrl.setActStatus("Initialization (delayed)"); + // #ifdef ENABLE_MQTT + // MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later + // #endif //ENABLE_MQTT + vTaskDelay(60 * 5000 / portTICK_PERIOD_MS); // Wait 5 minutes to give time to do an OTA update or fetch the log + } + + ESP_LOGD(TAG, "task_autodoFlow: start"); + doInit(); + + flowctrl.setAutoStartInterval(auto_interval); + autostartIsEnabled = flowctrl.getIsAutoStart(); + + if (isSetupModusActive()) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "We are in Setup Mode -> Not starting Auto Flow!"); + autostartIsEnabled = false; + // 15.7.0 Setup Wizard cannot take a Reference Picture #2953 + // std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); + // flowctrl.doFlowTakeImageOnly(zw_time); + } + + if (autostartIsEnabled) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Starting Flow..."); + } + else + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Autostart is not enabled -> Not starting Flow"); + } + + while (autostartIsEnabled) + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs + time_t roundStartTime = getUpTime(); + + std::string _zw = "Round #" + std::to_string(++countRounds) + " started"; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw); + + fr_start = esp_timer_get_time(); + + if (flowisrunning) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Autoflow: doFlow is already running!"); +#endif + } + else + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Autoflow: doFlow is started"); +#endif + flowisrunning = true; + doflow(); +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Remove older log files"); +#endif + LogFile.RemoveOldLogFile(); + LogFile.RemoveOldDataLog(); + } + + // Round finished -> Logfile + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) + " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)"); + + // CPU Temp -> Logfile + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C"); + + // WIFI Signal Strength (RSSI) -> Logfile + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm"); + + // Check if time is synchronized (if NTP is configured) + if (getUseNtp() && !getTimeIsSet()) + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time server is configured, but time is not yet set!"); + StatusLED(TIME_CHECK, 1, false); + } + +#if (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES) + wifiRoamingQuery(); +#endif + +// Scan channels and check if an AP with better RSSI is available, then disconnect and try to reconnect to AP with better RSSI +// NOTE: Keep this direct before the following task delay, because scan is done in blocking mode and this takes ca. 1,5 - 2s. +#ifdef WLAN_USE_ROAMING_BY_SCANNING + wifiRoamByScanning(); +#endif + + fr_delta_ms = (esp_timer_get_time() - fr_start) / 1000; + + if (auto_interval > fr_delta_ms) + { + const TickType_t xDelay = (auto_interval - fr_delta_ms) / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "Autoflow: sleep for: %ldms", (long)xDelay); + vTaskDelay(xDelay); + } + } + + while (1) + { + // Keep flow task running to handle necessary sub tasks like reboot handler, etc.. + vTaskDelay(2000 / portTICK_PERIOD_MS); + } + + vTaskDelete(NULL); // Delete this task if it exits from the loop above + xHandletask_autodoFlow = NULL; + + ESP_LOGD(TAG, "task_autodoFlow: end"); +} + +void InitializeFlowTask(void) +{ + BaseType_t xReturned; + + ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); + + uint32_t stackSize = 16 * 1024; + xReturned = xTaskCreatePinnedToCore(&task_autodoFlow, "task_autodoFlow", stackSize, NULL, tskIDLE_PRIORITY + 2, &xHandletask_autodoFlow, 0); + + if (xReturned != pdPASS) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Creation task_autodoFlow failed. Requested stack size:" + std::to_string(stackSize)); + LogFile.WriteHeapInfo("Creation task_autodoFlow failed"); + } + + ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); +} + +void register_server_main_flow_task_uri(httpd_handle_t server) +{ + ESP_LOGI(TAG, "server_main_flow_task - Registering URI handlers"); + + httpd_uri_t camuri = {}; + camuri.method = HTTP_GET; + + camuri.uri = "/doinit"; + camuri.handler = handler_init; + camuri.user_ctx = (void *)"Light On"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/setPreValue" + camuri.uri = "/setPreValue.html"; + camuri.handler = handler_prevalue; + camuri.user_ctx = (void *)"Prevalue"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/setPreValue"; + camuri.handler = handler_prevalue; + camuri.user_ctx = (void *)"Prevalue"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/flow_start"; + camuri.handler = handler_flow_start; + camuri.user_ctx = (void *)"Flow Start"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/statusflow.html"; + camuri.handler = handler_statusflow; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/statusflow"; + camuri.handler = handler_statusflow; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/cpu_temperature" + camuri.uri = "/cputemp.html"; + camuri.handler = handler_cputemp; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/cpu_temperature"; + camuri.handler = handler_cputemp; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/rssi" + camuri.uri = "/rssi.html"; + camuri.handler = handler_rssi; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/rssi"; + camuri.handler = handler_rssi; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/uptime"; + camuri.handler = handler_uptime; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/editflow"; + camuri.handler = handler_editflow; + camuri.user_ctx = (void *)"EditFlow"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/value" + camuri.uri = "/value.html"; + camuri.handler = handler_wasserzaehler; + camuri.user_ctx = (void *)"Value"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/value"; + camuri.handler = handler_wasserzaehler; + camuri.user_ctx = (void *)"Value"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/value" + camuri.uri = "/wasserzaehler.html"; + camuri.handler = handler_wasserzaehler; + camuri.user_ctx = (void *)"Wasserzaehler"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/json"; + camuri.handler = handler_json; + camuri.user_ctx = (void *)"JSON"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/heap"; + camuri.handler = handler_get_heap; + camuri.user_ctx = (void *)"Heap"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/stream"; + camuri.handler = handler_stream; + camuri.user_ctx = (void *)"stream"; + httpd_register_uri_handler(server, &camuri); +} diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.h b/code/components/jomjol_flowcontroll/MainFlowControl.h index 8a2d1c410..3596325f3 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.h +++ b/code/components/jomjol_flowcontroll/MainFlowControl.h @@ -1,87 +1,90 @@ -#pragma once - -#ifndef MAINFLOWCONTROL_H -#define MAINFLOWCONTROL_H - -#include -#include - -#include -#include "CImageBasis.h" -#include "ClassFlowControll.h" - -typedef struct -{ - framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 - gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - - int ImageQuality; // 0 - 63 - int ImageBrightness; // (-2 to 2) - set brightness - int ImageContrast; //-2 - 2 - int ImageSaturation; //-2 - 2 - int ImageSharpness; //-2 - 2 - bool ImageAutoSharpness; - int ImageSpecialEffect; // 0 - 6 - int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - int ImageAwb; // white balance enable (0 or 1) - int ImageAwbGain; // Auto White Balance enable (0 or 1) - int ImageAec; // auto exposure off (1 or 0) - int ImageAec2; // automatic exposure sensor (0 or 1) - int ImageAeLevel; // auto exposure levels (-2 to 2) - int ImageAecValue; // set exposure manually (0-1200) - int ImageAgc; // auto gain off (1 or 0) - int ImageAgcGain; // set gain manually (0 - 30) - int ImageBpc; // black pixel correction - int ImageWpc; // white pixel correction - int ImageRawGma; // (1 or 0) - int ImageLenc; // lens correction (1 or 0) - int ImageHmirror; // (0 or 1) flip horizontally - int ImageVflip; // Invert image (0 or 1) - int ImageDcw; // downsize enable (1 or 0) - - int ImageWidth; - int ImageHeight; - - int ImageLedIntensity; - - bool ImageZoomEnabled; - int ImageZoomMode; - int ImageZoomOffsetX; - int ImageZoomOffsetY; - int ImageZoomSize; - - int WaitBeforePicture; - bool isImageSize; - - bool CameraInitSuccessful; - bool changedCameraSettings; - bool DemoMode; - bool SaveAllFiles; -} camera_flow_config_temp_t; - -extern camera_flow_config_temp_t CFstatus; -extern ClassFlowControll flowctrl; - -esp_err_t setCCstatusToCFstatus(void); // CCstatus >>> CFstatus -esp_err_t setCFstatusToCCstatus(void); // CFstatus >>> CCstatus -esp_err_t setCFstatusToCam(void); // CFstatus >>> Kamera - -void register_server_main_flow_task_uri(httpd_handle_t server); - -void CheckIsPlannedReboot(void); -bool getIsPlannedReboot(void); - -void InitializeFlowTask(void); -void DeleteMainFlowTask(void); -bool isSetupModusActive(void); - -int getCountFlowRounds(void); - -#ifdef ENABLE_MQTT -esp_err_t MQTTCtrlFlowStart(std::string _topic); -#endif // ENABLE_MQTT - -esp_err_t GetRawJPG(httpd_req_t *req); -esp_err_t GetJPG(std::string _filename, httpd_req_t *req); - -#endif // MAINFLOWCONTROL_H +#pragma once + +#ifndef MAINFLOWCONTROL_H +#define MAINFLOWCONTROL_H + +#include +#include + +#include +#include "CImageBasis.h" +#include "ClassFlowControll.h" + +typedef struct +{ + uint16_t CamSensor_id; + + framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 + gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + + int ImageQuality; // 0 - 63 + int ImageBrightness; // (-2 to 2) - set brightness + int ImageContrast; //-2 - 2 + int ImageSaturation; //-2 - 2 + int ImageSharpness; //-2 - 2 + bool ImageAutoSharpness; + int ImageSpecialEffect; // 0 - 6 + int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + int ImageAwb; // white balance enable (0 or 1) + int ImageAwbGain; // Auto White Balance enable (0 or 1) + int ImageAec; // auto exposure off (1 or 0) + int ImageAec2; // automatic exposure sensor (0 or 1) + int ImageAeLevel; // auto exposure levels (-2 to 2) + int ImageAecValue; // set exposure manually (0-1200) + int ImageAgc; // auto gain off (1 or 0) + int ImageAgcGain; // set gain manually (0 - 30) + int ImageBpc; // black pixel correction + int ImageWpc; // white pixel correction + int ImageRawGma; // (1 or 0) + int ImageLenc; // lens correction (1 or 0) + int ImageHmirror; // (0 or 1) flip horizontally + int ImageVflip; // Invert image (0 or 1) + int ImageDcw; // downsize enable (1 or 0) + + int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + int ImageWidth; + int ImageHeight; + + int ImageLedIntensity; + + bool ImageZoomEnabled; + int ImageZoomOffsetX; + int ImageZoomOffsetY; + int ImageZoomSize; + + int WaitBeforePicture; + bool isImageSize; + + bool CameraInitSuccessful; + bool changedCameraSettings; + bool DemoMode; + bool SaveAllFiles; +} camera_flow_config_temp_t; + +extern camera_flow_config_temp_t CFstatus; +extern ClassFlowControll flowctrl; + +esp_err_t setCCstatusToCFstatus(void); // CCstatus >>> CFstatus +esp_err_t setCFstatusToCCstatus(void); // CFstatus >>> CCstatus +esp_err_t setCFstatusToCam(void); // CFstatus >>> Kamera + +void register_server_main_flow_task_uri(httpd_handle_t server); + +void CheckIsPlannedReboot(void); +bool getIsPlannedReboot(void); + +void InitializeFlowTask(void); +void DeleteMainFlowTask(void); +bool isSetupModusActive(void); + +int getCountFlowRounds(void); + +#ifdef ENABLE_MQTT +esp_err_t MQTTCtrlFlowStart(std::string _topic); +#endif // ENABLE_MQTT + +esp_err_t GetRawJPG(httpd_req_t *req); +esp_err_t GetJPG(std::string _filename, httpd_req_t *req); + +#endif // MAINFLOWCONTROL_H diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index c794646a3..49a1d9a51 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/code/components/jomjol_helper/Helper.cpp @@ -1206,3 +1206,26 @@ bool isInString(std::string &s, std::string const &toFind) return true; } + +int clipInt(int input, int high, int low) +{ + if (input < low) + { + input = low; + } + else if (input > high) + { + input = high; + } + return input; +} + +bool numericStrToBool(char *input) +{ + return (std::stoi(input) != 0); +} + +bool stringToBoolean(std::string input) +{ + return (input == "TRUE"); +} diff --git a/code/components/jomjol_helper/Helper.h b/code/components/jomjol_helper/Helper.h index 9cfdf702e..deeaf8a5f 100644 --- a/code/components/jomjol_helper/Helper.h +++ b/code/components/jomjol_helper/Helper.h @@ -102,4 +102,8 @@ bool replaceString(std::string& s, std::string const& toReplace, std::string con bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt); bool isInString(std::string& s, std::string const& toFind); +int clipInt(int input, int high, int low); +bool numericStrToBool(char *input); +bool stringToBoolean(std::string input); + #endif //HELPER_H diff --git a/param-docs/expert-params.txt b/param-docs/expert-params.txt index db38cc929..235a74d8c 100644 --- a/param-docs/expert-params.txt +++ b/param-docs/expert-params.txt @@ -1,46 +1,47 @@ -WaitBeforeTakingPicture -CamFrameSize -CamGainceiling -CamQuality -CamAutoSharpness -CamSharpness -CamSpecialEffect -CamWbMode -CamAwb -CamAwbGain -CamAec -CamAec2 -CamAeLevel -CamAecValue -CamAgc -CamAgcGain -CamBpc -CamWpc -CamRawGma -CamLenc -CamDcw -CamZoom -CamZoomSize -CamZoomOffsetX -CamZoomOffsetY -demo -SearchFieldX -SearchFieldY -AlignmentAlgo -CNNGoodThreshold -PreValueAgeStartup -ErrorMessage -CheckDigitIncreaseConsistency -IO0 -IO1 -IO3 -IO4 -IO12 -IO13 -AutoStart -Hostname -RSSIThreshold -TimeServer -CACert -ClientCert -ClientKey +WaitBeforeTakingPicture +CamFrameSize +CamGainceiling +CamQuality +CamAutoSharpness +CamSharpness +CamSpecialEffect +CamWbMode +CamAwb +CamAwbGain +CamAec +CamAec2 +CamAeLevel +CamAecValue +CamAgc +CamAgcGain +CamBpc +CamWpc +CamRawGma +CamLenc +CamDcw +CamDenoise +CamZoom +CamZoomSize +CamZoomOffsetX +CamZoomOffsetY +demo +SearchFieldX +SearchFieldY +AlignmentAlgo +CNNGoodThreshold +PreValueAgeStartup +ErrorMessage +CheckDigitIncreaseConsistency +IO0 +IO1 +IO3 +IO4 +IO12 +IO13 +AutoStart +Hostname +RSSIThreshold +TimeServer +CACert +ClientCert +ClientKey diff --git a/param-docs/parameter-pages/TakeImage/CamAeLevel.md b/param-docs/parameter-pages/TakeImage/CamAeLevel.md index 8f562828c..e7d5fd079 100644 --- a/param-docs/parameter-pages/TakeImage/CamAeLevel.md +++ b/param-docs/parameter-pages/TakeImage/CamAeLevel.md @@ -1,15 +1,16 @@ -# Parameter `CamAeLevel` -Default Value: `0` - -!!! Warning - This is an **Expert Parameter**! Only change it if you understand what it does! - -!!! Note - This parameter can also be set on the Reference Image configuration page! - -!!! Note - After changing this parameter you need to update your reference image and alignment markers! - -Auto-Exposure Compensation. Lower values produce darker image. - -Range (`-2` .. `2`) +# Parameter `CamAeLevel` +Default Value: `0` + +!!! Warning + This is an **Expert Parameter**! Only change it if you understand what it does! + +!!! Note + This parameter can also be set on the Reference Image configuration page! + +!!! Note + After changing this parameter you need to update your reference image and alignment markers! + +Auto-Exposure Compensation. Lower values produce darker image. + +available range on OV2640 (`-2` .. `2`) +available range on OV3660 and OV5640 (`-5` .. `5`) diff --git a/param-docs/parameter-pages/TakeImage/CamDenoise.md b/param-docs/parameter-pages/TakeImage/CamDenoise.md index 36c0a573d..917af00c7 100644 --- a/param-docs/parameter-pages/TakeImage/CamDenoise.md +++ b/param-docs/parameter-pages/TakeImage/CamDenoise.md @@ -1,10 +1,12 @@ -# Parameter `CamDenoise` -Default Value: ` ` - -!!! Warning - This is an **Expert Parameter**! Only change it if you understand what it does! - -!!! Note - After changing this parameter you need to update your reference image and alignment markers! - -Denoise Image (not supported) +# Parameter `CamDenoise` +Default Value: `0` + +!!! Warning + This is an **Expert Parameter**! Only change it if you understand what it does! + +!!! Note + After changing this parameter you need to update your reference image and alignment markers! + +Denoise Image, is only supported by OV3660 and OV5640 + +Range (`0` .. `8`) diff --git a/sd-card/config/config.ini b/sd-card/config/config.ini index 2b133857f..24b5c357b 100644 --- a/sd-card/config/config.ini +++ b/sd-card/config/config.ini @@ -26,6 +26,7 @@ CamLenc = true CamHmirror = false CamVflip = false CamDcw = true +CamDenoise = 0 CamZoom = false CamZoomOffsetX = 0 CamZoomOffsetY = 0 diff --git a/sd-card/html/edit_config_template.html b/sd-card/html/edit_config_template.html index d00ff6698..314fc88c9 100644 --- a/sd-card/html/edit_config_template.html +++ b/sd-card/html/edit_config_template.html @@ -1,3158 +1,3173 @@ - - - -Configuration - - - - - - - - - - - - - - - - - - -
-
-
- -

Configuration

- -
- CLICK HERE for usage description. More infos in documentation: - Parameter - -

- This page lists all available configuration parameters of the device.
- The description of each parameter can be shown by hovering over or by clicking the icon. -

-

- The page gets opened with the default view which should be sufficient for regular configuration tasks. Enabling the "Show Expert Parameters" - some expert parameters (light red background color) will be added to the parameter list. Additionally the button "Edit "Config.ini" File" - to edit the underlaying configuration file (config.ini) manually is now shown on top of the page. This function should be only used for special cases. -

-

- Sections (entire functionality) or single parameters having a checkbox can be enabled or disabled. - Disabling a complete section results in a disabled functionality. Whenever only a single parameter of a section is disabled - the hard-coded default value is used for the disabled parameter. -

-

- Don't forget to save the changes with the button "Save Config" at the bottom of this page.
- -

-
-
- - - - - - - - - - + + + +Configuration + + + + + + + + + + + + + + + + + + +
+
+
+ +

Configuration

+ +
+ CLICK HERE for usage description. More infos in documentation: + Parameter + +

+ This page lists all available configuration parameters of the device.
+ The description of each parameter can be shown by hovering over or by clicking the icon. +

+

+ The page gets opened with the default view which should be sufficient for regular configuration tasks. Enabling the "Show Expert Parameters" + some expert parameters (light red background color) will be added to the parameter list. Additionally the button "Edit "Config.ini" File" + to edit the underlaying configuration file (config.ini) manually is now shown on top of the page. This function should be only used for special cases. +

+

+ Sections (entire functionality) or single parameters having a checkbox can be enabled or disabled. + Disabling a complete section results in a disabled functionality. Whenever only a single parameter of a section is disabled + the hard-coded default value is used for the disabled parameter. +

+

+ Don't forget to save the changes with the button "Save Config" at the bottom of this page.
+ +

+
+
+ + + + + + + + + + diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index 593281ef0..2317ae946 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -1,1140 +1,1146 @@ -var config_gesamt = ""; -var config_split = []; -var param = []; -var category; -var ref = new Array(2); -var NUMBERS = new Array(0); -var REFERENCES = new Array(0); - - -function getNUMBERSList() { - _domainname = getDomainname(); - var namenumberslist = ""; - - var xhttp = new XMLHttpRequest(); - - xhttp.addEventListener('load', function(event) { - if (xhttp.status >= 200 && xhttp.status < 300) { - namenumberslist = xhttp.responseText; - } - else { - console.warn(request.statusText, request.responseText); - } - }); - - try { - url = _domainname + '/editflow?task=namenumbers'; - xhttp.open("GET", url, false); - xhttp.send(); - } catch (error) {} - - namenumberslist = namenumberslist.split("\t"); - - return namenumberslist; -} - - -function getDATAList() { - _domainname = getDomainname(); - datalist = ""; - - var xhttp = new XMLHttpRequest(); - - xhttp.addEventListener('load', function(event) { - if (xhttp.status >= 200 && xhttp.status < 300) { - datalist = xhttp.responseText; - } - else { - console.warn(request.statusText, request.responseText); - } - }); - - try { - url = _domainname + '/editflow?task=data'; - xhttp.open("GET", url, false); - xhttp.send(); - } catch (error) {} - - datalist = datalist.split("\t"); - datalist.pop(); - datalist.sort(); - - return datalist; -} - - -function getTFLITEList() { - _domainname = getDomainname(); - tflitelist = ""; - - var xhttp = new XMLHttpRequest(); - - xhttp.addEventListener('load', function(event) { - if (xhttp.status >= 200 && xhttp.status < 300) { - tflitelist = xhttp.responseText; - } - else { - console.warn(request.statusText, request.responseText); - } - }); - - try { - url = _domainname + '/editflow?task=tflite'; - xhttp.open("GET", url, false); - xhttp.send(); - } catch (error) {} - - tflitelist = tflitelist.split("\t"); - tflitelist.sort(); - - return tflitelist; -} - - -function ParseConfig() { - config_split = config_gesamt.split("\n"); - var aktline = 0; - - param = new Object(); - category = new Object(); - - var catname = "TakeImage"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "RawImagesLocation"); - ParamAddValue(param, catname, "RawImagesRetention"); - ParamAddValue(param, catname, "WaitBeforeTakingPicture"); - ParamAddValue(param, catname, "CamGainceiling"); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - ParamAddValue(param, catname, "CamQuality"); // 0 - 63 - ParamAddValue(param, catname, "CamBrightness"); // (-2 to 2) - set brightness - ParamAddValue(param, catname, "CamContrast"); //-2 - 2 - ParamAddValue(param, catname, "CamSaturation"); //-2 - 2 - ParamAddValue(param, catname, "CamSharpness"); //-2 - 2 - ParamAddValue(param, catname, "CamAutoSharpness"); // (1 or 0) - ParamAddValue(param, catname, "CamSpecialEffect"); // 0 - 6 - ParamAddValue(param, catname, "CamWbMode"); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - ParamAddValue(param, catname, "CamAwb"); // white balance enable (0 or 1) - ParamAddValue(param, catname, "CamAwbGain"); // Auto White Balance enable (0 or 1) - ParamAddValue(param, catname, "CamAec"); // auto exposure off (1 or 0) - ParamAddValue(param, catname, "CamAec2"); // automatic exposure sensor (0 or 1) - ParamAddValue(param, catname, "CamAeLevel"); // auto exposure levels (-2 to 2) - ParamAddValue(param, catname, "CamAecValue"); // set exposure manually (0-1200) - ParamAddValue(param, catname, "CamAgc"); // auto gain off (1 or 0) - ParamAddValue(param, catname, "CamAgcGain"); // set gain manually (0 - 30) - ParamAddValue(param, catname, "CamBpc"); // black pixel correction - ParamAddValue(param, catname, "CamWpc"); // white pixel correction - ParamAddValue(param, catname, "CamRawGma"); // (1 or 0) - ParamAddValue(param, catname, "CamLenc"); // lens correction (1 or 0) - ParamAddValue(param, catname, "CamHmirror"); // (0 or 1) flip horizontally - ParamAddValue(param, catname, "CamVflip"); // Invert image (0 or 1) - ParamAddValue(param, catname, "CamDcw"); // downsize enable (1 or 0) - ParamAddValue(param, catname, "CamZoom"); - ParamAddValue(param, catname, "CamZoomOffsetX"); - ParamAddValue(param, catname, "CamZoomOffsetY"); - ParamAddValue(param, catname, "CamZoomSize"); - ParamAddValue(param, catname, "LEDIntensity"); - ParamAddValue(param, catname, "Demo"); - - var catname = "Alignment"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "InitialRotate"); - ParamAddValue(param, catname, "SearchFieldX"); - ParamAddValue(param, catname, "SearchFieldY"); - ParamAddValue(param, catname, "AlignmentAlgo"); - - var catname = "Digits"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Model"); - ParamAddValue(param, catname, "CNNGoodThreshold", 1); - ParamAddValue(param, catname, "ROIImagesLocation"); - ParamAddValue(param, catname, "ROIImagesRetention"); - - var catname = "Analog"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Model"); - ParamAddValue(param, catname, "ROIImagesLocation"); - ParamAddValue(param, catname, "ROIImagesRetention"); - - var catname = "PostProcessing"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "DecimalShift", 1, true); - ParamAddValue(param, catname, "AnalogDigitalTransitionStart", 1, true); - // ParamAddValue(param, catname, "PreValueUse", 1, true, "true"); - ParamAddValue(param, catname, "PreValueUse"); - ParamAddValue(param, catname, "PreValueAgeStartup"); - ParamAddValue(param, catname, "AllowNegativeRates", 1, true, "false"); - ParamAddValue(param, catname, "MaxRateValue", 1, true); - ParamAddValue(param, catname, "MaxRateType", 1, true); - ParamAddValue(param, catname, "ExtendedResolution", 1, true, "false"); - ParamAddValue(param, catname, "IgnoreLeadingNaN", 1, true, "false"); - // ParamAddValue(param, catname, "IgnoreAllNaN", 1, true, "false"); - ParamAddValue(param, catname, "ErrorMessage"); - ParamAddValue(param, catname, "CheckDigitIncreaseConsistency"); - - var catname = "MQTT"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "MainTopic", 1, false); - ParamAddValue(param, catname, "ClientID"); - ParamAddValue(param, catname, "user"); - ParamAddValue(param, catname, "password"); - ParamAddValue(param, catname, "RetainMessages"); - ParamAddValue(param, catname, "HomeassistantDiscovery"); - ParamAddValue(param, catname, "MeterType"); - ParamAddValue(param, catname, "CACert"); - ParamAddValue(param, catname, "ClientCert"); - ParamAddValue(param, catname, "ClientKey"); - - var catname = "InfluxDB"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "Database"); -// ParamAddValue(param, catname, "Measurement"); - ParamAddValue(param, catname, "user"); - ParamAddValue(param, catname, "password"); - ParamAddValue(param, catname, "Measurement", 1, true); - ParamAddValue(param, catname, "Field", 1, true); - - var catname = "InfluxDBv2"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "Bucket"); -// ParamAddValue(param, catname, "Measurement"); - ParamAddValue(param, catname, "Org"); - ParamAddValue(param, catname, "Token"); - ParamAddValue(param, catname, "Measurement", 1, true); - ParamAddValue(param, catname, "Field", 1, true); - - var catname = "GPIO"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "IO0", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO1", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO3", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO4", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO12", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO13", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "LEDType"); - ParamAddValue(param, catname, "LEDNumbers"); - ParamAddValue(param, catname, "LEDColor", 3); - // Default Values, um abwärtskompatiblität zu gewährleisten - param[catname]["LEDType"]["value1"] = "WS2812"; - param[catname]["LEDNumbers"]["value1"] = "2"; - param[catname]["LEDColor"]["value1"] = "50"; - param[catname]["LEDColor"]["value2"] = "50"; - param[catname]["LEDColor"]["value3"] = "50"; - - var catname = "AutoTimer"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "AutoStart"); - ParamAddValue(param, catname, "Interval"); - - var catname = "DataLogging"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "DataLogActive"); - ParamAddValue(param, catname, "DataFilesRetention"); - - var catname = "Debug"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "LogLevel"); - ParamAddValue(param, catname, "LogfilesRetention"); - - var catname = "System"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Tooltip"); - ParamAddValue(param, catname, "TimeZone"); - ParamAddValue(param, catname, "TimeServer"); - ParamAddValue(param, catname, "Hostname"); - ParamAddValue(param, catname, "RSSIThreshold"); - ParamAddValue(param, catname, "CPUFrequency"); - ParamAddValue(param, catname, "SetupMode"); - - while (aktline < config_split.length){ - for (var cat in category) { - zw = cat.toUpperCase(); - zw1 = "[" + zw + "]"; - zw2 = ";[" + zw + "]"; - - if ((config_split[aktline].trim().toUpperCase() == zw1) || (config_split[aktline].trim().toUpperCase() == zw2)) { - if (config_split[aktline].trim().toUpperCase() == zw1) { - category[cat]["enabled"] = true; - } - - category[cat]["found"] = true; - category[cat]["line"] = aktline; - aktline = ParseConfigParamAll(aktline, cat); - continue; - } - } - - aktline++; - } - - // Make the downward compatiblity with DataLogging - if (category["DataLogging"]["found"] == false) { - category["DataLogging"]["found"] = true; - category["DataLogging"]["enabled"] = true; - - param["DataLogging"]["DataLogActive"]["found"] = true; - param["DataLogging"]["DataLogActive"]["enabled"] = true; - param["DataLogging"]["DataLogActive"]["value1"] = "true"; - - param["DataLogging"]["DataFilesRetention"]["found"] = true; - param["DataLogging"]["DataFilesRetention"]["enabled"] = true; - param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; - } - - if (category["DataLogging"]["enabled"] == false) { - category["DataLogging"]["enabled"] = true - } - - if (param["DataLogging"]["DataLogActive"]["enabled"] == false && param["DataLogging"]["DataLogActive"]["value1"] == "") { - param["DataLogging"]["DataLogActive"]["found"] = true; - param["DataLogging"]["DataLogActive"]["enabled"] = true; - param["DataLogging"]["DataLogActive"]["value1"] = "true"; - } - - if (param["DataLogging"]["DataFilesRetention"]["enabled"] == false && param["DataLogging"]["DataFilesRetention"]["value1"] == "") { - param["DataLogging"]["DataFilesRetention"]["found"] = true; - param["DataLogging"]["DataFilesRetention"]["enabled"] = true; - param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; - } - - // Downward compatibility: Create RSSIThreshold if not available - if (param["System"]["RSSIThreshold"]["found"] == false) { - param["System"]["RSSIThreshold"]["found"] = true; - param["System"]["RSSIThreshold"]["enabled"] = false; - param["System"]["RSSIThreshold"]["value1"] = "0"; - } -} - - -function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _defaultValue = "", _checkRegExList = null) { - param[_cat][_param] = new Object(); - param[_cat][_param]["found"] = false; - param[_cat][_param]["enabled"] = false; - param[_cat][_param]["line"] = -1; - param[_cat][_param]["anzParam"] = _anzParam; - param[_cat][_param]["defaultValue"] = _defaultValue; - param[_cat][_param]["Numbers"] = _isNUMBER; - param[_cat][_param].checkRegExList = _checkRegExList; -}; - - -function ParseConfigParamAll(_aktline, _catname) { - ++_aktline; - - while ((_aktline < config_split.length) && !(config_split[_aktline][0] == "[") && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { - var _input = config_split[_aktline]; - let [isCom, input] = isCommented(_input); - var linesplit = ZerlegeZeile(input); - ParamExtractValueAll(param, linesplit, _catname, _aktline, isCom); - - if (!isCom && (linesplit.length >= 5) && (_catname == 'Digits')) { - ExtractROIs(input, "digit"); - } - - if (!isCom && (linesplit.length >= 5) && (_catname == 'Analog')) { - ExtractROIs(input, "analog"); - } - - if (!isCom && (linesplit.length == 3) && (_catname == 'Alignment')) { - _newref = new Object(); - _newref["name"] = linesplit[0]; - _newref["x"] = linesplit[1]; - _newref["y"] = linesplit[2]; - REFERENCES.push(_newref); - } - - ++_aktline; - } - - return _aktline; -} - - -function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _iscom, _anzvalue = 1) { - if ((_linesplit[0].toUpperCase() == _paramname.toUpperCase()) && (_linesplit.length > _anzvalue)) { - _param[_catname][_paramname]["found"] = true; - _param[_catname][_paramname]["enabled"] = !_iscom; - _param[_catname][_paramname]["line"] = _aktline; - _param[_catname][_paramname]["anzpara"] = _anzvalue; - - for (var j = 1; j <= _anzvalue; ++j) { - _param[_catname][_paramname]["value"+j] = _linesplit[j]; - } - } -} - - -function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom) { - for (var paramname in _param[_catname]) { - _AktROI = "default"; - _AktPara = _linesplit[0]; - _pospunkt = _AktPara.indexOf ("."); - - if (_pospunkt > -1) { - _AktROI = _AktPara.substring(0, _pospunkt); - _AktPara = _AktPara.substring(_pospunkt+1); - } - - if (_AktPara.toUpperCase() == paramname.toUpperCase()) { - while (_linesplit.length <= _param[_catname][paramname]["anzParam"]) { - _linesplit.push(""); - } - - _param[_catname][paramname]["found"] = true; - _param[_catname][paramname]["enabled"] = !_iscom; - _param[_catname][paramname]["line"] = _aktline; - - if (_param[_catname][paramname]["Numbers"] == true) { // möglicher Multiusage - abc = getNUMBERS(_linesplit[0]); - abc[_catname][paramname] = new Object; - abc[_catname][paramname]["found"] = true; - abc[_catname][paramname]["enabled"] = !_iscom; - - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - abc[_catname][paramname]["value"+j] = _linesplit[j]; - } - - if (abc["name"] == "default") { - for (_num in NUMBERS) { // wert mit Default belegen - if (NUMBERS[_num][_catname][paramname]["found"] == false) { - NUMBERS[_num][_catname][paramname]["found"] = true; - NUMBERS[_num][_catname][paramname]["enabled"] = !_iscom; - NUMBERS[_num][_catname][paramname]["line"] = _aktline; - - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - NUMBERS[_num][_catname][paramname]["value"+j] = _linesplit[j]; - } - } - } - } - } - else { - _param[_catname][paramname]["found"] = true; - _param[_catname][paramname]["enabled"] = !_iscom; - _param[_catname][paramname]["line"] = _aktline; - - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - _param[_catname][paramname]["value"+j] = _linesplit[j]; - } - } - } - } -} - - -function getCamConfig() { - ParseConfig(); - - param["System"]["Tooltip"]["enabled"] = true; - param["Alignment"]["InitialRotate"]["enabled"] = true; - - param["TakeImage"]["WaitBeforeTakingPicture"]["enabled"] = true; - param["TakeImage"]["CamGainceiling"]["enabled"] = true; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - param["TakeImage"]["CamQuality"]["enabled"] = true; // 0 - 63 - param["TakeImage"]["CamBrightness"]["enabled"] = true; // (-2 to 2) - set brightness - param["TakeImage"]["CamContrast"]["enabled"] = true; //-2 - 2 - param["TakeImage"]["CamSaturation"]["enabled"] = true; //-2 - 2 - param["TakeImage"]["CamSharpness"]["enabled"] = true; //-2 - 2 - param["TakeImage"]["CamAutoSharpness"]["enabled"] = true; //(1 or 0) - param["TakeImage"]["CamSpecialEffect"]["enabled"] = true; // 0 - 6 - param["TakeImage"]["CamWbMode"]["enabled"] = true; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - param["TakeImage"]["CamAwb"]["enabled"] = true; // white balance enable (0 or 1) - param["TakeImage"]["CamAwbGain"]["enabled"] = true; // Auto White Balance enable (0 or 1) - param["TakeImage"]["CamAec"]["enabled"] = true; // auto exposure off (1 or 0) - param["TakeImage"]["CamAec2"]["enabled"] = true; // automatic exposure sensor (0 or 1) - param["TakeImage"]["CamAeLevel"]["enabled"] = true; // auto exposure levels (-2 to 2) - param["TakeImage"]["CamAecValue"]["enabled"] = true; // set exposure manually (0-1200) - param["TakeImage"]["CamAgc"]["enabled"] = true; // auto gain off (1 or 0) - param["TakeImage"]["CamAgcGain"]["enabled"] = true; // set gain manually (0 - 30) - param["TakeImage"]["CamBpc"]["enabled"] = true; // black pixel correction - param["TakeImage"]["CamWpc"]["enabled"] = true; // white pixel correction - param["TakeImage"]["CamRawGma"]["enabled"] = true; // (1 or 0) - param["TakeImage"]["CamLenc"]["enabled"] = true; // lens correction (1 or 0) - param["TakeImage"]["CamHmirror"]["enabled"] = true; // (0 or 1) flip horizontally - param["TakeImage"]["CamVflip"]["enabled"] = true; // Invert image (0 or 1) - param["TakeImage"]["CamDcw"]["enabled"] = true; // downsize enable (1 or 0) - param["TakeImage"]["CamZoom"]["enabled"] = true; - param["TakeImage"]["CamZoomOffsetX"]["enabled"] = true; - param["TakeImage"]["CamZoomOffsetY"]["enabled"] = true; - param["TakeImage"]["CamZoomSize"]["enabled"] = true; - param["TakeImage"]["LEDIntensity"]["enabled"] = true; - - if (!param["System"]["Tooltip"]["found"]) { - param["System"]["Tooltip"]["found"] = true; - param["System"]["Tooltip"].value1 = 'true'; - } - - if (!param["Alignment"]["InitialRotate"]["found"]) { - param["Alignment"]["InitialRotate"]["found"] = true; - param["Alignment"]["InitialRotate"].value1 = 'false'; - } - - if (!param["TakeImage"]["WaitBeforeTakingPicture"]["found"]) { - param["TakeImage"]["WaitBeforeTakingPicture"]["found"] = true; - param["TakeImage"]["WaitBeforeTakingPicture"].value1 = '5'; - } - if (!param["TakeImage"]["CamGainceiling"]["found"]) { - param["TakeImage"]["CamGainceiling"]["found"] = true; - param["TakeImage"]["CamGainceiling"].value1 = '1'; - } - if (!param["TakeImage"]["CamQuality"]["found"]) { - param["TakeImage"]["CamQuality"]["found"] = true; - param["TakeImage"]["CamQuality"].value1 = '10'; - } - if (!param["TakeImage"]["CamBrightness"]["found"]) { - param["TakeImage"]["CamBrightness"]["found"] = true; - param["TakeImage"]["CamBrightness"].value1 = '0'; - } - if (!param["TakeImage"]["CamContrast"]["found"]) { - param["TakeImage"]["CamContrast"]["found"] = true; - param["TakeImage"]["CamContrast"].value1 = '0'; - } - if (!param["TakeImage"]["CamSaturation"]["found"]) { - param["TakeImage"]["CamSaturation"]["found"] = true; - param["TakeImage"]["CamSaturation"].value1 = '0'; - } - if (!param["TakeImage"]["CamSharpness"]["found"]) { - param["TakeImage"]["CamSharpness"]["found"] = true; - param["TakeImage"]["CamSharpness"].value1 = '0'; - } - if (!param["TakeImage"]["CamAutoSharpness"]["found"]) { - param["TakeImage"]["CamAutoSharpness"]["found"] = true; - param["TakeImage"]["CamAutoSharpness"].value1 = 'false'; - } - if (!param["TakeImage"]["CamSpecialEffect"]["found"]) { - param["TakeImage"]["CamSpecialEffect"]["found"] = true; - param["TakeImage"]["CamSpecialEffect"].value1 = 'no_effect'; - } - if (!param["TakeImage"]["CamWbMode"]["found"]) { - param["TakeImage"]["CamWbMode"]["found"] = true; - param["TakeImage"]["CamWbMode"].value1 = 'auto'; - } - if (!param["TakeImage"]["CamAwb"]["found"]) { - param["TakeImage"]["CamAwb"]["found"] = true; - param["TakeImage"]["CamAwb"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAwbGain"]["found"]) { - param["TakeImage"]["CamAwbGain"]["found"] = true; - param["TakeImage"]["CamAwbGain"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAec"]["found"]) { - param["TakeImage"]["CamAec"]["found"] = true; - param["TakeImage"]["CamAec"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAec2"]["found"]) { - param["TakeImage"]["CamAec2"]["found"] = true; - param["TakeImage"]["CamAec2"].value1 = 'false'; - } - if (!param["TakeImage"]["CamAeLevel"]["found"]) { - param["TakeImage"]["CamAeLevel"]["found"] = true; - param["TakeImage"]["CamAeLevel"].value1 = '0'; - } - if (!param["TakeImage"]["CamAecValue"]["found"]) { - param["TakeImage"]["CamAecValue"]["found"] = true; - param["TakeImage"]["CamAecValue"].value1 = '168'; - } - if (!param["TakeImage"]["CamAgc"]["found"]) { - param["TakeImage"]["CamAgc"]["found"] = true; - param["TakeImage"]["CamAgc"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAgcGain"]["found"]) { - param["TakeImage"]["CamAgcGain"]["found"] = true; - param["TakeImage"]["CamAgcGain"].value1 = '0'; - } - if (!param["TakeImage"]["CamBpc"]["found"]) { - param["TakeImage"]["CamBpc"]["found"] = true; - param["TakeImage"]["CamBpc"].value1 = 'false'; - } - if (!param["TakeImage"]["CamWpc"]["found"]) { - param["TakeImage"]["CamWpc"]["found"] = true; - param["TakeImage"]["CamWpc"].value1 = 'true'; - } - if (!param["TakeImage"]["CamRawGma"]["found"]) { - param["TakeImage"]["CamRawGma"]["found"] = true; - param["TakeImage"]["CamRawGma"].value1 = 'true'; - } - if (!param["TakeImage"]["CamLenc"]["found"]) { - param["TakeImage"]["CamLenc"]["found"] = true; - param["TakeImage"]["CamLenc"].value1 = 'true'; - } - if (!param["TakeImage"]["CamHmirror"]["found"]) { - param["TakeImage"]["CamHmirror"]["found"] = true; - param["TakeImage"]["CamHmirror"].value1 = 'false'; - } - if (!param["TakeImage"]["CamVflip"]["found"]) { - param["TakeImage"]["CamVflip"]["found"] = true; - param["TakeImage"]["CamVflip"].value1 = 'false'; - } - if (!param["TakeImage"]["CamDcw"]["found"]) { - param["TakeImage"]["CamDcw"]["found"] = true; - param["TakeImage"]["CamDcw"].value1 = 'true'; - } - if (!param["TakeImage"]["CamZoom"]["found"]) { - param["TakeImage"]["CamZoom"]["found"] = true; - param["TakeImage"]["CamZoom"].value1 = 'false'; - } - if (!param["TakeImage"]["CamZoomOffsetX"]["found"]) { - param["TakeImage"]["CamZoomOffsetX"]["found"] = true; - param["TakeImage"]["CamZoomOffsetX"].value1 = '0'; - } - if (!param["TakeImage"]["CamZoomOffsetY"]["found"]) { - param["TakeImage"]["CamZoomOffsetY"]["found"] = true; - param["TakeImage"]["CamZoomOffsetY"].value1 = '0'; - } - if (!param["TakeImage"]["CamZoomSize"]["found"]) { - param["TakeImage"]["CamZoomSize"]["found"] = true; - param["TakeImage"]["CamZoomSize"].value1 = '0'; - } - if (!param["TakeImage"]["LEDIntensity"]["found"]) { - param["TakeImage"]["LEDIntensity"]["found"] = true; - param["TakeImage"]["LEDIntensity"].value1 = '50'; - } - - return param; -} - - -function getConfigParameters() { - return param; -} - - -function WriteConfigININew() { - // Cleanup empty NUMBERS - for (var j = 0; j < NUMBERS.length; ++j) { - if ((NUMBERS[j]["digit"].length + NUMBERS[j]["analog"].length) == 0) { - NUMBERS.splice(j, 1); - } - } - - config_split = new Array(0); - - for (var cat in param) { - text = "[" + cat + "]"; - - if (!category[cat]["enabled"]) { - text = ";" + text; - } - - config_split.push(text); - - for (var name in param[cat]) { - if (param[cat][name]["Numbers"]) { - for (_num in NUMBERS) { - text = NUMBERS[_num]["name"] + "." + name; - - var text = text + " =" - - for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { - if (!(typeof NUMBERS[_num][cat][name]["value"+j] == 'undefined')) { - text = text + " " + NUMBERS[_num][cat][name]["value"+j]; - } - } - - if (!NUMBERS[_num][cat][name]["enabled"]) { - text = ";" + text; - } - - config_split.push(text); - } - } - else { - var text = name + " =" - - for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { - if (!(typeof param[cat][name]["value"+j] == 'undefined')) { - text = text + " " + param[cat][name]["value"+j]; - } - } - - if (!param[cat][name]["enabled"]) { - text = ";" + text; - } - - config_split.push(text); - } - } - - if (cat == "Digits") { - for (var _roi in NUMBERS) { - if (NUMBERS[_roi]["digit"].length > 0) { - for (var _roiddet in NUMBERS[_roi]["digit"]) { - text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["digit"][_roiddet]["name"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["x"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["y"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dx"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dy"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["CCW"]; - config_split.push(text); - } - } - } - } - - if (cat == "Analog") { - for (var _roi in NUMBERS) { - if (NUMBERS[_roi]["analog"].length > 0) { - for (var _roiddet in NUMBERS[_roi]["analog"]) { - text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["analog"][_roiddet]["name"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["x"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["y"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dx"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dy"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["CCW"]; - config_split.push(text); - } - } - } - } - - if (cat == "Alignment") { - for (var _roi in REFERENCES) { - text = REFERENCES[_roi]["name"]; - text = text + " " + REFERENCES[_roi]["x"]; - text = text + " " + REFERENCES[_roi]["y"]; - config_split.push(text); - } - } - - config_split.push(""); - } -} - - -function isCommented(input) { - let isComment = false; - - if (input.charAt(0) == ';') { - isComment = true; - input = input.substr(1, input.length-1); - } - - return [isComment, input]; -} - - -function SaveConfigToServer(_domainname){ - // leere Zeilen am Ende löschen - var zw = config_split.length - 1; - - while (config_split[zw] == "") { - config_split.pop(); - } - - var config_gesamt = ""; - - for (var i = 0; i < config_split.length; ++i) - { - config_gesamt = config_gesamt + config_split[i] + "\n"; - } - - FileDeleteOnServer("/config/config.ini", _domainname); - FileSendContent(config_gesamt, "/config/config.ini", _domainname); -} - - -function getConfig() { - return config_gesamt; -} - - -function getConfigCategory() { - return category; -} - - -function ExtractROIs(_aktline, _type){ - var linesplit = ZerlegeZeile(_aktline); - abc = getNUMBERS(linesplit[0], _type); - abc["pos_ref"] = _aktline; - abc["x"] = linesplit[1]; - abc["y"] = linesplit[2]; - abc["dx"] = linesplit[3]; - abc["dy"] = linesplit[4]; - abc["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); - abc["CCW"] = "false"; - - if (linesplit.length >= 6) { - abc["CCW"] = linesplit[5]; - } -} - - -function getNUMBERS(_name, _type, _create = true) { - _pospunkt = _name.indexOf ("."); - - if (_pospunkt > -1) { - _digit = _name.substring(0, _pospunkt); - _roi = _name.substring(_pospunkt+1); - } - else { - _digit = "default"; - _roi = _name; - } - - _ret = -1; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _digit) { - _ret = NUMBERS[i]; - } - } - - if (!_create) { // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück - return _ret; - } - - if (_ret == -1) { - _ret = new Object(); - _ret["name"] = _digit; - _ret['digit'] = new Array(); - _ret['analog'] = new Array(); - - for (_cat in param) { - for (_param in param[_cat]) { - if (param[_cat][_param]["Numbers"] == true){ - if (typeof _ret[_cat] == 'undefined') { - _ret[_cat] = new Object(); - } - - _ret[_cat][_param] = new Object(); - _ret[_cat][_param]["found"] = false; - _ret[_cat][_param]["enabled"] = false; - _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; - } - } - } - - NUMBERS.push(_ret); - } - - if (typeof _type == 'undefined') { // muss schon existieren !!! - also erst nach Digits / Analog aufrufen - return _ret; - } - - neuroi = new Object(); - neuroi["name"] = _roi; - _ret[_type].push(neuroi); - - return neuroi; -} - - -function CopyReferenceToImgTmp(_domainname) { - for (index = 0; index < 2; ++index) { - _filenamevon = REFERENCES[index]["name"]; - _filenamenach = _filenamevon.replace("/config/", "/img_tmp/"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - } -} - - -function GetReferencesInfo(){ - return REFERENCES; -} - - -function UpdateConfigReferences(_domainname){ - for (var index = 0; index < 2; ++index) { - _filenamenach = REFERENCES[index]["name"]; - _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - } -} - - -function UpdateConfigReference(_anzneueref, _domainname){ - var index = 0; - - if (_anzneueref == 1) { - index = 0; - } - - else if (_anzneueref == 2) { - index = 1; - } - - _filenamenach = REFERENCES[index]["name"]; - _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); - - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); -} - - -function getNUMBERInfo(){ - return NUMBERS; -} - - -function RenameNUMBER(_alt, _neu){ - if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0)) { - return "Number sequence name must not contain , . \" or a space"; - } - - index = -1; - found = false; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _alt) { - index = i; - } - - if (NUMBERS[i]["name"] == _neu) { - found = true; - } - } - - if (found) { - return "Number sequence name is already existing, please choose another name"; - } - - NUMBERS[index]["name"] = _neu; - - return ""; -} - - -function DeleteNUMBER(_delete){ - if (NUMBERS.length == 1) { - return "One number sequence is mandatory. Therefore this cannot be deleted" - } - - index = -1; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _delete) { - index = i; - } - } - - if (index > -1) { - NUMBERS.splice(index, 1); - } - - return ""; -} - - -function CreateNUMBER(_numbernew){ - found = false; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _numbernew) { - found = true; - } - } - - if (found) { - return "Number sequence name is already existing, please choose another name"; - } - - _ret = new Object(); - _ret["name"] = _numbernew; - _ret['digit'] = new Array(); - _ret['analog'] = new Array(); - - for (_cat in param) { - for (_param in param[_cat]) { - if (param[_cat][_param]["Numbers"] == true) { - if (typeof (_ret[_cat]) === "undefined") { - _ret[_cat] = new Object(); - } - - _ret[_cat][_param] = new Object(); - - if (param[_cat][_param]["defaultValue"] === "") { - _ret[_cat][_param]["found"] = false; - _ret[_cat][_param]["enabled"] = false; - } - else { - _ret[_cat][_param]["found"] = true; - _ret[_cat][_param]["enabled"] = true; - _ret[_cat][_param]["value1"] = param[_cat][_param]["defaultValue"]; - - } - - _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; - } - } - } - - NUMBERS.push(_ret); - return ""; -} - - -function getROIInfo(_typeROI, _number){ - index = -1; - - for (var i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _number) { - index = i; - } - } - - if (index != -1) { - return NUMBERS[index][_typeROI]; - } - else { - return ""; - } -} - - -function RenameROI(_number, _type, _alt, _neu){ - if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) || (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || (_neu.includes("\""))) { - return "ROI name must not contain . : , ; = \" or space"; - } - - index = -1; - found = false; - _indexnumber = -1; - - for (j = 0; j < NUMBERS.length; ++j) { - if (NUMBERS[j]["name"] == _number) { - _indexnumber = j; - } - } - - if (_indexnumber == -1) { - return "Number sequence not existing. ROI cannot be renamed" - } - - for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { - if (NUMBERS[_indexnumber][_type][i]["name"] == _alt) { - index = i; - } - - if (NUMBERS[_indexnumber][_type][i]["name"] == _neu) { - found = true; - } - } - - if (found) { - return "ROI name is already existing, please choose another name"; - } - - NUMBERS[_indexnumber][_type][index]["name"] = _neu; - - return ""; -} - - -function DeleteNUMBER(_delte) { - if (NUMBERS.length == 1) { - return "The last number cannot be deleted" - } - - index = -1; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _delte) { - index = i; - } - } - - if (index > -1) { - NUMBERS.splice(index, 1); - } - - return ""; -} - - -function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){ - _indexnumber = -1; - - for (j = 0; j < NUMBERS.length; ++j) { - if (NUMBERS[j]["name"] == _number) { - _indexnumber = j; - } - } - - if (_indexnumber == -1) { - return "Number sequence not existing. ROI cannot be created" - } - - found = false; - - for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { - if (NUMBERS[_indexnumber][_type][i]["name"] == _roinew) { - found = true; - } - } - - if (found) { - return "ROI name is already existing, please choose another name"; - } - - _ret = new Object(); - _ret["name"] = _roinew; - _ret["x"] = _x; - _ret["y"] = _y; - _ret["dx"] = _dx; - _ret["dy"] = _dy; - _ret["ar"] = _dx / _dy; - _ret["CCW"] = _CCW; - - NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret); - - return ""; -} +var config_gesamt = ""; +var config_split = []; +var param = []; +var category; +var ref = new Array(2); +var NUMBERS = new Array(0); +var REFERENCES = new Array(0); + + +function getNUMBERSList() { + _domainname = getDomainname(); + var namenumberslist = ""; + + var xhttp = new XMLHttpRequest(); + + xhttp.addEventListener('load', function(event) { + if (xhttp.status >= 200 && xhttp.status < 300) { + namenumberslist = xhttp.responseText; + } + else { + console.warn(request.statusText, request.responseText); + } + }); + + try { + url = _domainname + '/editflow?task=namenumbers'; + xhttp.open("GET", url, false); + xhttp.send(); + } catch (error) {} + + namenumberslist = namenumberslist.split("\t"); + + return namenumberslist; +} + + +function getDATAList() { + _domainname = getDomainname(); + datalist = ""; + + var xhttp = new XMLHttpRequest(); + + xhttp.addEventListener('load', function(event) { + if (xhttp.status >= 200 && xhttp.status < 300) { + datalist = xhttp.responseText; + } + else { + console.warn(request.statusText, request.responseText); + } + }); + + try { + url = _domainname + '/editflow?task=data'; + xhttp.open("GET", url, false); + xhttp.send(); + } catch (error) {} + + datalist = datalist.split("\t"); + datalist.pop(); + datalist.sort(); + + return datalist; +} + + +function getTFLITEList() { + _domainname = getDomainname(); + tflitelist = ""; + + var xhttp = new XMLHttpRequest(); + + xhttp.addEventListener('load', function(event) { + if (xhttp.status >= 200 && xhttp.status < 300) { + tflitelist = xhttp.responseText; + } + else { + console.warn(request.statusText, request.responseText); + } + }); + + try { + url = _domainname + '/editflow?task=tflite'; + xhttp.open("GET", url, false); + xhttp.send(); + } catch (error) {} + + tflitelist = tflitelist.split("\t"); + tflitelist.sort(); + + return tflitelist; +} + + +function ParseConfig() { + config_split = config_gesamt.split("\n"); + var aktline = 0; + + param = new Object(); + category = new Object(); + + var catname = "TakeImage"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "RawImagesLocation"); + ParamAddValue(param, catname, "RawImagesRetention"); + ParamAddValue(param, catname, "WaitBeforeTakingPicture"); + ParamAddValue(param, catname, "CamGainceiling"); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + ParamAddValue(param, catname, "CamQuality"); // 0 - 63 + ParamAddValue(param, catname, "CamBrightness"); // (-2 to 2) - set brightness + ParamAddValue(param, catname, "CamContrast"); //-2 - 2 + ParamAddValue(param, catname, "CamSaturation"); //-2 - 2 + ParamAddValue(param, catname, "CamSharpness"); //-2 - 2 + ParamAddValue(param, catname, "CamAutoSharpness"); // (1 or 0) + ParamAddValue(param, catname, "CamSpecialEffect"); // 0 - 6 + ParamAddValue(param, catname, "CamWbMode"); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + ParamAddValue(param, catname, "CamAwb"); // white balance enable (0 or 1) + ParamAddValue(param, catname, "CamAwbGain"); // Auto White Balance enable (0 or 1) + ParamAddValue(param, catname, "CamAec"); // auto exposure off (1 or 0) + ParamAddValue(param, catname, "CamAec2"); // automatic exposure sensor (0 or 1) + ParamAddValue(param, catname, "CamAeLevel"); // auto exposure levels (-2 to 2) + ParamAddValue(param, catname, "CamAecValue"); // set exposure manually (0-1200) + ParamAddValue(param, catname, "CamAgc"); // auto gain off (1 or 0) + ParamAddValue(param, catname, "CamAgcGain"); // set gain manually (0 - 30) + ParamAddValue(param, catname, "CamBpc"); // black pixel correction + ParamAddValue(param, catname, "CamWpc"); // white pixel correction + ParamAddValue(param, catname, "CamRawGma"); // (1 or 0) + ParamAddValue(param, catname, "CamLenc"); // lens correction (1 or 0) + ParamAddValue(param, catname, "CamHmirror"); // (0 or 1) flip horizontally + ParamAddValue(param, catname, "CamVflip"); // Invert image (0 or 1) + ParamAddValue(param, catname, "CamDcw"); // downsize enable (1 or 0) + ParamAddValue(param, catname, "CamDenoise"); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + ParamAddValue(param, catname, "CamZoom"); + ParamAddValue(param, catname, "CamZoomOffsetX"); + ParamAddValue(param, catname, "CamZoomOffsetY"); + ParamAddValue(param, catname, "CamZoomSize"); + ParamAddValue(param, catname, "LEDIntensity"); + ParamAddValue(param, catname, "Demo"); + + var catname = "Alignment"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "InitialRotate"); + ParamAddValue(param, catname, "SearchFieldX"); + ParamAddValue(param, catname, "SearchFieldY"); + ParamAddValue(param, catname, "AlignmentAlgo"); + + var catname = "Digits"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Model"); + ParamAddValue(param, catname, "CNNGoodThreshold", 1); + ParamAddValue(param, catname, "ROIImagesLocation"); + ParamAddValue(param, catname, "ROIImagesRetention"); + + var catname = "Analog"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Model"); + ParamAddValue(param, catname, "ROIImagesLocation"); + ParamAddValue(param, catname, "ROIImagesRetention"); + + var catname = "PostProcessing"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "DecimalShift", 1, true); + ParamAddValue(param, catname, "AnalogDigitalTransitionStart", 1, true); + // ParamAddValue(param, catname, "PreValueUse", 1, true, "true"); + ParamAddValue(param, catname, "PreValueUse"); + ParamAddValue(param, catname, "PreValueAgeStartup"); + ParamAddValue(param, catname, "AllowNegativeRates", 1, true, "false"); + ParamAddValue(param, catname, "MaxRateValue", 1, true); + ParamAddValue(param, catname, "MaxRateType", 1, true); + ParamAddValue(param, catname, "ExtendedResolution", 1, true, "false"); + ParamAddValue(param, catname, "IgnoreLeadingNaN", 1, true, "false"); + // ParamAddValue(param, catname, "IgnoreAllNaN", 1, true, "false"); + ParamAddValue(param, catname, "ErrorMessage"); + ParamAddValue(param, catname, "CheckDigitIncreaseConsistency"); + + var catname = "MQTT"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "MainTopic", 1, false); + ParamAddValue(param, catname, "ClientID"); + ParamAddValue(param, catname, "user"); + ParamAddValue(param, catname, "password"); + ParamAddValue(param, catname, "RetainMessages"); + ParamAddValue(param, catname, "HomeassistantDiscovery"); + ParamAddValue(param, catname, "MeterType"); + ParamAddValue(param, catname, "CACert"); + ParamAddValue(param, catname, "ClientCert"); + ParamAddValue(param, catname, "ClientKey"); + + var catname = "InfluxDB"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "Database"); +// ParamAddValue(param, catname, "Measurement"); + ParamAddValue(param, catname, "user"); + ParamAddValue(param, catname, "password"); + ParamAddValue(param, catname, "Measurement", 1, true); + ParamAddValue(param, catname, "Field", 1, true); + + var catname = "InfluxDBv2"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "Bucket"); +// ParamAddValue(param, catname, "Measurement"); + ParamAddValue(param, catname, "Org"); + ParamAddValue(param, catname, "Token"); + ParamAddValue(param, catname, "Measurement", 1, true); + ParamAddValue(param, catname, "Field", 1, true); + + var catname = "GPIO"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "IO0", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO1", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO3", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO4", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO12", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO13", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "LEDType"); + ParamAddValue(param, catname, "LEDNumbers"); + ParamAddValue(param, catname, "LEDColor", 3); + // Default Values, um abwärtskompatiblität zu gewährleisten + param[catname]["LEDType"]["value1"] = "WS2812"; + param[catname]["LEDNumbers"]["value1"] = "2"; + param[catname]["LEDColor"]["value1"] = "50"; + param[catname]["LEDColor"]["value2"] = "50"; + param[catname]["LEDColor"]["value3"] = "50"; + + var catname = "AutoTimer"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "AutoStart"); + ParamAddValue(param, catname, "Interval"); + + var catname = "DataLogging"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "DataLogActive"); + ParamAddValue(param, catname, "DataFilesRetention"); + + var catname = "Debug"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "LogLevel"); + ParamAddValue(param, catname, "LogfilesRetention"); + + var catname = "System"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Tooltip"); + ParamAddValue(param, catname, "TimeZone"); + ParamAddValue(param, catname, "TimeServer"); + ParamAddValue(param, catname, "Hostname"); + ParamAddValue(param, catname, "RSSIThreshold"); + ParamAddValue(param, catname, "CPUFrequency"); + ParamAddValue(param, catname, "SetupMode"); + + while (aktline < config_split.length){ + for (var cat in category) { + zw = cat.toUpperCase(); + zw1 = "[" + zw + "]"; + zw2 = ";[" + zw + "]"; + + if ((config_split[aktline].trim().toUpperCase() == zw1) || (config_split[aktline].trim().toUpperCase() == zw2)) { + if (config_split[aktline].trim().toUpperCase() == zw1) { + category[cat]["enabled"] = true; + } + + category[cat]["found"] = true; + category[cat]["line"] = aktline; + aktline = ParseConfigParamAll(aktline, cat); + continue; + } + } + + aktline++; + } + + // Make the downward compatiblity with DataLogging + if (category["DataLogging"]["found"] == false) { + category["DataLogging"]["found"] = true; + category["DataLogging"]["enabled"] = true; + + param["DataLogging"]["DataLogActive"]["found"] = true; + param["DataLogging"]["DataLogActive"]["enabled"] = true; + param["DataLogging"]["DataLogActive"]["value1"] = "true"; + + param["DataLogging"]["DataFilesRetention"]["found"] = true; + param["DataLogging"]["DataFilesRetention"]["enabled"] = true; + param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; + } + + if (category["DataLogging"]["enabled"] == false) { + category["DataLogging"]["enabled"] = true + } + + if (param["DataLogging"]["DataLogActive"]["enabled"] == false && param["DataLogging"]["DataLogActive"]["value1"] == "") { + param["DataLogging"]["DataLogActive"]["found"] = true; + param["DataLogging"]["DataLogActive"]["enabled"] = true; + param["DataLogging"]["DataLogActive"]["value1"] = "true"; + } + + if (param["DataLogging"]["DataFilesRetention"]["enabled"] == false && param["DataLogging"]["DataFilesRetention"]["value1"] == "") { + param["DataLogging"]["DataFilesRetention"]["found"] = true; + param["DataLogging"]["DataFilesRetention"]["enabled"] = true; + param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; + } + + // Downward compatibility: Create RSSIThreshold if not available + if (param["System"]["RSSIThreshold"]["found"] == false) { + param["System"]["RSSIThreshold"]["found"] = true; + param["System"]["RSSIThreshold"]["enabled"] = false; + param["System"]["RSSIThreshold"]["value1"] = "0"; + } +} + + +function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _defaultValue = "", _checkRegExList = null) { + param[_cat][_param] = new Object(); + param[_cat][_param]["found"] = false; + param[_cat][_param]["enabled"] = false; + param[_cat][_param]["line"] = -1; + param[_cat][_param]["anzParam"] = _anzParam; + param[_cat][_param]["defaultValue"] = _defaultValue; + param[_cat][_param]["Numbers"] = _isNUMBER; + param[_cat][_param].checkRegExList = _checkRegExList; +}; + + +function ParseConfigParamAll(_aktline, _catname) { + ++_aktline; + + while ((_aktline < config_split.length) && !(config_split[_aktline][0] == "[") && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { + var _input = config_split[_aktline]; + let [isCom, input] = isCommented(_input); + var linesplit = ZerlegeZeile(input); + ParamExtractValueAll(param, linesplit, _catname, _aktline, isCom); + + if (!isCom && (linesplit.length >= 5) && (_catname == 'Digits')) { + ExtractROIs(input, "digit"); + } + + if (!isCom && (linesplit.length >= 5) && (_catname == 'Analog')) { + ExtractROIs(input, "analog"); + } + + if (!isCom && (linesplit.length == 3) && (_catname == 'Alignment')) { + _newref = new Object(); + _newref["name"] = linesplit[0]; + _newref["x"] = linesplit[1]; + _newref["y"] = linesplit[2]; + REFERENCES.push(_newref); + } + + ++_aktline; + } + + return _aktline; +} + + +function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _iscom, _anzvalue = 1) { + if ((_linesplit[0].toUpperCase() == _paramname.toUpperCase()) && (_linesplit.length > _anzvalue)) { + _param[_catname][_paramname]["found"] = true; + _param[_catname][_paramname]["enabled"] = !_iscom; + _param[_catname][_paramname]["line"] = _aktline; + _param[_catname][_paramname]["anzpara"] = _anzvalue; + + for (var j = 1; j <= _anzvalue; ++j) { + _param[_catname][_paramname]["value"+j] = _linesplit[j]; + } + } +} + + +function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom) { + for (var paramname in _param[_catname]) { + _AktROI = "default"; + _AktPara = _linesplit[0]; + _pospunkt = _AktPara.indexOf ("."); + + if (_pospunkt > -1) { + _AktROI = _AktPara.substring(0, _pospunkt); + _AktPara = _AktPara.substring(_pospunkt+1); + } + + if (_AktPara.toUpperCase() == paramname.toUpperCase()) { + while (_linesplit.length <= _param[_catname][paramname]["anzParam"]) { + _linesplit.push(""); + } + + _param[_catname][paramname]["found"] = true; + _param[_catname][paramname]["enabled"] = !_iscom; + _param[_catname][paramname]["line"] = _aktline; + + if (_param[_catname][paramname]["Numbers"] == true) { // möglicher Multiusage + abc = getNUMBERS(_linesplit[0]); + abc[_catname][paramname] = new Object; + abc[_catname][paramname]["found"] = true; + abc[_catname][paramname]["enabled"] = !_iscom; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + abc[_catname][paramname]["value"+j] = _linesplit[j]; + } + + if (abc["name"] == "default") { + for (_num in NUMBERS) { // wert mit Default belegen + if (NUMBERS[_num][_catname][paramname]["found"] == false) { + NUMBERS[_num][_catname][paramname]["found"] = true; + NUMBERS[_num][_catname][paramname]["enabled"] = !_iscom; + NUMBERS[_num][_catname][paramname]["line"] = _aktline; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + NUMBERS[_num][_catname][paramname]["value"+j] = _linesplit[j]; + } + } + } + } + } + else { + _param[_catname][paramname]["found"] = true; + _param[_catname][paramname]["enabled"] = !_iscom; + _param[_catname][paramname]["line"] = _aktline; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + _param[_catname][paramname]["value"+j] = _linesplit[j]; + } + } + } + } +} + + +function getCamConfig() { + ParseConfig(); + + param["System"]["Tooltip"]["enabled"] = true; + param["Alignment"]["InitialRotate"]["enabled"] = true; + + param["TakeImage"]["WaitBeforeTakingPicture"]["enabled"] = true; + param["TakeImage"]["CamGainceiling"]["enabled"] = true; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + param["TakeImage"]["CamQuality"]["enabled"] = true; // 0 - 63 + param["TakeImage"]["CamBrightness"]["enabled"] = true; // (-2 to 2) - set brightness + param["TakeImage"]["CamContrast"]["enabled"] = true; //-2 - 2 + param["TakeImage"]["CamSaturation"]["enabled"] = true; //-2 - 2 + param["TakeImage"]["CamSharpness"]["enabled"] = true; //-2 - 2 + param["TakeImage"]["CamAutoSharpness"]["enabled"] = true; //(1 or 0) + param["TakeImage"]["CamSpecialEffect"]["enabled"] = true; // 0 - 6 + param["TakeImage"]["CamWbMode"]["enabled"] = true; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + param["TakeImage"]["CamAwb"]["enabled"] = true; // white balance enable (0 or 1) + param["TakeImage"]["CamAwbGain"]["enabled"] = true; // Auto White Balance enable (0 or 1) + param["TakeImage"]["CamAec"]["enabled"] = true; // auto exposure off (1 or 0) + param["TakeImage"]["CamAec2"]["enabled"] = true; // automatic exposure sensor (0 or 1) + param["TakeImage"]["CamAeLevel"]["enabled"] = true; // auto exposure levels (-2 to 2) + param["TakeImage"]["CamAecValue"]["enabled"] = true; // set exposure manually (0-1200) + param["TakeImage"]["CamAgc"]["enabled"] = true; // auto gain off (1 or 0) + param["TakeImage"]["CamAgcGain"]["enabled"] = true; // set gain manually (0 - 30) + param["TakeImage"]["CamBpc"]["enabled"] = true; // black pixel correction + param["TakeImage"]["CamWpc"]["enabled"] = true; // white pixel correction + param["TakeImage"]["CamRawGma"]["enabled"] = true; // (1 or 0) + param["TakeImage"]["CamLenc"]["enabled"] = true; // lens correction (1 or 0) + param["TakeImage"]["CamHmirror"]["enabled"] = true; // (0 or 1) flip horizontally + param["TakeImage"]["CamVflip"]["enabled"] = true; // Invert image (0 or 1) + param["TakeImage"]["CamDcw"]["enabled"] = true; // downsize enable (1 or 0) + param["TakeImage"]["CamDenoise"]["enabled"] = true; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + param["TakeImage"]["CamZoom"]["enabled"] = true; + param["TakeImage"]["CamZoomOffsetX"]["enabled"] = true; + param["TakeImage"]["CamZoomOffsetY"]["enabled"] = true; + param["TakeImage"]["CamZoomSize"]["enabled"] = true; + param["TakeImage"]["LEDIntensity"]["enabled"] = true; + + if (!param["System"]["Tooltip"]["found"]) { + param["System"]["Tooltip"]["found"] = true; + param["System"]["Tooltip"].value1 = 'true'; + } + + if (!param["Alignment"]["InitialRotate"]["found"]) { + param["Alignment"]["InitialRotate"]["found"] = true; + param["Alignment"]["InitialRotate"].value1 = 'false'; + } + + if (!param["TakeImage"]["WaitBeforeTakingPicture"]["found"]) { + param["TakeImage"]["WaitBeforeTakingPicture"]["found"] = true; + param["TakeImage"]["WaitBeforeTakingPicture"].value1 = '5'; + } + if (!param["TakeImage"]["CamGainceiling"]["found"]) { + param["TakeImage"]["CamGainceiling"]["found"] = true; + param["TakeImage"]["CamGainceiling"].value1 = '1'; + } + if (!param["TakeImage"]["CamQuality"]["found"]) { + param["TakeImage"]["CamQuality"]["found"] = true; + param["TakeImage"]["CamQuality"].value1 = '10'; + } + if (!param["TakeImage"]["CamBrightness"]["found"]) { + param["TakeImage"]["CamBrightness"]["found"] = true; + param["TakeImage"]["CamBrightness"].value1 = '0'; + } + if (!param["TakeImage"]["CamContrast"]["found"]) { + param["TakeImage"]["CamContrast"]["found"] = true; + param["TakeImage"]["CamContrast"].value1 = '0'; + } + if (!param["TakeImage"]["CamSaturation"]["found"]) { + param["TakeImage"]["CamSaturation"]["found"] = true; + param["TakeImage"]["CamSaturation"].value1 = '0'; + } + if (!param["TakeImage"]["CamSharpness"]["found"]) { + param["TakeImage"]["CamSharpness"]["found"] = true; + param["TakeImage"]["CamSharpness"].value1 = '0'; + } + if (!param["TakeImage"]["CamAutoSharpness"]["found"]) { + param["TakeImage"]["CamAutoSharpness"]["found"] = true; + param["TakeImage"]["CamAutoSharpness"].value1 = 'false'; + } + if (!param["TakeImage"]["CamSpecialEffect"]["found"]) { + param["TakeImage"]["CamSpecialEffect"]["found"] = true; + param["TakeImage"]["CamSpecialEffect"].value1 = 'no_effect'; + } + if (!param["TakeImage"]["CamWbMode"]["found"]) { + param["TakeImage"]["CamWbMode"]["found"] = true; + param["TakeImage"]["CamWbMode"].value1 = 'auto'; + } + if (!param["TakeImage"]["CamAwb"]["found"]) { + param["TakeImage"]["CamAwb"]["found"] = true; + param["TakeImage"]["CamAwb"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAwbGain"]["found"]) { + param["TakeImage"]["CamAwbGain"]["found"] = true; + param["TakeImage"]["CamAwbGain"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAec"]["found"]) { + param["TakeImage"]["CamAec"]["found"] = true; + param["TakeImage"]["CamAec"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAec2"]["found"]) { + param["TakeImage"]["CamAec2"]["found"] = true; + param["TakeImage"]["CamAec2"].value1 = 'false'; + } + if (!param["TakeImage"]["CamAeLevel"]["found"]) { + param["TakeImage"]["CamAeLevel"]["found"] = true; + param["TakeImage"]["CamAeLevel"].value1 = '0'; + } + if (!param["TakeImage"]["CamAecValue"]["found"]) { + param["TakeImage"]["CamAecValue"]["found"] = true; + param["TakeImage"]["CamAecValue"].value1 = '168'; + } + if (!param["TakeImage"]["CamAgc"]["found"]) { + param["TakeImage"]["CamAgc"]["found"] = true; + param["TakeImage"]["CamAgc"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAgcGain"]["found"]) { + param["TakeImage"]["CamAgcGain"]["found"] = true; + param["TakeImage"]["CamAgcGain"].value1 = '0'; + } + if (!param["TakeImage"]["CamBpc"]["found"]) { + param["TakeImage"]["CamBpc"]["found"] = true; + param["TakeImage"]["CamBpc"].value1 = 'false'; + } + if (!param["TakeImage"]["CamWpc"]["found"]) { + param["TakeImage"]["CamWpc"]["found"] = true; + param["TakeImage"]["CamWpc"].value1 = 'true'; + } + if (!param["TakeImage"]["CamRawGma"]["found"]) { + param["TakeImage"]["CamRawGma"]["found"] = true; + param["TakeImage"]["CamRawGma"].value1 = 'true'; + } + if (!param["TakeImage"]["CamLenc"]["found"]) { + param["TakeImage"]["CamLenc"]["found"] = true; + param["TakeImage"]["CamLenc"].value1 = 'true'; + } + if (!param["TakeImage"]["CamHmirror"]["found"]) { + param["TakeImage"]["CamHmirror"]["found"] = true; + param["TakeImage"]["CamHmirror"].value1 = 'false'; + } + if (!param["TakeImage"]["CamVflip"]["found"]) { + param["TakeImage"]["CamVflip"]["found"] = true; + param["TakeImage"]["CamVflip"].value1 = 'false'; + } + if (!param["TakeImage"]["CamDcw"]["found"]) { + param["TakeImage"]["CamDcw"]["found"] = true; + param["TakeImage"]["CamDcw"].value1 = 'true'; + } + if (!param["TakeImage"]["CamDenoise"]["found"]) { + param["TakeImage"]["CamDenoise"]["found"] = true; + param["TakeImage"]["CamDenoise"].value1 = '0'; + } + if (!param["TakeImage"]["CamZoom"]["found"]) { + param["TakeImage"]["CamZoom"]["found"] = true; + param["TakeImage"]["CamZoom"].value1 = 'false'; + } + if (!param["TakeImage"]["CamZoomOffsetX"]["found"]) { + param["TakeImage"]["CamZoomOffsetX"]["found"] = true; + param["TakeImage"]["CamZoomOffsetX"].value1 = '0'; + } + if (!param["TakeImage"]["CamZoomOffsetY"]["found"]) { + param["TakeImage"]["CamZoomOffsetY"]["found"] = true; + param["TakeImage"]["CamZoomOffsetY"].value1 = '0'; + } + if (!param["TakeImage"]["CamZoomSize"]["found"]) { + param["TakeImage"]["CamZoomSize"]["found"] = true; + param["TakeImage"]["CamZoomSize"].value1 = '0'; + } + if (!param["TakeImage"]["LEDIntensity"]["found"]) { + param["TakeImage"]["LEDIntensity"]["found"] = true; + param["TakeImage"]["LEDIntensity"].value1 = '50'; + } + + return param; +} + + +function getConfigParameters() { + return param; +} + + +function WriteConfigININew() { + // Cleanup empty NUMBERS + for (var j = 0; j < NUMBERS.length; ++j) { + if ((NUMBERS[j]["digit"].length + NUMBERS[j]["analog"].length) == 0) { + NUMBERS.splice(j, 1); + } + } + + config_split = new Array(0); + + for (var cat in param) { + text = "[" + cat + "]"; + + if (!category[cat]["enabled"]) { + text = ";" + text; + } + + config_split.push(text); + + for (var name in param[cat]) { + if (param[cat][name]["Numbers"]) { + for (_num in NUMBERS) { + text = NUMBERS[_num]["name"] + "." + name; + + var text = text + " =" + + for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { + if (!(typeof NUMBERS[_num][cat][name]["value"+j] == 'undefined')) { + text = text + " " + NUMBERS[_num][cat][name]["value"+j]; + } + } + + if (!NUMBERS[_num][cat][name]["enabled"]) { + text = ";" + text; + } + + config_split.push(text); + } + } + else { + var text = name + " =" + + for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { + if (!(typeof param[cat][name]["value"+j] == 'undefined')) { + text = text + " " + param[cat][name]["value"+j]; + } + } + + if (!param[cat][name]["enabled"]) { + text = ";" + text; + } + + config_split.push(text); + } + } + + if (cat == "Digits") { + for (var _roi in NUMBERS) { + if (NUMBERS[_roi]["digit"].length > 0) { + for (var _roiddet in NUMBERS[_roi]["digit"]) { + text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["digit"][_roiddet]["name"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["x"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["y"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dx"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dy"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["CCW"]; + config_split.push(text); + } + } + } + } + + if (cat == "Analog") { + for (var _roi in NUMBERS) { + if (NUMBERS[_roi]["analog"].length > 0) { + for (var _roiddet in NUMBERS[_roi]["analog"]) { + text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["analog"][_roiddet]["name"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["x"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["y"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dx"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dy"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["CCW"]; + config_split.push(text); + } + } + } + } + + if (cat == "Alignment") { + for (var _roi in REFERENCES) { + text = REFERENCES[_roi]["name"]; + text = text + " " + REFERENCES[_roi]["x"]; + text = text + " " + REFERENCES[_roi]["y"]; + config_split.push(text); + } + } + + config_split.push(""); + } +} + + +function isCommented(input) { + let isComment = false; + + if (input.charAt(0) == ';') { + isComment = true; + input = input.substr(1, input.length-1); + } + + return [isComment, input]; +} + + +function SaveConfigToServer(_domainname){ + // leere Zeilen am Ende löschen + var zw = config_split.length - 1; + + while (config_split[zw] == "") { + config_split.pop(); + } + + var config_gesamt = ""; + + for (var i = 0; i < config_split.length; ++i) + { + config_gesamt = config_gesamt + config_split[i] + "\n"; + } + + FileDeleteOnServer("/config/config.ini", _domainname); + FileSendContent(config_gesamt, "/config/config.ini", _domainname); +} + + +function getConfig() { + return config_gesamt; +} + + +function getConfigCategory() { + return category; +} + + +function ExtractROIs(_aktline, _type){ + var linesplit = ZerlegeZeile(_aktline); + abc = getNUMBERS(linesplit[0], _type); + abc["pos_ref"] = _aktline; + abc["x"] = linesplit[1]; + abc["y"] = linesplit[2]; + abc["dx"] = linesplit[3]; + abc["dy"] = linesplit[4]; + abc["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); + abc["CCW"] = "false"; + + if (linesplit.length >= 6) { + abc["CCW"] = linesplit[5]; + } +} + + +function getNUMBERS(_name, _type, _create = true) { + _pospunkt = _name.indexOf ("."); + + if (_pospunkt > -1) { + _digit = _name.substring(0, _pospunkt); + _roi = _name.substring(_pospunkt+1); + } + else { + _digit = "default"; + _roi = _name; + } + + _ret = -1; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _digit) { + _ret = NUMBERS[i]; + } + } + + if (!_create) { // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück + return _ret; + } + + if (_ret == -1) { + _ret = new Object(); + _ret["name"] = _digit; + _ret['digit'] = new Array(); + _ret['analog'] = new Array(); + + for (_cat in param) { + for (_param in param[_cat]) { + if (param[_cat][_param]["Numbers"] == true){ + if (typeof _ret[_cat] == 'undefined') { + _ret[_cat] = new Object(); + } + + _ret[_cat][_param] = new Object(); + _ret[_cat][_param]["found"] = false; + _ret[_cat][_param]["enabled"] = false; + _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; + } + } + } + + NUMBERS.push(_ret); + } + + if (typeof _type == 'undefined') { // muss schon existieren !!! - also erst nach Digits / Analog aufrufen + return _ret; + } + + neuroi = new Object(); + neuroi["name"] = _roi; + _ret[_type].push(neuroi); + + return neuroi; +} + + +function CopyReferenceToImgTmp(_domainname) { + for (index = 0; index < 2; ++index) { + _filenamevon = REFERENCES[index]["name"]; + _filenamenach = _filenamevon.replace("/config/", "/img_tmp/"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + } +} + + +function GetReferencesInfo(){ + return REFERENCES; +} + + +function UpdateConfigReferences(_domainname){ + for (var index = 0; index < 2; ++index) { + _filenamenach = REFERENCES[index]["name"]; + _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + } +} + + +function UpdateConfigReference(_anzneueref, _domainname){ + var index = 0; + + if (_anzneueref == 1) { + index = 0; + } + + else if (_anzneueref == 2) { + index = 1; + } + + _filenamenach = REFERENCES[index]["name"]; + _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); + + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); +} + + +function getNUMBERInfo(){ + return NUMBERS; +} + + +function RenameNUMBER(_alt, _neu){ + if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0)) { + return "Number sequence name must not contain , . \" or a space"; + } + + index = -1; + found = false; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _alt) { + index = i; + } + + if (NUMBERS[i]["name"] == _neu) { + found = true; + } + } + + if (found) { + return "Number sequence name is already existing, please choose another name"; + } + + NUMBERS[index]["name"] = _neu; + + return ""; +} + + +function DeleteNUMBER(_delete){ + if (NUMBERS.length == 1) { + return "One number sequence is mandatory. Therefore this cannot be deleted" + } + + index = -1; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _delete) { + index = i; + } + } + + if (index > -1) { + NUMBERS.splice(index, 1); + } + + return ""; +} + + +function CreateNUMBER(_numbernew){ + found = false; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _numbernew) { + found = true; + } + } + + if (found) { + return "Number sequence name is already existing, please choose another name"; + } + + _ret = new Object(); + _ret["name"] = _numbernew; + _ret['digit'] = new Array(); + _ret['analog'] = new Array(); + + for (_cat in param) { + for (_param in param[_cat]) { + if (param[_cat][_param]["Numbers"] == true) { + if (typeof (_ret[_cat]) === "undefined") { + _ret[_cat] = new Object(); + } + + _ret[_cat][_param] = new Object(); + + if (param[_cat][_param]["defaultValue"] === "") { + _ret[_cat][_param]["found"] = false; + _ret[_cat][_param]["enabled"] = false; + } + else { + _ret[_cat][_param]["found"] = true; + _ret[_cat][_param]["enabled"] = true; + _ret[_cat][_param]["value1"] = param[_cat][_param]["defaultValue"]; + + } + + _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; + } + } + } + + NUMBERS.push(_ret); + return ""; +} + + +function getROIInfo(_typeROI, _number){ + index = -1; + + for (var i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _number) { + index = i; + } + } + + if (index != -1) { + return NUMBERS[index][_typeROI]; + } + else { + return ""; + } +} + + +function RenameROI(_number, _type, _alt, _neu){ + if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) || (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || (_neu.includes("\""))) { + return "ROI name must not contain . : , ; = \" or space"; + } + + index = -1; + found = false; + _indexnumber = -1; + + for (j = 0; j < NUMBERS.length; ++j) { + if (NUMBERS[j]["name"] == _number) { + _indexnumber = j; + } + } + + if (_indexnumber == -1) { + return "Number sequence not existing. ROI cannot be renamed" + } + + for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { + if (NUMBERS[_indexnumber][_type][i]["name"] == _alt) { + index = i; + } + + if (NUMBERS[_indexnumber][_type][i]["name"] == _neu) { + found = true; + } + } + + if (found) { + return "ROI name is already existing, please choose another name"; + } + + NUMBERS[_indexnumber][_type][index]["name"] = _neu; + + return ""; +} + + +function DeleteNUMBER(_delte) { + if (NUMBERS.length == 1) { + return "The last number cannot be deleted" + } + + index = -1; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _delte) { + index = i; + } + } + + if (index > -1) { + NUMBERS.splice(index, 1); + } + + return ""; +} + + +function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){ + _indexnumber = -1; + + for (j = 0; j < NUMBERS.length; ++j) { + if (NUMBERS[j]["name"] == _number) { + _indexnumber = j; + } + } + + if (_indexnumber == -1) { + return "Number sequence not existing. ROI cannot be created" + } + + found = false; + + for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { + if (NUMBERS[_indexnumber][_type][i]["name"] == _roinew) { + found = true; + } + } + + if (found) { + return "ROI name is already existing, please choose another name"; + } + + _ret = new Object(); + _ret["name"] = _roinew; + _ret["x"] = _x; + _ret["y"] = _y; + _ret["dx"] = _dx; + _ret["dy"] = _dy; + _ret["ar"] = _dx / _dy; + _ret["CCW"] = _CCW; + + NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret); + + return ""; +} From 33023c2fc047a91d76525e5afea84baa074801bf Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Tue, 14 May 2024 18:55:58 +1000 Subject: [PATCH 12/20] fix line endings to LF --- .../ClassControllCamera.cpp | 2356 +++--- .../ClassControllCamera.h | 220 +- .../ClassFlowTakeImage.cpp | 1050 +-- .../jomjol_flowcontroll/MainFlowControl.cpp | 3180 ++++----- .../jomjol_flowcontroll/MainFlowControl.h | 180 +- param-docs/expert-params.txt | 94 +- .../parameter-pages/TakeImage/CamAeLevel.md | 32 +- .../parameter-pages/TakeImage/CamDenoise.md | 24 +- sd-card/html/edit_config_template.html | 6346 ++++++++--------- sd-card/html/readconfigparam.js | 2292 +++--- 10 files changed, 7887 insertions(+), 7887 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index d85a6cd20..d101f7f1b 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -1,1178 +1,1178 @@ -#include "ClassControllCamera.h" -#include "ClassLogFile.h" - -#include -#include "driver/gpio.h" -#include "esp_timer.h" -#include "esp_log.h" - -#include "Helper.h" -#include "statusled.h" -#include "CImageBasis.h" - -#include "server_ota.h" -#include "server_GPIO.h" - -#include "../../include/defines.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "esp_camera.h" - -#include "driver/ledc.h" -#include "MainFlowControl.h" - -#include "ov2640_sharpness.h" - -#if (ESP_IDF_VERSION_MAJOR >= 5) -#include "soc/periph_defs.h" -#include "esp_private/periph_ctrl.h" -#include "soc/gpio_sig_map.h" -#include "soc/gpio_periph.h" -#include "soc/io_mux_reg.h" -#include "esp_rom_gpio.h" -#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio -#define gpio_matrix_in(a, b, c) esp_rom_gpio_connect_in_signal(a, b, c) -#define gpio_matrix_out(a, b, c, d) esp_rom_gpio_connect_out_signal(a, b, c, d) -#define ets_delay_us(a) esp_rom_delay_us(a) -#endif - -CCamera Camera; -camera_controll_config_temp_t CCstatus; - -static const char *TAG = "CAM"; - -/* Camera live stream */ -#define PART_BOUNDARY "123456789000000000000987654321" -static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; -static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; -static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; - -uint8_t *demoImage = NULL; // Buffer holding the demo image in bytes -#define DEMO_IMAGE_SIZE 30000 // Max size of demo image in bytes - -// Camera module bus communications frequency. -// Originally: config.xclk_freq_mhz = 20000000, but this lead to visual artifacts on many modules. -// See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. -#if !defined(XCLK_FREQ_MHZ) -// int xclk = 8; -int xclk = 20; // Orginal value -#else -int xclk = XCLK_FREQ_MHZ; -#endif - -static camera_config_t camera_config = { - .pin_pwdn = CAM_PIN_PWDN, - .pin_reset = CAM_PIN_RESET, - .pin_xclk = CAM_PIN_XCLK, - .pin_sscb_sda = CAM_PIN_SIOD, - .pin_sscb_scl = CAM_PIN_SIOC, - - .pin_d7 = CAM_PIN_D7, - .pin_d6 = CAM_PIN_D6, - .pin_d5 = CAM_PIN_D5, - .pin_d4 = CAM_PIN_D4, - .pin_d3 = CAM_PIN_D3, - .pin_d2 = CAM_PIN_D2, - .pin_d1 = CAM_PIN_D1, - .pin_d0 = CAM_PIN_D0, - .pin_vsync = CAM_PIN_VSYNC, - .pin_href = CAM_PIN_HREF, - .pin_pclk = CAM_PIN_PCLK, - - .xclk_freq_hz = (xclk * 1000000), - .ledc_timer = LEDC_TIMER_0, // LEDC timer to be used for generating XCLK - .ledc_channel = LEDC_CHANNEL_0, // LEDC channel to be used for generating XCLK - - .pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,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 - .jpeg_quality = 6, // 0-63 lower number means higher quality - .fb_count = 1, // if more than one, i2s runs in continuous mode. Use only with JPEG - .fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */ - .grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version -}; - -typedef struct -{ - httpd_req_t *req; - size_t len; -} jpg_chunking_t; - -CCamera::CCamera(void) -{ -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "CreateClassCamera"); -#endif - CCstatus.WaitBeforePicture = 2; - - ledc_init(); -} - -esp_err_t CCamera::InitCam(void) -{ - ESP_LOGD(TAG, "Init Camera"); - - CCstatus.ImageQuality = camera_config.jpeg_quality; - CCstatus.ImageFrameSize = camera_config.frame_size; - - // initialize the camera - esp_camera_deinit(); // De-init in case it was already initialized - esp_err_t err = esp_camera_init(&camera_config); - - if (err != ESP_OK) - { - ESP_LOGE(TAG, "Camera Init Failed"); - return err; - } - - CCstatus.CameraInitSuccessful = true; - - // Get a reference to the sensor - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - CCstatus.CamSensor_id = s->id.PID; - - // Dump camera module, warn for unsupported modules. - switch (CCstatus.CamSensor_id) - { - case OV2640_PID: - ESP_LOGI(TAG, "OV2640 camera module detected"); - break; - case OV3660_PID: - ESP_LOGI(TAG, "OV3660 camera module detected"); - break; - case OV5640_PID: - ESP_LOGI(TAG, "OV5640 camera module detected"); - break; - default: - ESP_LOGE(TAG, "Camera module is unknown and not properly supported!"); - CCstatus.CameraInitSuccessful = false; - } - } - - if (CCstatus.CameraInitSuccessful) - { - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - -bool CCamera::testCamera(void) -{ - bool success; - camera_fb_t *fb = esp_camera_fb_get(); - - if (fb) - { - success = true; - } - else - { - success = false; - } - - esp_camera_fb_return(fb); - - return success; -} - -void CCamera::ledc_init(void) -{ -#ifdef USE_PWM_LEDFLASH - // Prepare and then apply the LEDC PWM timer configuration - ledc_timer_config_t ledc_timer = {}; - - ledc_timer.speed_mode = LEDC_MODE; - ledc_timer.timer_num = LEDC_TIMER; - ledc_timer.duty_resolution = LEDC_DUTY_RES; - ledc_timer.freq_hz = LEDC_FREQUENCY; // Set output frequency at 5 kHz - ledc_timer.clk_cfg = LEDC_AUTO_CLK; - - ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); - - // Prepare and then apply the LEDC PWM channel configuration - ledc_channel_config_t ledc_channel = {}; - - ledc_channel.speed_mode = LEDC_MODE; - ledc_channel.channel = LEDC_CHANNEL; - ledc_channel.timer_sel = LEDC_TIMER; - ledc_channel.intr_type = LEDC_INTR_DISABLE; - ledc_channel.gpio_num = LEDC_OUTPUT_IO; - ledc_channel.duty = 0; // Set duty to 0% - ledc_channel.hpoint = 0; - // ledc_channel.flags.output_invert = LEDC_OUTPUT_INVERT; - - ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); -#endif -} - -void CCamera::SetLEDIntensity(float _intrel) -{ - _intrel = min(_intrel, (float)100); - _intrel = max(_intrel, (float)0); - _intrel = _intrel / 100; - CCstatus.ImageLedIntensity = (int)(_intrel * 8191); - ESP_LOGD(TAG, "Set led_intensity to %d of 8191", CCstatus.ImageLedIntensity); -} - -bool CCamera::getCameraInitSuccessful(void) -{ - return CCstatus.CameraInitSuccessful; -} - -esp_err_t CCamera::setSensorDatenFromCCstatus(void) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - s->set_framesize(s, CCstatus.ImageFrameSize); - s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - - s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 - - s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 - s->set_contrast(s, CCstatus.ImageContrast); // -2 to 2 - s->set_saturation(s, CCstatus.ImageSaturation); // -2 to 2 - // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 - SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); - - s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable - s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 - s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 - - s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable - - s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable - s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 - - s->set_bpc(s, CCstatus.ImageBpc); // 0 = disable , 1 = enable - s->set_wpc(s, CCstatus.ImageWpc); // 0 = disable , 1 = enable - - s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable - - s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable - s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable - - s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable - - s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - s->set_awb_gain(s, CCstatus.ImageAwbGain); // 0 = disable , 1 = enable - s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable - - s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - // special_effect muß als Letztes gesetzt werden, sonst geht es nicht - s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) - - TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; - vTaskDelay(xDelay2); - - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - -esp_err_t CCamera::getSensorDatenToCCstatus(void) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - CCstatus.CamSensor_id = s->id.PID; - - CCstatus.ImageFrameSize = (framesize_t)s->status.framesize; - CCstatus.ImageGainceiling = (gainceiling_t)s->status.gainceiling; - - CCstatus.ImageQuality = s->status.quality; - CCstatus.ImageBrightness = s->status.brightness; - CCstatus.ImageContrast = s->status.contrast; - CCstatus.ImageSaturation = s->status.saturation; - // CCstatus.ImageSharpness = s->status.sharpness; // gibt -1 zurück, da es nicht unterstützt wird - CCstatus.ImageWbMode = s->status.wb_mode; - CCstatus.ImageAwb = s->status.awb; - CCstatus.ImageAwbGain = s->status.awb_gain; - CCstatus.ImageAec = s->status.aec; - CCstatus.ImageAec2 = s->status.aec2; - CCstatus.ImageAeLevel = s->status.ae_level; - CCstatus.ImageAecValue = s->status.aec_value; - CCstatus.ImageAgc = s->status.agc; - CCstatus.ImageAgcGain = s->status.agc_gain; - CCstatus.ImageBpc = s->status.bpc; - CCstatus.ImageWpc = s->status.wpc; - CCstatus.ImageRawGma = s->status.raw_gma; - CCstatus.ImageLenc = s->status.lenc; - CCstatus.ImageSpecialEffect = s->status.special_effect; - CCstatus.ImageHmirror = s->status.hmirror; - CCstatus.ImageVflip = s->status.vflip; - CCstatus.ImageDcw = s->status.dcw; - CCstatus.ImageDenoiseLevel = s->status.denoise; - - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - - -// - It always zooms to the image center when offsets are zero -// - if imageSize = 0 then the image is not zoomed -// - if imageSize = max value, then the image is fully zoomed in -// - a zoom step is >>> Width + 32 px / Height + 24 px -void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY) -{ - // for OV2640, This works only if the aspect ratio of 4:3 is preserved in the window size. - // use only values divisible by 8 without remainder - imageWidth = CCstatus.ImageWidth + (imageSize * 4 * 8); - imageHeight = CCstatus.ImageHeight + (imageSize * 3 * 8); - - int _maxX = frameSizeX - imageWidth; - int _maxY = frameSizeY - imageHeight; - - if ((abs(zoomOffsetX) * 2) > _maxX) - { - if (zoomOffsetX > 0) - { - zoomOffsetX = _maxX; - } - else - { - zoomOffsetX = 0; - } - } - else - { - if (zoomOffsetX > 0) - { - zoomOffsetX = ((_maxX / 2) + zoomOffsetX); - } - else - { - zoomOffsetX = ((_maxX / 2) + zoomOffsetX); - } - } - - if ((abs(zoomOffsetY) * 2) > _maxY) - { - if (zoomOffsetY > 0) - { - zoomOffsetY = _maxY; - } - else - { - zoomOffsetY = 0; - } - } - else - { - if (zoomOffsetY > 0) - { - zoomOffsetY = ((_maxY / 2) + zoomOffsetY); - } - else - { - zoomOffsetY = ((_maxY / 2) + zoomOffsetY); - } - } -} - - -void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - if (zoomEnabled) - { - int _imageSize_temp = 0; - int _imageWidth = CCstatus.ImageWidth; - int _imageHeight = CCstatus.ImageHeight; - int _offsetx = zoomOffsetX; - int _offsety = zoomOffsetY; - int frameSizeX; - int frameSizeY; - - switch (CCstatus.CamSensor_id) - { - case OV5640_PID: - frameSizeX = 2592; - frameSizeY = 1944; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 - // 59 = ((2560 - 640) / 8 / 4) - 1 - if (imageSize < 59) - { - _imageSize_temp = (59 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - case OV3660_PID: - frameSizeX = 2048; - frameSizeY = 1536; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 - // 43 = ((2048 - 640) / 8 / 4) - 1 - if (imageSize < 43) - { - _imageSize_temp = (43 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - case OV2640_PID: - frameSizeX = 1600; - frameSizeY = 1200; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 - // 29 = ((1600 - 640) / 8 / 4) - 1 - if (imageSize < 29) - { - _imageSize_temp = (29 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - default: - // do nothing - break; - } - } - else - { - s->set_framesize(s, CCstatus.ImageFrameSize); - } - } -} - -void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (CCstatus.CamSensor_id == OV5640_PID) - { - qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) - } - else - { - qual = min(63, max(8, qual)); // Limit quality from 8..63 (values lower than 8 tent to be unstable) - } - - SetImageWidthHeightFromResolution(resol); - - - if (s != NULL) - { - s->set_quality(s, qual); - SetZoomSize(zoomEnabled, zoomOffsetX, zoomOffsetY, imageSize); - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetQualityZoomSize, Failed to get Cam control structure"); - } -} - -void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - if (CCstatus.CamSensor_id == OV2640_PID) - { - _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); - // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. - if (_autoSharpnessEnabled) - { - ov2640_enable_auto_sharpness(s); - } - else - { - ov2640_set_sharpness(s, _sharpnessLevel); - } - } - else - { - _sharpnessLevel = min(3, max(-3, _sharpnessLevel)); - // for CAMERA_OV5640 and CAMERA_OV3660 - if (_autoSharpnessEnabled) - { - // autoSharpness is not supported, default to zero - s->set_sharpness(s, 0); - } - else - { - s->set_sharpness(s, _sharpnessLevel); - } - } - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetCamSharpness, Failed to get Cam control structure"); - } -} - -void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) -{ - if (CCstatus.CamSensor_id == OV2640_PID) - { - s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); - } - else - { - // for CAMERA_OV5640 and CAMERA_OV3660 - bool scale = !(xOutput == xTotal && yOutput == yTotal); - bool binning = (xTotal >= (frameSizeX>>1)); - s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); - } -} - -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) - { - j->len = 0; - } - - if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) - { - return 0; - } - - j->len += len; - - return len; -} - -esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - Start"); -#endif - - _Image->EmptyImage(); // Delete previous stored raw image -> black image - - LEDOnOff(true); // Status-LED on - - if (delay > 0) - { - LightOnOff(true); // Flash-LED on - const TickType_t xDelay = delay / portTICK_PERIOD_MS; - vTaskDelay(xDelay); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - After LightOn"); -#endif - - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CaptureToBasisImage) - most probably caused " - "by a hardware problem (instablility, ...). System will reboot."); - doReboot(); - - return ESP_FAIL; - } - - if (CCstatus.DemoMode) - { - // Use images stored on SD-Card instead of camera image - /* Replace Framebuffer with image from SD-Card */ - loadNextDemoImage(fb); - } - - CImageBasis *_zwImage = new CImageBasis("zwImage"); - - if (_zwImage) - { - _zwImage->LoadFromMemory(fb->buf, fb->len); - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToBasisImage: Can't allocate _zwImage"); - } - - esp_camera_fb_return(fb); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - After fb_get"); -#endif - - LEDOnOff(false); // Status-LED off - - if (delay > 0) - { - LightOnOff(false); // Flash-LED off - } - - // TickType_t xDelay = 1000 / portTICK_PERIOD_MS; - // vTaskDelay( xDelay ); // wait for power to recover - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - After LoadFromMemory"); -#endif - - if (_zwImage == NULL) - { - return ESP_OK; - } - - stbi_uc *p_target; - stbi_uc *p_source; - int channels = 3; - int width = CCstatus.ImageWidth; - int height = CCstatus.ImageHeight; - -#ifdef DEBUG_DETAIL_ON - std::string _zw = "Targetimage: " + std::to_string((int)_Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height); - _zw = _zw + " _zwImage: " + std::to_string((int)_zwImage->rgb_image) + " Size: " + std::to_string(_zwImage->width) + ", " + std::to_string(_zwImage->height); - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw); -#endif - - 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 = _zwImage->rgb_image + (channels * (y * width + x)); - - for (int c = 0; c < channels; c++) - { - p_target[c] = p_source[c]; - } - } - } - - delete _zwImage; - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CaptureToBasisImage - Done"); -#endif - - return ESP_OK; -} - -esp_err_t CCamera::CaptureToFile(std::string nm, int delay) -{ - string ftype; - - LEDOnOff(true); // Status-LED on - - if (delay > 0) - { - LightOnOff(true); // Flash-LED on - const TickType_t xDelay = delay / portTICK_PERIOD_MS; - vTaskDelay(xDelay); - } - - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " - "Check camera module and/or proper electrical connection"); - // doReboot(); - - return ESP_FAIL; - } - - LEDOnOff(false); // Status-LED off - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "w %d, h %d, size %d", fb->width, fb->height, fb->len); -#endif - - nm = FormatFileName(nm); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Save Camera to: %s", nm.c_str()); -#endif - - ftype = toUpper(getFileType(nm)); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Filetype: %s", ftype.c_str()); -#endif - - uint8_t *buf = NULL; - size_t buf_len = 0; - bool converted = false; - - if (ftype.compare("BMP") == 0) - { - frame2bmp(fb, &buf, &buf_len); - converted = true; - } - - if (ftype.compare("JPG") == 0) - { - if (fb->format != PIXFORMAT_JPEG) - { - bool jpeg_converted = frame2jpg(fb, CCstatus.ImageQuality, &buf, &buf_len); - converted = true; - - if (!jpeg_converted) - { - ESP_LOGE(TAG, "JPEG compression failed"); - } - } - else - { - buf_len = fb->len; - buf = fb->buf; - } - } - - FILE *fp = fopen(nm.c_str(), "wb"); - - if (fp == NULL) - { - // If an error occurs during the file creation - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Failed to open file " + nm); - } - else - { - fwrite(buf, sizeof(uint8_t), buf_len, fp); - fclose(fp); - } - - if (converted) - { - free(buf); - } - - esp_camera_fb_return(fb); - - if (delay > 0) - { - LightOnOff(false); // Flash-LED off - } - - return ESP_OK; -} - -esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) -{ - esp_err_t res = ESP_OK; - size_t fb_len = 0; - int64_t fr_start = esp_timer_get_time(); - - LEDOnOff(true); // Status-LED on - - if (delay > 0) - { - LightOnOff(true); // Flash-LED on - const TickType_t xDelay = delay / portTICK_PERIOD_MS; - vTaskDelay(xDelay); - } - - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " - "Check camera module and/or proper electrical connection"); - httpd_resp_send_500(req); - // doReboot(); - - return ESP_FAIL; - } - - LEDOnOff(false); // Status-LED off - res = httpd_resp_set_type(req, "image/jpeg"); - - if (res == ESP_OK) - { - res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=raw.jpg"); - } - - if (res == ESP_OK) - { - if (CCstatus.DemoMode) - { - // Use images stored on SD-Card instead of camera image - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using Demo image!"); - /* Replace Framebuffer with image from SD-Card */ - loadNextDemoImage(fb); - - res = httpd_resp_send(req, (const char *)fb->buf, fb->len); - } - else - { - if (fb->format == PIXFORMAT_JPEG) - { - fb_len = fb->len; - res = httpd_resp_send(req, (const char *)fb->buf, fb->len); - } - else - { - jpg_chunking_t jchunk = {req, 0}; - res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; - httpd_resp_send_chunk(req, NULL, 0); - fb_len = jchunk.len; - } - } - } - - esp_camera_fb_return(fb); - int64_t fr_end = esp_timer_get_time(); - - ESP_LOGI(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); - - if (delay > 0) - { - LightOnOff(false); // Flash-LED off - } - - return res; -} - -esp_err_t CCamera::CaptureToStream(httpd_req_t *req, bool FlashlightOn) -{ - esp_err_t res = ESP_OK; - size_t fb_len = 0; - int64_t fr_start; - char *part_buf[64]; - - // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden - if (CFstatus.changedCameraSettings) - { - Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); - CFstatus.changedCameraSettings = false; - } - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream started"); - - if (FlashlightOn) - { - LEDOnOff(true); // Status-LED on - LightOnOff(true); // Flash-LED on - } - - // httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //stream is blocking web interface, only serving to local - - httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); - httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); - - while (1) - { - fr_start = esp_timer_get_time(); - camera_fb_t *fb = esp_camera_fb_get(); - esp_camera_fb_return(fb); - fb = esp_camera_fb_get(); - - if (!fb) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToStream: Camera framebuffer not available"); - break; - } - - fb_len = fb->len; - - if (res == ESP_OK) - { - size_t hlen = snprintf((char *)part_buf, sizeof(part_buf), _STREAM_PART, fb_len); - res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); - } - - if (res == ESP_OK) - { - res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb_len); - } - - if (res == ESP_OK) - { - res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); - } - - esp_camera_fb_return(fb); - - int64_t fr_end = esp_timer_get_time(); - ESP_LOGD(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); - - if (res != ESP_OK) - { - // Exit loop, e.g. also when closing the webpage - break; - } - - int64_t fr_delta_ms = (fr_end - fr_start) / 1000; - - if (CAM_LIVESTREAM_REFRESHRATE > fr_delta_ms) - { - const TickType_t xDelay = (CAM_LIVESTREAM_REFRESHRATE - fr_delta_ms) / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "Stream: sleep for: %ldms", (long)xDelay * 10); - vTaskDelay(xDelay); - } - } - - LEDOnOff(false); // Status-LED off - LightOnOff(false); // Flash-LED off - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream stopped"); - - return res; -} - -void CCamera::LightOnOff(bool status) -{ - GpioHandler *gpioHandler = gpio_handler_get(); - - if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) - { - ESP_LOGD(TAG, "Use gpioHandler to trigger flashlight"); - gpioHandler->flashLightEnable(status); - } - else - { -#ifdef USE_PWM_LEDFLASH - if (status) - { - ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", CCstatus.ImageLedIntensity); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, CCstatus.ImageLedIntensity)); - // Update duty to apply the new value - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); - } - else - { - ESP_LOGD(TAG, "Internal Flash-LED turn off PWM"); - ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0)); - ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); - } -#else - // Init the GPIO - gpio_pad_select_gpio(FLASH_GPIO); - - // Set the GPIO as a push/pull output - gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); - - if (status) - { - gpio_set_level(FLASH_GPIO, 1); - } - else - { - gpio_set_level(FLASH_GPIO, 0); - } -#endif - } -} - -void CCamera::LEDOnOff(bool status) -{ - if (xHandle_task_StatusLED == NULL) - { - // Init the GPIO - gpio_pad_select_gpio(BLINK_GPIO); - - /* Set the GPIO as a push/pull output */ - gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); - - if (!status) - { - gpio_set_level(BLINK_GPIO, 1); - } - else - { - gpio_set_level(BLINK_GPIO, 0); - } - } -} - -void CCamera::SetImageWidthHeightFromResolution(framesize_t resol) -{ - if (resol == FRAMESIZE_QVGA) - { - CCstatus.ImageHeight = 240; - CCstatus.ImageWidth = 320; - } - else if (resol == FRAMESIZE_VGA) - { - CCstatus.ImageHeight = 480; - CCstatus.ImageWidth = 640; - } - else if (resol == FRAMESIZE_SVGA) - { - CCstatus.ImageHeight = 600; - CCstatus.ImageWidth = 800; - } - else if (resol == FRAMESIZE_XGA) - { - CCstatus.ImageHeight = 768; - CCstatus.ImageWidth = 1024; - } - else if (resol == FRAMESIZE_HD) - { - CCstatus.ImageHeight = 720; - CCstatus.ImageWidth = 1280; - } - else if (resol == FRAMESIZE_SXGA) - { - CCstatus.ImageHeight = 1024; - CCstatus.ImageWidth = 1280; - } - else if (resol == FRAMESIZE_UXGA) - { - CCstatus.ImageHeight = 1200; - CCstatus.ImageWidth = 1600; - } -} - -framesize_t CCamera::TextToFramesize(const char *_size) -{ - if (strcmp(_size, "QVGA") == 0) - { - return FRAMESIZE_QVGA; // 320x240 - } - else if (strcmp(_size, "VGA") == 0) - { - return FRAMESIZE_VGA; // 640x480 - } - else if (strcmp(_size, "SVGA") == 0) - { - return FRAMESIZE_SVGA; // 800x600 - } - else if (strcmp(_size, "XGA") == 0) - { - return FRAMESIZE_XGA; // 1024x768 - } - else if (strcmp(_size, "SXGA") == 0) - { - return FRAMESIZE_SXGA; // 1280x1024 - } - else if (strcmp(_size, "UXGA") == 0) - { - return FRAMESIZE_UXGA; // 1600x1200 - } - - return CCstatus.ImageFrameSize; -} - -std::vector demoFiles; - -void CCamera::useDemoMode(void) -{ - char line[50]; - - FILE *fd = fopen("/sdcard/demo/files.txt", "r"); - - if (!fd) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can not start Demo mode, the folder '/sdcard/demo/' does not contain the needed files!"); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "See Details on https://jomjol.github.io/AI-on-the-edge-device-docs/Demo-Mode!"); - return; - } - - demoImage = (uint8_t *)malloc(DEMO_IMAGE_SIZE); - - if (demoImage == NULL) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to acquire required memory for demo image!"); - return; - } - - while (fgets(line, sizeof(line), fd) != NULL) - { - line[strlen(line) - 1] = '\0'; - demoFiles.push_back(line); - } - - fclose(fd); - - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Using Demo mode (" + std::to_string(demoFiles.size()) + " files) instead of real camera image!"); - - for (auto file : demoFiles) - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, file); - } - - CCstatus.DemoMode = true; -} - -bool CCamera::loadNextDemoImage(camera_fb_t *fb) -{ - char filename[50]; - int readBytes; - long fileSize; - - snprintf(filename, sizeof(filename), "/sdcard/demo/%s", demoFiles[getCountFlowRounds() % demoFiles.size()].c_str()); - - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using " + std::string(filename) + " as demo image"); - - /* Inject saved image */ - - FILE *fp = fopen(filename, "rb"); - - if (!fp) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filename) + "!"); - return false; - } - - fileSize = GetFileSize(filename); - - if (fileSize > DEMO_IMAGE_SIZE) - { - char buf[100]; - snprintf(buf, sizeof(buf), "Demo Image (%d bytes) is larger than provided buffer (%d bytes)!", (int)fileSize, DEMO_IMAGE_SIZE); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string(buf)); - return false; - } - - readBytes = fread(demoImage, 1, DEMO_IMAGE_SIZE, fp); - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "read " + std::to_string(readBytes) + " bytes"); - fclose(fp); - - fb->buf = demoImage; // Update pointer - fb->len = readBytes; - // ToDo do we also need to set height, width, format and timestamp? - - return true; -} - -long CCamera::GetFileSize(std::string filename) -{ - struct stat stat_buf; - long rc = stat(filename.c_str(), &stat_buf); - return rc == 0 ? stat_buf.st_size : -1; -} +#include "ClassControllCamera.h" +#include "ClassLogFile.h" + +#include +#include "driver/gpio.h" +#include "esp_timer.h" +#include "esp_log.h" + +#include "Helper.h" +#include "statusled.h" +#include "CImageBasis.h" + +#include "server_ota.h" +#include "server_GPIO.h" + +#include "../../include/defines.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_camera.h" + +#include "driver/ledc.h" +#include "MainFlowControl.h" + +#include "ov2640_sharpness.h" + +#if (ESP_IDF_VERSION_MAJOR >= 5) +#include "soc/periph_defs.h" +#include "esp_private/periph_ctrl.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_periph.h" +#include "soc/io_mux_reg.h" +#include "esp_rom_gpio.h" +#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio +#define gpio_matrix_in(a, b, c) esp_rom_gpio_connect_in_signal(a, b, c) +#define gpio_matrix_out(a, b, c, d) esp_rom_gpio_connect_out_signal(a, b, c, d) +#define ets_delay_us(a) esp_rom_delay_us(a) +#endif + +CCamera Camera; +camera_controll_config_temp_t CCstatus; + +static const char *TAG = "CAM"; + +/* Camera live stream */ +#define PART_BOUNDARY "123456789000000000000987654321" +static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; +static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; +static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; + +uint8_t *demoImage = NULL; // Buffer holding the demo image in bytes +#define DEMO_IMAGE_SIZE 30000 // Max size of demo image in bytes + +// Camera module bus communications frequency. +// Originally: config.xclk_freq_mhz = 20000000, but this lead to visual artifacts on many modules. +// See https://github.com/espressif/esp32-camera/issues/150#issuecomment-726473652 et al. +#if !defined(XCLK_FREQ_MHZ) +// int xclk = 8; +int xclk = 20; // Orginal value +#else +int xclk = XCLK_FREQ_MHZ; +#endif + +static camera_config_t camera_config = { + .pin_pwdn = CAM_PIN_PWDN, + .pin_reset = CAM_PIN_RESET, + .pin_xclk = CAM_PIN_XCLK, + .pin_sscb_sda = CAM_PIN_SIOD, + .pin_sscb_scl = CAM_PIN_SIOC, + + .pin_d7 = CAM_PIN_D7, + .pin_d6 = CAM_PIN_D6, + .pin_d5 = CAM_PIN_D5, + .pin_d4 = CAM_PIN_D4, + .pin_d3 = CAM_PIN_D3, + .pin_d2 = CAM_PIN_D2, + .pin_d1 = CAM_PIN_D1, + .pin_d0 = CAM_PIN_D0, + .pin_vsync = CAM_PIN_VSYNC, + .pin_href = CAM_PIN_HREF, + .pin_pclk = CAM_PIN_PCLK, + + .xclk_freq_hz = (xclk * 1000000), + .ledc_timer = LEDC_TIMER_0, // LEDC timer to be used for generating XCLK + .ledc_channel = LEDC_CHANNEL_0, // LEDC channel to be used for generating XCLK + + .pixel_format = PIXFORMAT_JPEG, // YUV422,GRAYSCALE,RGB565,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 + .jpeg_quality = 6, // 0-63 lower number means higher quality + .fb_count = 1, // if more than one, i2s runs in continuous mode. Use only with JPEG + .fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */ + .grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version +}; + +typedef struct +{ + httpd_req_t *req; + size_t len; +} jpg_chunking_t; + +CCamera::CCamera(void) +{ +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "CreateClassCamera"); +#endif + CCstatus.WaitBeforePicture = 2; + + ledc_init(); +} + +esp_err_t CCamera::InitCam(void) +{ + ESP_LOGD(TAG, "Init Camera"); + + CCstatus.ImageQuality = camera_config.jpeg_quality; + CCstatus.ImageFrameSize = camera_config.frame_size; + + // initialize the camera + esp_camera_deinit(); // De-init in case it was already initialized + esp_err_t err = esp_camera_init(&camera_config); + + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Camera Init Failed"); + return err; + } + + CCstatus.CameraInitSuccessful = true; + + // Get a reference to the sensor + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + CCstatus.CamSensor_id = s->id.PID; + + // Dump camera module, warn for unsupported modules. + switch (CCstatus.CamSensor_id) + { + case OV2640_PID: + ESP_LOGI(TAG, "OV2640 camera module detected"); + break; + case OV3660_PID: + ESP_LOGI(TAG, "OV3660 camera module detected"); + break; + case OV5640_PID: + ESP_LOGI(TAG, "OV5640 camera module detected"); + break; + default: + ESP_LOGE(TAG, "Camera module is unknown and not properly supported!"); + CCstatus.CameraInitSuccessful = false; + } + } + + if (CCstatus.CameraInitSuccessful) + { + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + +bool CCamera::testCamera(void) +{ + bool success; + camera_fb_t *fb = esp_camera_fb_get(); + + if (fb) + { + success = true; + } + else + { + success = false; + } + + esp_camera_fb_return(fb); + + return success; +} + +void CCamera::ledc_init(void) +{ +#ifdef USE_PWM_LEDFLASH + // Prepare and then apply the LEDC PWM timer configuration + ledc_timer_config_t ledc_timer = {}; + + ledc_timer.speed_mode = LEDC_MODE; + ledc_timer.timer_num = LEDC_TIMER; + ledc_timer.duty_resolution = LEDC_DUTY_RES; + ledc_timer.freq_hz = LEDC_FREQUENCY; // Set output frequency at 5 kHz + ledc_timer.clk_cfg = LEDC_AUTO_CLK; + + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + // Prepare and then apply the LEDC PWM channel configuration + ledc_channel_config_t ledc_channel = {}; + + ledc_channel.speed_mode = LEDC_MODE; + ledc_channel.channel = LEDC_CHANNEL; + ledc_channel.timer_sel = LEDC_TIMER; + ledc_channel.intr_type = LEDC_INTR_DISABLE; + ledc_channel.gpio_num = LEDC_OUTPUT_IO; + ledc_channel.duty = 0; // Set duty to 0% + ledc_channel.hpoint = 0; + // ledc_channel.flags.output_invert = LEDC_OUTPUT_INVERT; + + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); +#endif +} + +void CCamera::SetLEDIntensity(float _intrel) +{ + _intrel = min(_intrel, (float)100); + _intrel = max(_intrel, (float)0); + _intrel = _intrel / 100; + CCstatus.ImageLedIntensity = (int)(_intrel * 8191); + ESP_LOGD(TAG, "Set led_intensity to %d of 8191", CCstatus.ImageLedIntensity); +} + +bool CCamera::getCameraInitSuccessful(void) +{ + return CCstatus.CameraInitSuccessful; +} + +esp_err_t CCamera::setSensorDatenFromCCstatus(void) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + s->set_framesize(s, CCstatus.ImageFrameSize); + s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + + s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 + + s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 + s->set_contrast(s, CCstatus.ImageContrast); // -2 to 2 + s->set_saturation(s, CCstatus.ImageSaturation); // -2 to 2 + // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 + SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); + + s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable + s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 + s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 + + s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable + + s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable + s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 + + s->set_bpc(s, CCstatus.ImageBpc); // 0 = disable , 1 = enable + s->set_wpc(s, CCstatus.ImageWpc); // 0 = disable , 1 = enable + + s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable + s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable + + s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable + s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable + + s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable + + s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_awb_gain(s, CCstatus.ImageAwbGain); // 0 = disable , 1 = enable + s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable + + s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + // special_effect muß als Letztes gesetzt werden, sonst geht es nicht + s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + + TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; + vTaskDelay(xDelay2); + + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + +esp_err_t CCamera::getSensorDatenToCCstatus(void) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + CCstatus.CamSensor_id = s->id.PID; + + CCstatus.ImageFrameSize = (framesize_t)s->status.framesize; + CCstatus.ImageGainceiling = (gainceiling_t)s->status.gainceiling; + + CCstatus.ImageQuality = s->status.quality; + CCstatus.ImageBrightness = s->status.brightness; + CCstatus.ImageContrast = s->status.contrast; + CCstatus.ImageSaturation = s->status.saturation; + // CCstatus.ImageSharpness = s->status.sharpness; // gibt -1 zurück, da es nicht unterstützt wird + CCstatus.ImageWbMode = s->status.wb_mode; + CCstatus.ImageAwb = s->status.awb; + CCstatus.ImageAwbGain = s->status.awb_gain; + CCstatus.ImageAec = s->status.aec; + CCstatus.ImageAec2 = s->status.aec2; + CCstatus.ImageAeLevel = s->status.ae_level; + CCstatus.ImageAecValue = s->status.aec_value; + CCstatus.ImageAgc = s->status.agc; + CCstatus.ImageAgcGain = s->status.agc_gain; + CCstatus.ImageBpc = s->status.bpc; + CCstatus.ImageWpc = s->status.wpc; + CCstatus.ImageRawGma = s->status.raw_gma; + CCstatus.ImageLenc = s->status.lenc; + CCstatus.ImageSpecialEffect = s->status.special_effect; + CCstatus.ImageHmirror = s->status.hmirror; + CCstatus.ImageVflip = s->status.vflip; + CCstatus.ImageDcw = s->status.dcw; + CCstatus.ImageDenoiseLevel = s->status.denoise; + + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + + +// - It always zooms to the image center when offsets are zero +// - if imageSize = 0 then the image is not zoomed +// - if imageSize = max value, then the image is fully zoomed in +// - a zoom step is >>> Width + 32 px / Height + 24 px +void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY) +{ + // for OV2640, This works only if the aspect ratio of 4:3 is preserved in the window size. + // use only values divisible by 8 without remainder + imageWidth = CCstatus.ImageWidth + (imageSize * 4 * 8); + imageHeight = CCstatus.ImageHeight + (imageSize * 3 * 8); + + int _maxX = frameSizeX - imageWidth; + int _maxY = frameSizeY - imageHeight; + + if ((abs(zoomOffsetX) * 2) > _maxX) + { + if (zoomOffsetX > 0) + { + zoomOffsetX = _maxX; + } + else + { + zoomOffsetX = 0; + } + } + else + { + if (zoomOffsetX > 0) + { + zoomOffsetX = ((_maxX / 2) + zoomOffsetX); + } + else + { + zoomOffsetX = ((_maxX / 2) + zoomOffsetX); + } + } + + if ((abs(zoomOffsetY) * 2) > _maxY) + { + if (zoomOffsetY > 0) + { + zoomOffsetY = _maxY; + } + else + { + zoomOffsetY = 0; + } + } + else + { + if (zoomOffsetY > 0) + { + zoomOffsetY = ((_maxY / 2) + zoomOffsetY); + } + else + { + zoomOffsetY = ((_maxY / 2) + zoomOffsetY); + } + } +} + + +void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + if (zoomEnabled) + { + int _imageSize_temp = 0; + int _imageWidth = CCstatus.ImageWidth; + int _imageHeight = CCstatus.ImageHeight; + int _offsetx = zoomOffsetX; + int _offsety = zoomOffsetY; + int frameSizeX; + int frameSizeY; + + switch (CCstatus.CamSensor_id) + { + case OV5640_PID: + frameSizeX = 2592; + frameSizeY = 1944; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 + // 59 = ((2560 - 640) / 8 / 4) - 1 + if (imageSize < 59) + { + _imageSize_temp = (59 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case OV3660_PID: + frameSizeX = 2048; + frameSizeY = 1536; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 43 = ((2048 - 640) / 8 / 4) - 1 + if (imageSize < 43) + { + _imageSize_temp = (43 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case OV2640_PID: + frameSizeX = 1600; + frameSizeY = 1200; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 29 = ((1600 - 640) / 8 / 4) - 1 + if (imageSize < 29) + { + _imageSize_temp = (29 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + default: + // do nothing + break; + } + } + else + { + s->set_framesize(s, CCstatus.ImageFrameSize); + } + } +} + +void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (CCstatus.CamSensor_id == OV5640_PID) + { + qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) + } + else + { + qual = min(63, max(8, qual)); // Limit quality from 8..63 (values lower than 8 tent to be unstable) + } + + SetImageWidthHeightFromResolution(resol); + + + if (s != NULL) + { + s->set_quality(s, qual); + SetZoomSize(zoomEnabled, zoomOffsetX, zoomOffsetY, imageSize); + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetQualityZoomSize, Failed to get Cam control structure"); + } +} + +void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + if (CCstatus.CamSensor_id == OV2640_PID) + { + _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); + // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. + if (_autoSharpnessEnabled) + { + ov2640_enable_auto_sharpness(s); + } + else + { + ov2640_set_sharpness(s, _sharpnessLevel); + } + } + else + { + _sharpnessLevel = min(3, max(-3, _sharpnessLevel)); + // for CAMERA_OV5640 and CAMERA_OV3660 + if (_autoSharpnessEnabled) + { + // autoSharpness is not supported, default to zero + s->set_sharpness(s, 0); + } + else + { + s->set_sharpness(s, _sharpnessLevel); + } + } + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetCamSharpness, Failed to get Cam control structure"); + } +} + +void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) +{ + if (CCstatus.CamSensor_id == OV2640_PID) + { + s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); + } + else + { + // for CAMERA_OV5640 and CAMERA_OV3660 + bool scale = !(xOutput == xTotal && yOutput == yTotal); + bool binning = (xTotal >= (frameSizeX>>1)); + s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); + } +} + +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) + { + j->len = 0; + } + + if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) + { + return 0; + } + + j->len += len; + + return len; +} + +esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - Start"); +#endif + + _Image->EmptyImage(); // Delete previous stored raw image -> black image + + LEDOnOff(true); // Status-LED on + + if (delay > 0) + { + LightOnOff(true); // Flash-LED on + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay(xDelay); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - After LightOn"); +#endif + + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CaptureToBasisImage) - most probably caused " + "by a hardware problem (instablility, ...). System will reboot."); + doReboot(); + + return ESP_FAIL; + } + + if (CCstatus.DemoMode) + { + // Use images stored on SD-Card instead of camera image + /* Replace Framebuffer with image from SD-Card */ + loadNextDemoImage(fb); + } + + CImageBasis *_zwImage = new CImageBasis("zwImage"); + + if (_zwImage) + { + _zwImage->LoadFromMemory(fb->buf, fb->len); + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToBasisImage: Can't allocate _zwImage"); + } + + esp_camera_fb_return(fb); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - After fb_get"); +#endif + + LEDOnOff(false); // Status-LED off + + if (delay > 0) + { + LightOnOff(false); // Flash-LED off + } + + // TickType_t xDelay = 1000 / portTICK_PERIOD_MS; + // vTaskDelay( xDelay ); // wait for power to recover + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - After LoadFromMemory"); +#endif + + if (_zwImage == NULL) + { + return ESP_OK; + } + + stbi_uc *p_target; + stbi_uc *p_source; + int channels = 3; + int width = CCstatus.ImageWidth; + int height = CCstatus.ImageHeight; + +#ifdef DEBUG_DETAIL_ON + std::string _zw = "Targetimage: " + std::to_string((int)_Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height); + _zw = _zw + " _zwImage: " + std::to_string((int)_zwImage->rgb_image) + " Size: " + std::to_string(_zwImage->width) + ", " + std::to_string(_zwImage->height); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw); +#endif + + 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 = _zwImage->rgb_image + (channels * (y * width + x)); + + for (int c = 0; c < channels; c++) + { + p_target[c] = p_source[c]; + } + } + } + + delete _zwImage; + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("CaptureToBasisImage - Done"); +#endif + + return ESP_OK; +} + +esp_err_t CCamera::CaptureToFile(std::string nm, int delay) +{ + string ftype; + + LEDOnOff(true); // Status-LED on + + if (delay > 0) + { + LightOnOff(true); // Flash-LED on + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay(xDelay); + } + + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " + "Check camera module and/or proper electrical connection"); + // doReboot(); + + return ESP_FAIL; + } + + LEDOnOff(false); // Status-LED off + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "w %d, h %d, size %d", fb->width, fb->height, fb->len); +#endif + + nm = FormatFileName(nm); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Save Camera to: %s", nm.c_str()); +#endif + + ftype = toUpper(getFileType(nm)); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Filetype: %s", ftype.c_str()); +#endif + + uint8_t *buf = NULL; + size_t buf_len = 0; + bool converted = false; + + if (ftype.compare("BMP") == 0) + { + frame2bmp(fb, &buf, &buf_len); + converted = true; + } + + if (ftype.compare("JPG") == 0) + { + if (fb->format != PIXFORMAT_JPEG) + { + bool jpeg_converted = frame2jpg(fb, CCstatus.ImageQuality, &buf, &buf_len); + converted = true; + + if (!jpeg_converted) + { + ESP_LOGE(TAG, "JPEG compression failed"); + } + } + else + { + buf_len = fb->len; + buf = fb->buf; + } + } + + FILE *fp = fopen(nm.c_str(), "wb"); + + if (fp == NULL) + { + // If an error occurs during the file creation + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Failed to open file " + nm); + } + else + { + fwrite(buf, sizeof(uint8_t), buf_len, fp); + fclose(fp); + } + + if (converted) + { + free(buf); + } + + esp_camera_fb_return(fb); + + if (delay > 0) + { + LightOnOff(false); // Flash-LED off + } + + return ESP_OK; +} + +esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) +{ + esp_err_t res = ESP_OK; + size_t fb_len = 0; + int64_t fr_start = esp_timer_get_time(); + + LEDOnOff(true); // Status-LED on + + if (delay > 0) + { + LightOnOff(true); // Flash-LED on + const TickType_t xDelay = delay / portTICK_PERIOD_MS; + vTaskDelay(xDelay); + } + + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " + "Check camera module and/or proper electrical connection"); + httpd_resp_send_500(req); + // doReboot(); + + return ESP_FAIL; + } + + LEDOnOff(false); // Status-LED off + res = httpd_resp_set_type(req, "image/jpeg"); + + if (res == ESP_OK) + { + res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=raw.jpg"); + } + + if (res == ESP_OK) + { + if (CCstatus.DemoMode) + { + // Use images stored on SD-Card instead of camera image + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using Demo image!"); + /* Replace Framebuffer with image from SD-Card */ + loadNextDemoImage(fb); + + res = httpd_resp_send(req, (const char *)fb->buf, fb->len); + } + else + { + if (fb->format == PIXFORMAT_JPEG) + { + fb_len = fb->len; + res = httpd_resp_send(req, (const char *)fb->buf, fb->len); + } + else + { + jpg_chunking_t jchunk = {req, 0}; + res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; + httpd_resp_send_chunk(req, NULL, 0); + fb_len = jchunk.len; + } + } + } + + esp_camera_fb_return(fb); + int64_t fr_end = esp_timer_get_time(); + + ESP_LOGI(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); + + if (delay > 0) + { + LightOnOff(false); // Flash-LED off + } + + return res; +} + +esp_err_t CCamera::CaptureToStream(httpd_req_t *req, bool FlashlightOn) +{ + esp_err_t res = ESP_OK; + size_t fb_len = 0; + int64_t fr_start; + char *part_buf[64]; + + // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden + if (CFstatus.changedCameraSettings) + { + Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + CFstatus.changedCameraSettings = false; + } + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream started"); + + if (FlashlightOn) + { + LEDOnOff(true); // Status-LED on + LightOnOff(true); // Flash-LED on + } + + // httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //stream is blocking web interface, only serving to local + + httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); + httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); + + while (1) + { + fr_start = esp_timer_get_time(); + camera_fb_t *fb = esp_camera_fb_get(); + esp_camera_fb_return(fb); + fb = esp_camera_fb_get(); + + if (!fb) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToStream: Camera framebuffer not available"); + break; + } + + fb_len = fb->len; + + if (res == ESP_OK) + { + size_t hlen = snprintf((char *)part_buf, sizeof(part_buf), _STREAM_PART, fb_len); + res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); + } + + if (res == ESP_OK) + { + res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb_len); + } + + if (res == ESP_OK) + { + res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); + } + + esp_camera_fb_return(fb); + + int64_t fr_end = esp_timer_get_time(); + ESP_LOGD(TAG, "JPG: %dKB %dms", (int)(fb_len / 1024), (int)((fr_end - fr_start) / 1000)); + + if (res != ESP_OK) + { + // Exit loop, e.g. also when closing the webpage + break; + } + + int64_t fr_delta_ms = (fr_end - fr_start) / 1000; + + if (CAM_LIVESTREAM_REFRESHRATE > fr_delta_ms) + { + const TickType_t xDelay = (CAM_LIVESTREAM_REFRESHRATE - fr_delta_ms) / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "Stream: sleep for: %ldms", (long)xDelay * 10); + vTaskDelay(xDelay); + } + } + + LEDOnOff(false); // Status-LED off + LightOnOff(false); // Flash-LED off + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream stopped"); + + return res; +} + +void CCamera::LightOnOff(bool status) +{ + GpioHandler *gpioHandler = gpio_handler_get(); + + if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) + { + ESP_LOGD(TAG, "Use gpioHandler to trigger flashlight"); + gpioHandler->flashLightEnable(status); + } + else + { +#ifdef USE_PWM_LEDFLASH + if (status) + { + ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", CCstatus.ImageLedIntensity); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, CCstatus.ImageLedIntensity)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); + } + else + { + ESP_LOGD(TAG, "Internal Flash-LED turn off PWM"); + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0)); + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); + } +#else + // Init the GPIO + gpio_pad_select_gpio(FLASH_GPIO); + + // Set the GPIO as a push/pull output + gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT); + + if (status) + { + gpio_set_level(FLASH_GPIO, 1); + } + else + { + gpio_set_level(FLASH_GPIO, 0); + } +#endif + } +} + +void CCamera::LEDOnOff(bool status) +{ + if (xHandle_task_StatusLED == NULL) + { + // Init the GPIO + gpio_pad_select_gpio(BLINK_GPIO); + + /* Set the GPIO as a push/pull output */ + gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); + + if (!status) + { + gpio_set_level(BLINK_GPIO, 1); + } + else + { + gpio_set_level(BLINK_GPIO, 0); + } + } +} + +void CCamera::SetImageWidthHeightFromResolution(framesize_t resol) +{ + if (resol == FRAMESIZE_QVGA) + { + CCstatus.ImageHeight = 240; + CCstatus.ImageWidth = 320; + } + else if (resol == FRAMESIZE_VGA) + { + CCstatus.ImageHeight = 480; + CCstatus.ImageWidth = 640; + } + else if (resol == FRAMESIZE_SVGA) + { + CCstatus.ImageHeight = 600; + CCstatus.ImageWidth = 800; + } + else if (resol == FRAMESIZE_XGA) + { + CCstatus.ImageHeight = 768; + CCstatus.ImageWidth = 1024; + } + else if (resol == FRAMESIZE_HD) + { + CCstatus.ImageHeight = 720; + CCstatus.ImageWidth = 1280; + } + else if (resol == FRAMESIZE_SXGA) + { + CCstatus.ImageHeight = 1024; + CCstatus.ImageWidth = 1280; + } + else if (resol == FRAMESIZE_UXGA) + { + CCstatus.ImageHeight = 1200; + CCstatus.ImageWidth = 1600; + } +} + +framesize_t CCamera::TextToFramesize(const char *_size) +{ + if (strcmp(_size, "QVGA") == 0) + { + return FRAMESIZE_QVGA; // 320x240 + } + else if (strcmp(_size, "VGA") == 0) + { + return FRAMESIZE_VGA; // 640x480 + } + else if (strcmp(_size, "SVGA") == 0) + { + return FRAMESIZE_SVGA; // 800x600 + } + else if (strcmp(_size, "XGA") == 0) + { + return FRAMESIZE_XGA; // 1024x768 + } + else if (strcmp(_size, "SXGA") == 0) + { + return FRAMESIZE_SXGA; // 1280x1024 + } + else if (strcmp(_size, "UXGA") == 0) + { + return FRAMESIZE_UXGA; // 1600x1200 + } + + return CCstatus.ImageFrameSize; +} + +std::vector demoFiles; + +void CCamera::useDemoMode(void) +{ + char line[50]; + + FILE *fd = fopen("/sdcard/demo/files.txt", "r"); + + if (!fd) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can not start Demo mode, the folder '/sdcard/demo/' does not contain the needed files!"); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "See Details on https://jomjol.github.io/AI-on-the-edge-device-docs/Demo-Mode!"); + return; + } + + demoImage = (uint8_t *)malloc(DEMO_IMAGE_SIZE); + + if (demoImage == NULL) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to acquire required memory for demo image!"); + return; + } + + while (fgets(line, sizeof(line), fd) != NULL) + { + line[strlen(line) - 1] = '\0'; + demoFiles.push_back(line); + } + + fclose(fd); + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Using Demo mode (" + std::to_string(demoFiles.size()) + " files) instead of real camera image!"); + + for (auto file : demoFiles) + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, file); + } + + CCstatus.DemoMode = true; +} + +bool CCamera::loadNextDemoImage(camera_fb_t *fb) +{ + char filename[50]; + int readBytes; + long fileSize; + + snprintf(filename, sizeof(filename), "/sdcard/demo/%s", demoFiles[getCountFlowRounds() % demoFiles.size()].c_str()); + + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using " + std::string(filename) + " as demo image"); + + /* Inject saved image */ + + FILE *fp = fopen(filename, "rb"); + + if (!fp) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filename) + "!"); + return false; + } + + fileSize = GetFileSize(filename); + + if (fileSize > DEMO_IMAGE_SIZE) + { + char buf[100]; + snprintf(buf, sizeof(buf), "Demo Image (%d bytes) is larger than provided buffer (%d bytes)!", (int)fileSize, DEMO_IMAGE_SIZE); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string(buf)); + return false; + } + + readBytes = fread(demoImage, 1, DEMO_IMAGE_SIZE, fp); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "read " + std::to_string(readBytes) + " bytes"); + fclose(fp); + + fb->buf = demoImage; // Update pointer + fb->len = readBytes; + // ToDo do we also need to set height, width, format and timestamp? + + return true; +} + +long CCamera::GetFileSize(std::string filename) +{ + struct stat stat_buf; + long rc = stat(filename.c_str(), &stat_buf); + return rc == 0 ? stat_buf.st_size : -1; +} diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index fb284d3ca..c563c0a47 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -1,111 +1,111 @@ -#pragma once - -#ifndef CLASSCONTROLLCAMERA_H -#define CLASSCONTROLLCAMERA_H - -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" - -#include "esp_camera.h" -#include -#include -#include "CImageBasis.h" -#include "../../include/defines.h" - -typedef struct -{ - uint16_t CamSensor_id; - - framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 - gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - - int ImageQuality; // 0 - 63 - int ImageBrightness; // (-2 to 2) - set brightness - int ImageContrast; //-2 - 2 - int ImageSaturation; //-2 - 2 - int ImageSharpness; //-2 - 2 - bool ImageAutoSharpness; - int ImageSpecialEffect; // 0 - 6 - int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - int ImageAwb; // white balance enable (0 or 1) - int ImageAwbGain; // Auto White Balance enable (0 or 1) - int ImageAec; // auto exposure off (1 or 0) - int ImageAec2; // automatic exposure sensor (0 or 1) - int ImageAeLevel; // auto exposure levels (-2 to 2) - int ImageAecValue; // set exposure manually (0-1200) - int ImageAgc; // auto gain off (1 or 0) - int ImageAgcGain; // set gain manually (0 - 30) - int ImageBpc; // black pixel correction - int ImageWpc; // white pixel correction - int ImageRawGma; // (1 or 0) - int ImageLenc; // lens correction (1 or 0) - int ImageHmirror; // (0 or 1) flip horizontally - int ImageVflip; // Invert image (0 or 1) - int ImageDcw; // downsize enable (1 or 0) - - int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - int ImageWidth; - int ImageHeight; - - int ImageLedIntensity; - - bool ImageZoomEnabled; - int ImageZoomOffsetX; - int ImageZoomOffsetY; - int ImageZoomSize; - - int WaitBeforePicture; - bool isImageSize; - - bool CameraInitSuccessful; - bool changedCameraSettings; - bool DemoMode; - bool SaveAllFiles; -} camera_controll_config_temp_t; - -extern camera_controll_config_temp_t CCstatus; - -class CCamera -{ -protected: - void ledc_init(void); - bool loadNextDemoImage(camera_fb_t *fb); - long GetFileSize(std::string filename); - void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); - void SetImageWidthHeightFromResolution(framesize_t resol); - void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); - -public: - CCamera(void); - esp_err_t InitCam(void); - - void LightOnOff(bool status); - void LEDOnOff(bool status); - - esp_err_t setSensorDatenFromCCstatus(void); - esp_err_t getSensorDatenToCCstatus(void); - - esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); - esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); - - void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); - void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); - void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel); - - void SetLEDIntensity(float _intrel); - bool testCamera(void); - bool getCameraInitSuccessful(void); - void useDemoMode(void); - - 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; +#pragma once + +#ifndef CLASSCONTROLLCAMERA_H +#define CLASSCONTROLLCAMERA_H + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/event_groups.h" + +#include "esp_camera.h" +#include +#include +#include "CImageBasis.h" +#include "../../include/defines.h" + +typedef struct +{ + uint16_t CamSensor_id; + + framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 + gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + + int ImageQuality; // 0 - 63 + int ImageBrightness; // (-2 to 2) - set brightness + int ImageContrast; //-2 - 2 + int ImageSaturation; //-2 - 2 + int ImageSharpness; //-2 - 2 + bool ImageAutoSharpness; + int ImageSpecialEffect; // 0 - 6 + int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + int ImageAwb; // white balance enable (0 or 1) + int ImageAwbGain; // Auto White Balance enable (0 or 1) + int ImageAec; // auto exposure off (1 or 0) + int ImageAec2; // automatic exposure sensor (0 or 1) + int ImageAeLevel; // auto exposure levels (-2 to 2) + int ImageAecValue; // set exposure manually (0-1200) + int ImageAgc; // auto gain off (1 or 0) + int ImageAgcGain; // set gain manually (0 - 30) + int ImageBpc; // black pixel correction + int ImageWpc; // white pixel correction + int ImageRawGma; // (1 or 0) + int ImageLenc; // lens correction (1 or 0) + int ImageHmirror; // (0 or 1) flip horizontally + int ImageVflip; // Invert image (0 or 1) + int ImageDcw; // downsize enable (1 or 0) + + int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + int ImageWidth; + int ImageHeight; + + int ImageLedIntensity; + + bool ImageZoomEnabled; + int ImageZoomOffsetX; + int ImageZoomOffsetY; + int ImageZoomSize; + + int WaitBeforePicture; + bool isImageSize; + + bool CameraInitSuccessful; + bool changedCameraSettings; + bool DemoMode; + bool SaveAllFiles; +} camera_controll_config_temp_t; + +extern camera_controll_config_temp_t CCstatus; + +class CCamera +{ +protected: + void ledc_init(void); + bool loadNextDemoImage(camera_fb_t *fb); + long GetFileSize(std::string filename); + void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); + void SetImageWidthHeightFromResolution(framesize_t resol); + void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); + +public: + CCamera(void); + esp_err_t InitCam(void); + + void LightOnOff(bool status); + void LEDOnOff(bool status); + + esp_err_t setSensorDatenFromCCstatus(void); + esp_err_t getSensorDatenToCCstatus(void); + + esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); + esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); + + void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); + void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); + void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel); + + void SetLEDIntensity(float _intrel); + bool testCamera(void); + bool getCameraInitSuccessful(void); + void useDemoMode(void); + + 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; #endif \ No newline at end of file diff --git a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp index a577061d6..42461ac48 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp @@ -1,525 +1,525 @@ -#include -#include -#include -#include - -#include "ClassFlowTakeImage.h" -#include "Helper.h" -#include "ClassLogFile.h" - -#include "CImageBasis.h" -#include "ClassControllCamera.h" -#include "MainFlowControl.h" - -#include "esp_wifi.h" -#include "esp_log.h" -#include "../../include/defines.h" -#include "psram.h" - -#include - -// #define DEBUG_DETAIL_ON -// #define WIFITURNOFF - -static const char *TAG = "TAKEIMAGE"; - -esp_err_t ClassFlowTakeImage::camera_capture(void) -{ - string nm = namerawimage; - Camera.CaptureToFile(nm); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - return ESP_OK; -} - -void ClassFlowTakeImage::takePictureWithFlash(int flash_duration) -{ - // in case the image is flipped, it must be reset here // - rawImage->width = CCstatus.ImageWidth; - rawImage->height = CCstatus.ImageHeight; - - ESP_LOGD(TAG, "flash_duration: %d", flash_duration); - - Camera.CaptureToBasisImage(rawImage, flash_duration); - - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - if (CCstatus.SaveAllFiles) - { - rawImage->SaveToFile(namerawimage); - } -} - -void ClassFlowTakeImage::SetInitialParameter(void) -{ - TimeImageTaken = 0; - rawImage = NULL; - disabled = false; - namerawimage = "/sdcard/img_tmp/raw.jpg"; -} - -// auslesen der Kameraeinstellungen aus der config.ini -// wird beim Start aufgerufen -bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) -{ - Camera.getSensorDatenToCCstatus(); // Kamera >>> CCstatus - - std::vector splitted; - - aktparamgraph = trim(aktparamgraph); - - if (aktparamgraph.size() == 0) - { - if (!this->GetNextParagraph(pfile, aktparamgraph)) - { - return false; - } - } - - if (aktparamgraph.compare("[TakeImage]") != 0) - { - // Paragraph does not fit TakeImage - return false; - } - - while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) - { - splitted = ZerlegeZeile(aktparamgraph); - - if ((toUpper(splitted[0]) == "RAWIMAGESLOCATION") && (splitted.size() > 1)) - { - imagesLocation = "/sdcard" + splitted[1]; - isLogImage = true; - } - - else if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1)) - { - this->imagesRetention = std::stod(splitted[1]); - } - - else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) - { - CCstatus.SaveAllFiles = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1)) - { - int _WaitBeforePicture = std::stoi(splitted[1]); - if (_WaitBeforePicture != 0) - { - CCstatus.WaitBeforePicture = _WaitBeforePicture; - } - else - { - CCstatus.WaitBeforePicture = 2; - } - } - - else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1)) - { - std::string _ImageGainceiling = toUpper(splitted[1]); - if (_ImageGainceiling == "X4") - { - CCstatus.ImageGainceiling = GAINCEILING_4X; - } - else if (_ImageGainceiling == "X8") - { - CCstatus.ImageGainceiling = GAINCEILING_8X; - } - else if (_ImageGainceiling == "X16") - { - CCstatus.ImageGainceiling = GAINCEILING_16X; - } - else if (_ImageGainceiling == "X32") - { - CCstatus.ImageGainceiling = GAINCEILING_32X; - } - else if (_ImageGainceiling == "X64") - { - CCstatus.ImageGainceiling = GAINCEILING_64X; - } - else if (_ImageGainceiling == "X128") - { - CCstatus.ImageGainceiling = GAINCEILING_128X; - } - else - { - CCstatus.ImageGainceiling = GAINCEILING_2X; - } - } - - else if ((toUpper(splitted[0]) == "CAMQUALITY") && (splitted.size() > 1)) - { - int _ImageQuality = std::stoi(splitted[1]); - CCstatus.ImageQuality = clipInt(_ImageQuality, 63, 6); - } - - else if ((toUpper(splitted[0]) == "CAMBRIGHTNESS") && (splitted.size() > 1)) - { - int _ImageBrightness = std::stoi(splitted[1]); - CCstatus.ImageBrightness = clipInt(_ImageBrightness, 2, -2); - } - - else if ((toUpper(splitted[0]) == "CAMCONTRAST") && (splitted.size() > 1)) - { - int _ImageContrast = std::stoi(splitted[1]); - CCstatus.ImageContrast = clipInt(_ImageContrast, 2, -2); - } - - else if ((toUpper(splitted[0]) == "CAMSATURATION") && (splitted.size() > 1)) - { - int _ImageSaturation = std::stoi(splitted[1]); - CCstatus.ImageSaturation = clipInt(_ImageSaturation, 2, -2); - } - - else if ((toUpper(splitted[0]) == "CAMSHARPNESS") && (splitted.size() > 1)) - { - int _ImageSharpness = std::stoi(splitted[1]); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageSharpness = clipInt(_ImageSharpness, 2, -2); - } - else - { - CCstatus.ImageSharpness = clipInt(_ImageSharpness, 3, -3); - } - } - - else if ((toUpper(splitted[0]) == "CAMAUTOSHARPNESS") && (splitted.size() > 1)) - { - CCstatus.ImageAutoSharpness = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMSPECIALEFFECT") && (splitted.size() > 1)) - { - std::string _ImageSpecialEffect = toUpper(splitted[1]); - if (_ImageSpecialEffect == "NEGATIVE") - { - CCstatus.ImageSpecialEffect = 1; - } - else if (_ImageSpecialEffect == "GRAYSCALE") - { - CCstatus.ImageSpecialEffect = 2; - } - else if (_ImageSpecialEffect == "RED") - { - CCstatus.ImageSpecialEffect = 3; - } - else if (_ImageSpecialEffect == "GREEN") - { - CCstatus.ImageSpecialEffect = 4; - } - else if (_ImageSpecialEffect == "BLUE") - { - CCstatus.ImageSpecialEffect = 5; - } - else if (_ImageSpecialEffect == "RETRO") - { - CCstatus.ImageSpecialEffect = 6; - } - else - { - CCstatus.ImageSpecialEffect = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMWBMODE") && (splitted.size() > 1)) - { - std::string _ImageWbMode = toUpper(splitted[1]); - if (_ImageWbMode == "SUNNY") - { - CCstatus.ImageWbMode = 1; - } - else if (_ImageWbMode == "CLOUDY") - { - CCstatus.ImageWbMode = 2; - } - else if (_ImageWbMode == "OFFICE") - { - CCstatus.ImageWbMode = 3; - } - else if (_ImageWbMode == "HOME") - { - CCstatus.ImageWbMode = 4; - } - else - { - CCstatus.ImageWbMode = 0; - } - } - - else if ((toUpper(splitted[0]) == "CAMAWB") && (splitted.size() > 1)) - { - CCstatus.ImageAwb = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMAWBGAIN") && (splitted.size() > 1)) - { - CCstatus.ImageAwbGain = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMAEC") && (splitted.size() > 1)) - { - CCstatus.ImageAec = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMAEC2") && (splitted.size() > 1)) - { - CCstatus.ImageAec2 = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMAELEVEL") && (splitted.size() > 1)) - { - int _ImageAeLevel = std::stoi(splitted[1]); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 2, -2); - } - else - { - CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 5, -5); - } - } - - else if ((toUpper(splitted[0]) == "CAMAECVALUE") && (splitted.size() > 1)) - { - int _ImageAecValue = std::stoi(splitted[1]); - CCstatus.ImageAecValue = clipInt(_ImageAecValue, 1200, 0); - } - - else if ((toUpper(splitted[0]) == "CAMAGC") && (splitted.size() > 1)) - { - CCstatus.ImageAgc = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMAGCGAIN") && (splitted.size() > 1)) - { - int _ImageAgcGain = std::stoi(splitted[1]); - CCstatus.ImageAgcGain = clipInt(_ImageAgcGain, 30, 0); - } - - else if ((toUpper(splitted[0]) == "CAMBPC") && (splitted.size() > 1)) - { - CCstatus.ImageBpc = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMWPC") && (splitted.size() > 1)) - { - CCstatus.ImageWpc = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMRAWGMA") && (splitted.size() > 1)) - { - CCstatus.ImageRawGma = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMLENC") && (splitted.size() > 1)) - { - CCstatus.ImageLenc = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMHMIRROR") && (splitted.size() > 1)) - { - CCstatus.ImageHmirror = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMVFLIP") && (splitted.size() > 1)) - { - CCstatus.ImageVflip = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMDCW") && (splitted.size() > 1)) - { - CCstatus.ImageDcw = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMSDENOISE") && (splitted.size() > 1)) - { - int _ImageDenoiseLevel = std::stoi(splitted[1]); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageDenoiseLevel = 0; - } - else - { - CCstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0); - } - } - - else if ((toUpper(splitted[0]) == "CAMZOOM") && (splitted.size() > 1)) - { - CCstatus.ImageZoomEnabled = stringToBoolean(toUpper(splitted[1])); - } - - else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETX") && (splitted.size() > 1)) - { - int _ImageZoomOffsetX = std::stoi(splitted[1]); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480); - } - else if (CCstatus.CamSensor_id == OV3660_PID) - { - CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704); - } - else if (CCstatus.CamSensor_id == OV5640_PID) - { - CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960); - } - } - - else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETY") && (splitted.size() > 1)) - { - int _ImageZoomOffsetY = std::stoi(splitted[1]); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360); - } - else if (CCstatus.CamSensor_id == OV3660_PID) - { - CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528); - } - else if (CCstatus.CamSensor_id == OV5640_PID) - { - CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720); - } - } - - else if ((toUpper(splitted[0]) == "CAMZOOMSIZE") && (splitted.size() > 1)) - { - int _ImageZoomSize = std::stoi(splitted[1]); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0); - } - else if (CCstatus.CamSensor_id == OV3660_PID) - { - CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0); - } - else if (CCstatus.CamSensor_id == OV5640_PID) - { - CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0); - } - } - - else if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1)) - { - float ledintensity = std::stof(splitted[1]); - Camera.SetLEDIntensity(ledintensity); - } - - else if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1)) - { - CCstatus.DemoMode = stringToBoolean(toUpper(splitted[1])); - if (CCstatus.DemoMode) - { - Camera.useDemoMode(); - } - } - } - - Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); - - rawImage = new CImageBasis("rawImage"); - rawImage->CreateEmptyImage(CCstatus.ImageWidth, CCstatus.ImageHeight, 3); - - return true; -} - -ClassFlowTakeImage::ClassFlowTakeImage(std::vector *lfc) : ClassFlowImage(lfc, TAG) -{ - imagesLocation = "/log/source"; - imagesRetention = 5; - SetInitialParameter(); -} - -string ClassFlowTakeImage::getHTMLSingleStep(string host) -{ - string result; - result = "Raw Image:
\n\n"; - return result; -} - -// wird bei jeder Auswertrunde aufgerufen -bool ClassFlowTakeImage::doFlow(string zwtime) -{ - psram_init_shared_memory_for_take_image_step(); - - string logPath = CreateLogFolder(zwtime); - - int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash"); -#endif - -#ifdef WIFITURNOFF - esp_wifi_stop(); // to save power usage and -#endif - - // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden - if (CFstatus.changedCameraSettings) - { - Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); - CFstatus.changedCameraSettings = false; - } - - takePictureWithFlash(flash_duration); - -#ifdef WIFITURNOFF - esp_wifi_start(); -#endif - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash"); -#endif - - LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage); - - RemoveOldLogs(); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs"); -#endif - - psram_deinit_shared_memory_for_take_image_step(); - - return true; -} - -esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req) -{ - int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - return Camera.CaptureToHTTP(req, flash_duration); -} - -ImageData *ClassFlowTakeImage::SendRawImage(void) -{ - CImageBasis *zw = new CImageBasis("SendRawImage", rawImage); - ImageData *id; - int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); - Camera.CaptureToBasisImage(zw, flash_duration); - time(&TimeImageTaken); - localtime(&TimeImageTaken); - - id = zw->writeToMemoryAsJPG(); - delete zw; - return id; -} - -time_t ClassFlowTakeImage::getTimeImageTaken(void) -{ - return TimeImageTaken; -} - -ClassFlowTakeImage::~ClassFlowTakeImage(void) -{ - delete rawImage; -} +#include +#include +#include +#include + +#include "ClassFlowTakeImage.h" +#include "Helper.h" +#include "ClassLogFile.h" + +#include "CImageBasis.h" +#include "ClassControllCamera.h" +#include "MainFlowControl.h" + +#include "esp_wifi.h" +#include "esp_log.h" +#include "../../include/defines.h" +#include "psram.h" + +#include + +// #define DEBUG_DETAIL_ON +// #define WIFITURNOFF + +static const char *TAG = "TAKEIMAGE"; + +esp_err_t ClassFlowTakeImage::camera_capture(void) +{ + string nm = namerawimage; + Camera.CaptureToFile(nm); + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + return ESP_OK; +} + +void ClassFlowTakeImage::takePictureWithFlash(int flash_duration) +{ + // in case the image is flipped, it must be reset here // + rawImage->width = CCstatus.ImageWidth; + rawImage->height = CCstatus.ImageHeight; + + ESP_LOGD(TAG, "flash_duration: %d", flash_duration); + + Camera.CaptureToBasisImage(rawImage, flash_duration); + + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + if (CCstatus.SaveAllFiles) + { + rawImage->SaveToFile(namerawimage); + } +} + +void ClassFlowTakeImage::SetInitialParameter(void) +{ + TimeImageTaken = 0; + rawImage = NULL; + disabled = false; + namerawimage = "/sdcard/img_tmp/raw.jpg"; +} + +// auslesen der Kameraeinstellungen aus der config.ini +// wird beim Start aufgerufen +bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) +{ + Camera.getSensorDatenToCCstatus(); // Kamera >>> CCstatus + + std::vector splitted; + + aktparamgraph = trim(aktparamgraph); + + if (aktparamgraph.size() == 0) + { + if (!this->GetNextParagraph(pfile, aktparamgraph)) + { + return false; + } + } + + if (aktparamgraph.compare("[TakeImage]") != 0) + { + // Paragraph does not fit TakeImage + return false; + } + + while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) + { + splitted = ZerlegeZeile(aktparamgraph); + + if ((toUpper(splitted[0]) == "RAWIMAGESLOCATION") && (splitted.size() > 1)) + { + imagesLocation = "/sdcard" + splitted[1]; + isLogImage = true; + } + + else if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1)) + { + this->imagesRetention = std::stod(splitted[1]); + } + + else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) + { + CCstatus.SaveAllFiles = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1)) + { + int _WaitBeforePicture = std::stoi(splitted[1]); + if (_WaitBeforePicture != 0) + { + CCstatus.WaitBeforePicture = _WaitBeforePicture; + } + else + { + CCstatus.WaitBeforePicture = 2; + } + } + + else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1)) + { + std::string _ImageGainceiling = toUpper(splitted[1]); + if (_ImageGainceiling == "X4") + { + CCstatus.ImageGainceiling = GAINCEILING_4X; + } + else if (_ImageGainceiling == "X8") + { + CCstatus.ImageGainceiling = GAINCEILING_8X; + } + else if (_ImageGainceiling == "X16") + { + CCstatus.ImageGainceiling = GAINCEILING_16X; + } + else if (_ImageGainceiling == "X32") + { + CCstatus.ImageGainceiling = GAINCEILING_32X; + } + else if (_ImageGainceiling == "X64") + { + CCstatus.ImageGainceiling = GAINCEILING_64X; + } + else if (_ImageGainceiling == "X128") + { + CCstatus.ImageGainceiling = GAINCEILING_128X; + } + else + { + CCstatus.ImageGainceiling = GAINCEILING_2X; + } + } + + else if ((toUpper(splitted[0]) == "CAMQUALITY") && (splitted.size() > 1)) + { + int _ImageQuality = std::stoi(splitted[1]); + CCstatus.ImageQuality = clipInt(_ImageQuality, 63, 6); + } + + else if ((toUpper(splitted[0]) == "CAMBRIGHTNESS") && (splitted.size() > 1)) + { + int _ImageBrightness = std::stoi(splitted[1]); + CCstatus.ImageBrightness = clipInt(_ImageBrightness, 2, -2); + } + + else if ((toUpper(splitted[0]) == "CAMCONTRAST") && (splitted.size() > 1)) + { + int _ImageContrast = std::stoi(splitted[1]); + CCstatus.ImageContrast = clipInt(_ImageContrast, 2, -2); + } + + else if ((toUpper(splitted[0]) == "CAMSATURATION") && (splitted.size() > 1)) + { + int _ImageSaturation = std::stoi(splitted[1]); + CCstatus.ImageSaturation = clipInt(_ImageSaturation, 2, -2); + } + + else if ((toUpper(splitted[0]) == "CAMSHARPNESS") && (splitted.size() > 1)) + { + int _ImageSharpness = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageSharpness = clipInt(_ImageSharpness, 2, -2); + } + else + { + CCstatus.ImageSharpness = clipInt(_ImageSharpness, 3, -3); + } + } + + else if ((toUpper(splitted[0]) == "CAMAUTOSHARPNESS") && (splitted.size() > 1)) + { + CCstatus.ImageAutoSharpness = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMSPECIALEFFECT") && (splitted.size() > 1)) + { + std::string _ImageSpecialEffect = toUpper(splitted[1]); + if (_ImageSpecialEffect == "NEGATIVE") + { + CCstatus.ImageSpecialEffect = 1; + } + else if (_ImageSpecialEffect == "GRAYSCALE") + { + CCstatus.ImageSpecialEffect = 2; + } + else if (_ImageSpecialEffect == "RED") + { + CCstatus.ImageSpecialEffect = 3; + } + else if (_ImageSpecialEffect == "GREEN") + { + CCstatus.ImageSpecialEffect = 4; + } + else if (_ImageSpecialEffect == "BLUE") + { + CCstatus.ImageSpecialEffect = 5; + } + else if (_ImageSpecialEffect == "RETRO") + { + CCstatus.ImageSpecialEffect = 6; + } + else + { + CCstatus.ImageSpecialEffect = 0; + } + } + + else if ((toUpper(splitted[0]) == "CAMWBMODE") && (splitted.size() > 1)) + { + std::string _ImageWbMode = toUpper(splitted[1]); + if (_ImageWbMode == "SUNNY") + { + CCstatus.ImageWbMode = 1; + } + else if (_ImageWbMode == "CLOUDY") + { + CCstatus.ImageWbMode = 2; + } + else if (_ImageWbMode == "OFFICE") + { + CCstatus.ImageWbMode = 3; + } + else if (_ImageWbMode == "HOME") + { + CCstatus.ImageWbMode = 4; + } + else + { + CCstatus.ImageWbMode = 0; + } + } + + else if ((toUpper(splitted[0]) == "CAMAWB") && (splitted.size() > 1)) + { + CCstatus.ImageAwb = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAWBGAIN") && (splitted.size() > 1)) + { + CCstatus.ImageAwbGain = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAEC") && (splitted.size() > 1)) + { + CCstatus.ImageAec = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAEC2") && (splitted.size() > 1)) + { + CCstatus.ImageAec2 = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAELEVEL") && (splitted.size() > 1)) + { + int _ImageAeLevel = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 2, -2); + } + else + { + CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 5, -5); + } + } + + else if ((toUpper(splitted[0]) == "CAMAECVALUE") && (splitted.size() > 1)) + { + int _ImageAecValue = std::stoi(splitted[1]); + CCstatus.ImageAecValue = clipInt(_ImageAecValue, 1200, 0); + } + + else if ((toUpper(splitted[0]) == "CAMAGC") && (splitted.size() > 1)) + { + CCstatus.ImageAgc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMAGCGAIN") && (splitted.size() > 1)) + { + int _ImageAgcGain = std::stoi(splitted[1]); + CCstatus.ImageAgcGain = clipInt(_ImageAgcGain, 30, 0); + } + + else if ((toUpper(splitted[0]) == "CAMBPC") && (splitted.size() > 1)) + { + CCstatus.ImageBpc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMWPC") && (splitted.size() > 1)) + { + CCstatus.ImageWpc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMRAWGMA") && (splitted.size() > 1)) + { + CCstatus.ImageRawGma = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMLENC") && (splitted.size() > 1)) + { + CCstatus.ImageLenc = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMHMIRROR") && (splitted.size() > 1)) + { + CCstatus.ImageHmirror = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMVFLIP") && (splitted.size() > 1)) + { + CCstatus.ImageVflip = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMDCW") && (splitted.size() > 1)) + { + CCstatus.ImageDcw = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMSDENOISE") && (splitted.size() > 1)) + { + int _ImageDenoiseLevel = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageDenoiseLevel = 0; + } + else + { + CCstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0); + } + } + + else if ((toUpper(splitted[0]) == "CAMZOOM") && (splitted.size() > 1)) + { + CCstatus.ImageZoomEnabled = stringToBoolean(toUpper(splitted[1])); + } + + else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETX") && (splitted.size() > 1)) + { + int _ImageZoomOffsetX = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960); + } + } + + else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETY") && (splitted.size() > 1)) + { + int _ImageZoomOffsetY = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720); + } + } + + else if ((toUpper(splitted[0]) == "CAMZOOMSIZE") && (splitted.size() > 1)) + { + int _ImageZoomSize = std::stoi(splitted[1]); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0); + } + } + + else if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1)) + { + float ledintensity = std::stof(splitted[1]); + Camera.SetLEDIntensity(ledintensity); + } + + else if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1)) + { + CCstatus.DemoMode = stringToBoolean(toUpper(splitted[1])); + if (CCstatus.DemoMode) + { + Camera.useDemoMode(); + } + } + } + + Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + + rawImage = new CImageBasis("rawImage"); + rawImage->CreateEmptyImage(CCstatus.ImageWidth, CCstatus.ImageHeight, 3); + + return true; +} + +ClassFlowTakeImage::ClassFlowTakeImage(std::vector *lfc) : ClassFlowImage(lfc, TAG) +{ + imagesLocation = "/log/source"; + imagesRetention = 5; + SetInitialParameter(); +} + +string ClassFlowTakeImage::getHTMLSingleStep(string host) +{ + string result; + result = "Raw Image:
\n\n"; + return result; +} + +// wird bei jeder Auswertrunde aufgerufen +bool ClassFlowTakeImage::doFlow(string zwtime) +{ + psram_init_shared_memory_for_take_image_step(); + + string logPath = CreateLogFolder(zwtime); + + int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash"); +#endif + +#ifdef WIFITURNOFF + esp_wifi_stop(); // to save power usage and +#endif + + // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden + if (CFstatus.changedCameraSettings) + { + Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + CFstatus.changedCameraSettings = false; + } + + takePictureWithFlash(flash_duration); + +#ifdef WIFITURNOFF + esp_wifi_start(); +#endif + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash"); +#endif + + LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage); + + RemoveOldLogs(); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs"); +#endif + + psram_deinit_shared_memory_for_take_image_step(); + + return true; +} + +esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req) +{ + int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + return Camera.CaptureToHTTP(req, flash_duration); +} + +ImageData *ClassFlowTakeImage::SendRawImage(void) +{ + CImageBasis *zw = new CImageBasis("SendRawImage", rawImage); + ImageData *id; + int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000); + Camera.CaptureToBasisImage(zw, flash_duration); + time(&TimeImageTaken); + localtime(&TimeImageTaken); + + id = zw->writeToMemoryAsJPG(); + delete zw; + return id; +} + +time_t ClassFlowTakeImage::getTimeImageTaken(void) +{ + return TimeImageTaken; +} + +ClassFlowTakeImage::~ClassFlowTakeImage(void) +{ + delete rawImage; +} diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index f04a0c282..ce548c83f 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -1,1590 +1,1590 @@ -#include "MainFlowControl.h" - -#include -#include -#include "string.h" -#include "esp_log.h" -#include - -#include -#include - -#include "../../include/defines.h" -#include "Helper.h" -#include "statusled.h" - -#include "esp_camera.h" -#include "time_sntp.h" -#include "ClassControllCamera.h" - -#include "ClassFlowControll.h" - -#include "ClassLogFile.h" -#include "server_GPIO.h" - -#include "server_file.h" - -#include "read_wlanini.h" -#include "connect_wlan.h" -#include "psram.h" - -// support IDF 5.x -#ifndef portTICK_RATE_MS -#define portTICK_RATE_MS portTICK_PERIOD_MS -#endif - -ClassFlowControll flowctrl; -camera_flow_config_temp_t CFstatus; - -TaskHandle_t xHandletask_autodoFlow = NULL; - -bool bTaskAutoFlowCreated = false; -bool flowisrunning = false; - -long auto_interval = 0; -bool autostartIsEnabled = false; - -int countRounds = 0; -bool isPlannedReboot = false; - -static const char *TAG = "MAINCTRL"; - -// #define DEBUG_DETAIL_ON - -void CheckIsPlannedReboot(void) -{ - FILE *pfile; - - if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) - { - // LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Initial boot or not a planned reboot"); - isPlannedReboot = false; - } - else - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot"); - DeleteFile("/sdcard/reboot.txt"); // Prevent Boot Loop!!! - isPlannedReboot = true; - } -} - -bool getIsPlannedReboot(void) -{ - return isPlannedReboot; -} - -int getCountFlowRounds(void) -{ - return countRounds; -} - -esp_err_t GetJPG(std::string _filename, httpd_req_t *req) -{ - return flowctrl.GetJPGStream(_filename, req); -} - -esp_err_t GetRawJPG(httpd_req_t *req) -{ - return flowctrl.SendRawJPG(req); -} - -bool isSetupModusActive(void) -{ - return flowctrl.getStatusSetupModus(); -} - -void DeleteMainFlowTask(void) -{ -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "DeleteMainFlowTask: xHandletask_autodoFlow: %ld", (long)xHandletask_autodoFlow); -#endif - - if (xHandletask_autodoFlow != NULL) - { - vTaskDelete(xHandletask_autodoFlow); - xHandletask_autodoFlow = NULL; - } - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Killed: xHandletask_autodoFlow"); -#endif -} - -void doInit(void) -{ -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Start flowctrl.InitFlow(config);"); -#endif - flowctrl.InitFlow(CONFIG_FILE); -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Finished flowctrl.InitFlow(config);"); -#endif - - /* GPIO handler has to be initialized before MQTT init to ensure proper topic subscription */ - gpio_handler_init(); - -#ifdef ENABLE_MQTT - flowctrl.StartMQTTService(); -#endif // ENABLE_MQTT -} - -bool doflow(void) -{ - std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); - ESP_LOGD(TAG, "doflow - start %s", zw_time.c_str()); - flowisrunning = true; - flowctrl.doFlow(zw_time); - flowisrunning = false; - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "doflow - end %s", zw_time.c_str()); -#endif - - return true; -} - -esp_err_t setCCstatusToCFstatus(void) -{ - CFstatus.CamSensor_id = CCstatus.CamSensor_id; - - CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; - CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; - - CFstatus.ImageQuality = CCstatus.ImageQuality; - CFstatus.ImageBrightness = CCstatus.ImageBrightness; - CFstatus.ImageContrast = CCstatus.ImageContrast; - CFstatus.ImageSaturation = CCstatus.ImageSaturation; - CFstatus.ImageSharpness = CCstatus.ImageSharpness; - CFstatus.ImageAutoSharpness = CCstatus.ImageAutoSharpness; - CFstatus.ImageWbMode = CCstatus.ImageWbMode; - CFstatus.ImageAwb = CCstatus.ImageAwb; - CFstatus.ImageAwbGain = CCstatus.ImageAwbGain; - CFstatus.ImageAec = CCstatus.ImageAec; - CFstatus.ImageAec2 = CCstatus.ImageAec2; - CFstatus.ImageAeLevel = CCstatus.ImageAeLevel; - CFstatus.ImageAecValue = CCstatus.ImageAecValue; - CFstatus.ImageAgc = CCstatus.ImageAgc; - CFstatus.ImageAgcGain = CCstatus.ImageAgcGain; - CFstatus.ImageBpc = CCstatus.ImageBpc; - CFstatus.ImageWpc = CCstatus.ImageWpc; - CFstatus.ImageRawGma = CCstatus.ImageRawGma; - CFstatus.ImageLenc = CCstatus.ImageLenc; - CFstatus.ImageSpecialEffect = CCstatus.ImageSpecialEffect; - CFstatus.ImageHmirror = CCstatus.ImageHmirror; - CFstatus.ImageVflip = CCstatus.ImageVflip; - CFstatus.ImageDcw = CCstatus.ImageDcw; - CFstatus.ImageDenoiseLevel = CCstatus.ImageDenoiseLevel; - - CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; - - CFstatus.ImageZoomEnabled = CCstatus.ImageZoomEnabled; - CFstatus.ImageZoomOffsetX = CCstatus.ImageZoomOffsetX; - CFstatus.ImageZoomOffsetY = CCstatus.ImageZoomOffsetY; - CFstatus.ImageZoomSize = CCstatus.ImageZoomSize; - - CFstatus.WaitBeforePicture = CCstatus.WaitBeforePicture; - - return ESP_OK; -} - -esp_err_t setCFstatusToCCstatus(void) -{ - // CCstatus.CamSensor_id = CFstatus.CamSensor_id; - - CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; - CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; - - CCstatus.ImageQuality = CFstatus.ImageQuality; - CCstatus.ImageBrightness = CFstatus.ImageBrightness; - CCstatus.ImageContrast = CFstatus.ImageContrast; - CCstatus.ImageSaturation = CFstatus.ImageSaturation; - CCstatus.ImageSharpness = CFstatus.ImageSharpness; - CCstatus.ImageAutoSharpness = CFstatus.ImageAutoSharpness; - CCstatus.ImageWbMode = CFstatus.ImageWbMode; - CCstatus.ImageAwb = CFstatus.ImageAwb; - CCstatus.ImageAwbGain = CFstatus.ImageAwbGain; - CCstatus.ImageAec = CFstatus.ImageAec; - CCstatus.ImageAec2 = CFstatus.ImageAec2; - CCstatus.ImageAeLevel = CFstatus.ImageAeLevel; - CCstatus.ImageAecValue = CFstatus.ImageAecValue; - CCstatus.ImageAgc = CFstatus.ImageAgc; - CCstatus.ImageAgcGain = CFstatus.ImageAgcGain; - CCstatus.ImageBpc = CFstatus.ImageBpc; - CCstatus.ImageWpc = CFstatus.ImageWpc; - CCstatus.ImageRawGma = CFstatus.ImageRawGma; - CCstatus.ImageLenc = CFstatus.ImageLenc; - CCstatus.ImageSpecialEffect = CFstatus.ImageSpecialEffect; - CCstatus.ImageHmirror = CFstatus.ImageHmirror; - CCstatus.ImageVflip = CFstatus.ImageVflip; - CCstatus.ImageDcw = CFstatus.ImageDcw; - CCstatus.ImageDenoiseLevel = CFstatus.ImageDenoiseLevel; - - CCstatus.ImageLedIntensity = CFstatus.ImageLedIntensity; - - CCstatus.ImageZoomEnabled = CFstatus.ImageZoomEnabled; - CCstatus.ImageZoomOffsetX = CFstatus.ImageZoomOffsetX; - CCstatus.ImageZoomOffsetY = CFstatus.ImageZoomOffsetY; - CCstatus.ImageZoomSize = CFstatus.ImageZoomSize; - - CCstatus.WaitBeforePicture = CFstatus.WaitBeforePicture; - - return ESP_OK; -} - -esp_err_t setCFstatusToCam(void) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - s->set_framesize(s, CFstatus.ImageFrameSize); - s->set_gainceiling(s, CFstatus.ImageGainceiling); - - s->set_quality(s, CFstatus.ImageQuality); // 0 - 63 - - s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 - s->set_contrast(s, CFstatus.ImageContrast); // -2 to 2 - s->set_saturation(s, CFstatus.ImageSaturation); // -2 to 2 - // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 - Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); - - s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable - s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 - s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 - s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable - - s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable - s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 - - s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable - s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable - - s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable - - s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable - s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable - - s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable - - s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable - s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable - - s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - // special_effect muß als Letztes gesetzt werden, sonst geht es nicht - s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) - - TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; - vTaskDelay(xDelay2); - - return ESP_OK; - } - else - { - return ESP_FAIL; - } -} - -esp_err_t handler_get_heap(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_get_heap - Start"); - ESP_LOGD(TAG, "handler_get_heap uri: %s", req->uri); -#endif - - std::string zw = "Heap info:
" + getESPHeapInfo(); - -#ifdef TASK_ANALYSIS_ON - char *pcTaskList = (char *)calloc_psram_heap(std::string(TAG) + "->pcTaskList", 1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - if (pcTaskList) - { - vTaskList(pcTaskList); - zw = zw + "

Task info:
Name | State | Prio | Lowest stacksize | Creation order | CPU (-1=NoAffinity)
" + std::string(pcTaskList) + "
"; - free_psram_heap(std::string(TAG) + "->pcTaskList", pcTaskList); - } - else - { - zw = zw + "

Task info:
ERROR - Allocation of TaskList buffer in PSRAM failed"; - } -#endif - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (zw.length() > 0) - { - httpd_resp_send(req, zw.c_str(), zw.length()); - } - else - { - httpd_resp_send(req, NULL, 0); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_get_heap - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_init(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_init - Start"); - ESP_LOGD(TAG, "handler_doinit uri: %s", req->uri); -#endif - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - const char *resp_str = "Init started
"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - - doInit(); - - resp_str = "Init done
"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_init - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_stream(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_stream - Start"); - ESP_LOGD(TAG, "handler_stream uri: %s", req->uri); -#endif - - char _query[50]; - char _value[10]; - bool flashlightOn = false; - - if (httpd_req_get_url_query_str(req, _query, 50) == ESP_OK) - { - // ESP_LOGD(TAG, "Query: %s", _query); - if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "flashlight is found%s", _value); -#endif - if (strlen(_value) > 0) - { - flashlightOn = true; - } - } - } - - Camera.CaptureToStream(req, flashlightOn); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_stream - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_flow_start(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_flow_start - Start"); -#endif - - ESP_LOGD(TAG, "handler_flow_start uri: %s", req->uri); - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (autostartIsEnabled) - { - xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by REST API /flow_start"); - const char *resp_str = "The flow is going to be started immediately or is already running"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - else - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by REST API, but flow is not active!"); - const char *resp_str = "WARNING: Flow start triggered by REST API, but flow is not active"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_flow_start - Done"); -#endif - - return ESP_OK; -} - -#ifdef ENABLE_MQTT -esp_err_t MQTTCtrlFlowStart(std::string _topic) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Start"); -#endif - - ESP_LOGD(TAG, "MQTTCtrlFlowStart: topic %s", _topic.c_str()); - - if (autostartIsEnabled) - { - xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by MQTT topic " + _topic); - } - else - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by MQTT topic " + _topic + ", but flow is not active!"); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Done"); -#endif - - return ESP_OK; -} -#endif // ENABLE_MQTT - -esp_err_t handler_json(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_json - Start"); -#endif - - ESP_LOGD(TAG, "handler_JSON uri: %s", req->uri); - - if (bTaskAutoFlowCreated) - { - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_set_type(req, "application/json"); - - std::string zw = flowctrl.getJSON(); - if (zw.length() > 0) - { - httpd_resp_send(req, zw.c_str(), zw.length()); - } - else - { - httpd_resp_send(req, NULL, 0); - } - } - else - { - httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /json not yet available!"); - return ESP_ERR_NOT_FOUND; - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_JSON - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_wasserzaehler(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler water counter - Start"); -#endif - - if (bTaskAutoFlowCreated) - { - bool _rawValue = false; - bool _noerror = false; - bool _all = false; - std::string _type = "value"; - string zw; - - ESP_LOGD(TAG, "handler water counter uri: %s", req->uri); - - char _query[100]; - char _size[10]; - - if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) - { - // ESP_LOGD(TAG, "Query: %s", _query); - if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "all is found%s", _size); -#endif - _all = true; - } - - if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "all is found: %s", _size); -#endif - _type = std::string(_size); - } - - if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "rawvalue is found: %s", _size); -#endif - _rawValue = true; - } - - if (httpd_query_key_value(_query, "noerror", _size, 10) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "noerror is found: %s", _size); -#endif - _noerror = true; - } - } - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (_all) - { - httpd_resp_set_type(req, "text/plain"); - ESP_LOGD(TAG, "TYPE: %s", _type.c_str()); - int _intype = READOUT_TYPE_VALUE; - - if (_type == "prevalue") - { - _intype = READOUT_TYPE_PREVALUE; - } - - if (_type == "raw") - { - _intype = READOUT_TYPE_RAWVALUE; - } - - if (_type == "error") - { - _intype = READOUT_TYPE_ERROR; - } - - zw = flowctrl.getReadoutAll(_intype); - ESP_LOGD(TAG, "ZW: %s", zw.c_str()); - - if (zw.length() > 0) - { - httpd_resp_send(req, zw.c_str(), zw.length()); - } - - return ESP_OK; - } - - std::string *status = flowctrl.getActStatus(); - string query = std::string(_query); - // ESP_LOGD(TAG, "Query: %s, query.c_str()); - - if (query.find("full") != std::string::npos) - { - string txt; - txt = ""; - - if ((countRounds <= 1) && (*status != std::string("Flow finished"))) - { - // First round not completed yet - txt += "

Please wait for the first round to complete!

Current state: " + *status + "

\n"; - } - else - { - txt += "

Value

"; - } - - httpd_resp_sendstr_chunk(req, txt.c_str()); - } - - zw = flowctrl.getReadout(_rawValue, _noerror, 0); - - if (zw.length() > 0) - { - httpd_resp_sendstr_chunk(req, zw.c_str()); - } - - if (query.find("full") != std::string::npos) - { - string txt, zw; - - if ((countRounds <= 1) && (*status != std::string("Flow finished"))) - { - // First round not completed yet - // Nothing to do - } - else - { - /* Digital ROIs */ - txt = ""; - txt += "

Recognized Digit ROIs (previous round)

\n"; - txt += "\n"; - - std::vector htmlinfodig; - htmlinfodig = flowctrl.GetAllDigital(); - - for (int i = 0; i < htmlinfodig.size(); ++i) - { - if (flowctrl.GetTypeDigital() == Digital) - { - if (htmlinfodig[i]->val >= 10) - { - zw = "NaN"; - } - else - { - zw = to_string((int)htmlinfodig[i]->val); - } - - txt += "\n"; - } - else - { - std::stringstream stream; - stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val; - zw = stream.str(); - - if (std::stod(zw) >= 10) - { - zw = "NaN"; - } - - txt += "\n"; - } - delete htmlinfodig[i]; - } - - htmlinfodig.clear(); - - txt += "

" + zw + "

filename + "\">

" + zw + "

filename + "\">

\n"; - httpd_resp_sendstr_chunk(req, txt.c_str()); - - /* Analog ROIs */ - txt = "

Recognized Analog ROIs (previous round)

\n"; - txt += "\n"; - - std::vector htmlinfoana; - htmlinfoana = flowctrl.GetAllAnalog(); - - for (int i = 0; i < htmlinfoana.size(); ++i) - { - std::stringstream stream; - stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val; - zw = stream.str(); - - if (std::stod(zw) >= 10) - { - zw = "NaN"; - } - - txt += "\n"; - delete htmlinfoana[i]; - } - - htmlinfoana.clear(); - - txt += "\n

" + zw + "

filename + "\">

\n"; - httpd_resp_sendstr_chunk(req, txt.c_str()); - - /* Full Image - * Only show it after the image got taken and aligned */ - txt = "

Aligned Image (current round)

\n"; - - if ((*status == std::string("Initialization")) || - (*status == std::string("Initialization (delayed)")) || - (*status == std::string("Take Image"))) - { - txt += "

Current state: " + *status + "

\n"; - } - else - { - txt += "\n"; - } - httpd_resp_sendstr_chunk(req, txt.c_str()); - } - } - - /* Respond with an empty chunk to signal HTTP response completion */ - httpd_resp_sendstr_chunk(req, NULL); - } - else - { - httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /value not available!"); - return ESP_ERR_NOT_FOUND; - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_wasserzaehler - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_editflow(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_editflow - Start"); -#endif - - ESP_LOGD(TAG, "handler_editflow uri: %s", req->uri); - - char _query[200]; - char _valuechar[30]; - string _task; - - if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) - { - if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "task is found: %s", _valuechar); -#endif - _task = string(_valuechar); - } - } - - if (_task.compare("namenumbers") == 0) - { - ESP_LOGD(TAG, "Get NUMBER list"); - return get_numbers_file_handler(req); - } - - if (_task.compare("data") == 0) - { - ESP_LOGD(TAG, "Get data list"); - return get_data_file_handler(req); - } - - if (_task.compare("tflite") == 0) - { - ESP_LOGD(TAG, "Get tflite list"); - return get_tflite_file_handler(req); - } - - if (_task.compare("copy") == 0) - { - string in, out, zw; - - httpd_query_key_value(_query, "in", _valuechar, 30); - in = string(_valuechar); - httpd_query_key_value(_query, "out", _valuechar, 30); - out = string(_valuechar); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "in: %s", in.c_str()); - ESP_LOGD(TAG, "out: %s", out.c_str()); -#endif - - in = "/sdcard" + in; - out = "/sdcard" + out; - - CopyFile(in, out); - zw = "Copy Done"; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), zw.length()); - } - - if (_task.compare("cutref") == 0) - { - string in, out, zw; - int x, y, dx, dy; - bool enhance = false; - - httpd_query_key_value(_query, "in", _valuechar, 30); - in = string(_valuechar); - - httpd_query_key_value(_query, "out", _valuechar, 30); - out = string(_valuechar); - - httpd_query_key_value(_query, "x", _valuechar, 30); - string _x = string(_valuechar); - x = stoi(_x); - - httpd_query_key_value(_query, "y", _valuechar, 30); - string _y = string(_valuechar); - y = stoi(_y); - - httpd_query_key_value(_query, "dx", _valuechar, 30); - string _dx = string(_valuechar); - dx = stoi(_dx); - - httpd_query_key_value(_query, "dy", _valuechar, 30); - string _dy = string(_valuechar); - dy = stoi(_dy); - -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "in: %s", in.c_str()); - ESP_LOGD(TAG, "out: %s", out.c_str()); - ESP_LOGD(TAG, "x: %s", _x.c_str()); - ESP_LOGD(TAG, "y: %s", _y.c_str()); - ESP_LOGD(TAG, "dx: %s", _dx.c_str()); - ESP_LOGD(TAG, "dy: %s", _dy.c_str()); -#endif - - if (httpd_query_key_value(_query, "enhance", _valuechar, 10) == ESP_OK) - { - string _enhance = string(_valuechar); - - if (_enhance.compare("true") == 0) - { - enhance = true; - } - } - - in = "/sdcard" + in; - out = "/sdcard" + out; - - string out2 = out.substr(0, out.length() - 4) + "_org.jpg"; - - if ((flowctrl.SetupModeActive || (*flowctrl.getActStatus() == std::string("Flow finished"))) && psram_init_shared_memory_for_take_image_step()) - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Taking image for Alignment Mark Update..."); - - CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in); - caic->CutAndSave(out2, x, y, dx, dy); - delete caic; - - CImageBasis *cim = new CImageBasis("cutref", out2); - - if (enhance) - { - cim->Contrast(90); - } - - cim->SaveToFile(out); - delete cim; - - psram_deinit_shared_memory_for_take_image_step(); - zw = "CutImage Done"; - } - else - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Taking image for Alignment Mark not possible while device") + " is busy with a round (Current State: '" + *flowctrl.getActStatus() + "')!"); - zw = "Device Busy"; - } - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), zw.length()); - } - - // wird beim Erstellen eines neuen Referenzbildes aufgerufen - std::string *sys_status = flowctrl.getActStatus(); - - if ((sys_status->c_str() != std::string("Take Image")) && (sys_status->c_str() != std::string("Aligning"))) - { - if ((_task.compare("test_take") == 0) || (_task.compare("cam_settings") == 0)) - { - std::string _host = ""; - - // laden der aktuellen Kameraeinstellungen(CCstatus) in den Zwischenspeicher(CFstatus) - setCCstatusToCFstatus(); // CCstatus >>> CFstatus - - if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) - { - _host = std::string(_valuechar); - } - - if (httpd_query_key_value(_query, "waitb", _valuechar, 30) == ESP_OK) - { - int _waitb = std::stoi(_valuechar); - if (_waitb != 0) - { - CFstatus.WaitBeforePicture = _waitb; - } - } - - if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) - { - int _qual = std::stoi(_valuechar); - CFstatus.ImageQuality = clipInt(_qual, 63, 6); - } - - if (httpd_query_key_value(_query, "bri", _valuechar, 30) == ESP_OK) - { - int _bri = std::stoi(_valuechar); - CFstatus.ImageBrightness = clipInt(_bri, 2, -2); - } - - if (httpd_query_key_value(_query, "con", _valuechar, 30) == ESP_OK) - { - int _con = std::stoi(_valuechar); - CFstatus.ImageContrast = clipInt(_con, 2, -2); - } - - if (httpd_query_key_value(_query, "sat", _valuechar, 30) == ESP_OK) - { - int _sat = std::stoi(_valuechar); - CFstatus.ImageSaturation = clipInt(_sat, 2, -2); - } - - if (httpd_query_key_value(_query, "shp", _valuechar, 30) == ESP_OK) - { - int _shp = std::stoi(_valuechar); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CFstatus.ImageSharpness = clipInt(_shp, 2, -2); - } - else - { - CFstatus.ImageSharpness = clipInt(_shp, 3, -3); - } - } - - if (httpd_query_key_value(_query, "ashp", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageAutoSharpness = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "spe", _valuechar, 30) == ESP_OK) - { - int _spe = std::stoi(_valuechar); - CFstatus.ImageSpecialEffect = clipInt(_spe, 6, 0); - } - - if (httpd_query_key_value(_query, "wbm", _valuechar, 30) == ESP_OK) - { - int _wbm = std::stoi(_valuechar); - CFstatus.ImageWbMode = clipInt(_wbm, 4, 0); - } - - if (httpd_query_key_value(_query, "awb", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageAwb = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "awbg", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageAwbGain = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "aec", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageAec = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "aec2", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageAec2 = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "ael", _valuechar, 30) == ESP_OK) - { - int _ael = std::stoi(_valuechar); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CFstatus.ImageAeLevel = clipInt(_ael, 2, -2); - } - else - { - CFstatus.ImageAeLevel = clipInt(_ael, 5, -5); - } - } - - if (httpd_query_key_value(_query, "aecv", _valuechar, 30) == ESP_OK) - { - int _aecv = std::stoi(_valuechar); - CFstatus.ImageAecValue = clipInt(_aecv, 1200, 0); - } - - if (httpd_query_key_value(_query, "agc", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageAgc = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "agcg", _valuechar, 30) == ESP_OK) - { - int _agcg = std::stoi(_valuechar); - CFstatus.ImageAgcGain = clipInt(_agcg, 30, 0); - } - - if (httpd_query_key_value(_query, "bpc", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageBpc = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "wpc", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageWpc = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "rgma", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageRawGma = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "lenc", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageLenc = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "mirror", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageHmirror = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "flip", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageVflip = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "dcw", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageDcw = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "den", _valuechar, 30) == ESP_OK) - { - int _ImageDenoiseLevel = std::stoi(_valuechar); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CCstatus.ImageDenoiseLevel = 0; - } - else - { - CFstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0); - } - } - - if (httpd_query_key_value(_query, "zoom", _valuechar, 30) == ESP_OK) - { - CFstatus.ImageZoomEnabled = numericStrToBool(_valuechar); - } - - if (httpd_query_key_value(_query, "zoomx", _valuechar, 30) == ESP_OK) - { - int _ImageZoomOffsetX = std::stoi(_valuechar); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480); - } - else if (CCstatus.CamSensor_id == OV3660_PID) - { - CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704); - } - else if (CCstatus.CamSensor_id == OV5640_PID) - { - CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960); - } - } - - if (httpd_query_key_value(_query, "zoomy", _valuechar, 30) == ESP_OK) - { - int _ImageZoomOffsetY = std::stoi(_valuechar); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360); - } - else if (CCstatus.CamSensor_id == OV3660_PID) - { - CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528); - } - else if (CCstatus.CamSensor_id == OV5640_PID) - { - CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720); - } - } - - if (httpd_query_key_value(_query, "zooms", _valuechar, 30) == ESP_OK) - { - int _ImageZoomSize = std::stoi(_valuechar); - if (CCstatus.CamSensor_id == OV2640_PID) - { - CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0); - } - else if (CCstatus.CamSensor_id == OV3660_PID) - { - CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0); - } - else if (CCstatus.CamSensor_id == OV5640_PID) - { - CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0); - } - } - - if (httpd_query_key_value(_query, "ledi", _valuechar, 30) == ESP_OK) - { - float _ImageLedIntensity = std::stof(_valuechar); - Camera.SetLEDIntensity(_ImageLedIntensity); - CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; - } - - if (_task.compare("cam_settings") == 0) - { - // wird aufgerufen, wenn das Referenzbild + Kameraeinstellungen gespeichert wurden - setCFstatusToCCstatus(); // CFstatus >>> CCstatus - - // Kameraeinstellungen wurden verädert - CFstatus.changedCameraSettings = true; - - ESP_LOGD(TAG, "Cam Settings set"); - std::string _zw = "CamSettingsSet"; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, _zw.c_str(), _zw.length()); - } - else - { - // wird aufgerufen, wenn ein neues Referenzbild erstellt oder aktualisiert wurde - // CFstatus >>> Kamera - setCFstatusToCam(); - - Camera.SetQualityZoomSize(CFstatus.ImageQuality, CFstatus.ImageFrameSize, CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); - // Camera.SetZoomSize(CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); - - // Kameraeinstellungen wurden verädert - CFstatus.changedCameraSettings = true; - - ESP_LOGD(TAG, "test_take - vor TakeImage"); - std::string image_temp = flowctrl.doSingleStep("[TakeImage]", _host); - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, image_temp.c_str(), image_temp.length()); - } - } - - if (_task.compare("test_align") == 0) - { - std::string _host = ""; - - if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) - { - _host = std::string(_valuechar); - } - - std::string zw = flowctrl.doSingleStep("[Alignment]", _host); - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, zw.c_str(), zw.length()); - } - } - else - { - std::string _zw = "DeviceIsBusy"; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, _zw.c_str(), _zw.length()); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_editflow - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_statusflow(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_statusflow - Start"); -#endif - - const char *resp_str; - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (bTaskAutoFlowCreated) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "handler_statusflow: %s", req->uri); -#endif - - string *zw = flowctrl.getActStatusWithTime(); - resp_str = zw->c_str(); - - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - else - { - resp_str = "Flow task not yet created"; - httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_statusflow - Done"); -#endif - - return ESP_OK; -} - -esp_err_t handler_cputemp(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_cputemp - Start"); -#endif - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, std::to_string((int)temperatureRead()).c_str(), HTTPD_RESP_USE_STRLEN); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_cputemp - End"); -#endif - - return ESP_OK; -} - -esp_err_t handler_rssi(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_rssi - Start"); -#endif - - if (getWIFIisConnected()) - { - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, std::to_string(get_WIFI_RSSI()).c_str(), HTTPD_RESP_USE_STRLEN); - } - else - { - httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "WIFI not (yet) connected: REST API /rssi not available!"); - return ESP_ERR_NOT_FOUND; - } - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_rssi - End"); -#endif - - return ESP_OK; -} - -esp_err_t handler_uptime(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_uptime - Start"); -#endif - - std::string formatedUptime = getFormatedUptime(false); - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - httpd_resp_send(req, formatedUptime.c_str(), formatedUptime.length()); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_uptime - End"); -#endif - - return ESP_OK; -} - -esp_err_t handler_prevalue(httpd_req_t *req) -{ -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_prevalue - Start"); - ESP_LOGD(TAG, "handler_prevalue: %s", req->uri); -#endif - - // Default usage message when handler gets called without any parameter - const std::string RESTUsageInfo = - "00: Handler usage:
" - "- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main
" - "- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678
" - "NOTE:
" - "value >= 0.0: Set PreValue to provided value
" - "value < 0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)"; - - // Default return error message when no return is programmed - std::string sReturnMessage = "E90: Uninitialized"; - - char _query[100]; - char _numbersname[50] = "default"; - char _value[20] = ""; - - httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Query: %s", _query); -#endif - - if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) - { - // If request is incomplete - sReturnMessage = "E91: Query parameter incomplete or not valid!
" - "Call /setPreValue to show REST API usage info and/or check documentation"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - - if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Value: %s", _value); -#endif - } - } - else - { - // if no parameter is provided, print handler usage - httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length()); - return ESP_OK; - } - - if (strlen(_value) == 0) - { - // If no value is povided --> return actual PreValue - sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); - - if (sReturnMessage.empty()) - { - sReturnMessage = "E92: Numbers name not found"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - } - else - { - // New value is positive: Set PreValue to provided value and return value - // New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) + ", value: " + std::string(_value)); - - if (!flowctrl.UpdatePrevalue(_value, _numbersname, true)) - { - sReturnMessage = "E93: Update request rejected. Please check device logs for more details"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - - sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); - - if (sReturnMessage.empty()) - { - sReturnMessage = "E94: Numbers name not found"; - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - return ESP_FAIL; - } - } - - httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); - -#ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("handler_prevalue - End"); -#endif - - return ESP_OK; -} - -void task_autodoFlow(void *pvParameter) -{ - int64_t fr_start, fr_delta_ms; - - bTaskAutoFlowCreated = true; - - if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC)) - { - flowctrl.setActStatus("Initialization (delayed)"); - // #ifdef ENABLE_MQTT - // MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later - // #endif //ENABLE_MQTT - vTaskDelay(60 * 5000 / portTICK_PERIOD_MS); // Wait 5 minutes to give time to do an OTA update or fetch the log - } - - ESP_LOGD(TAG, "task_autodoFlow: start"); - doInit(); - - flowctrl.setAutoStartInterval(auto_interval); - autostartIsEnabled = flowctrl.getIsAutoStart(); - - if (isSetupModusActive()) - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "We are in Setup Mode -> Not starting Auto Flow!"); - autostartIsEnabled = false; - // 15.7.0 Setup Wizard cannot take a Reference Picture #2953 - // std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); - // flowctrl.doFlowTakeImageOnly(zw_time); - } - - if (autostartIsEnabled) - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Starting Flow..."); - } - else - { - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Autostart is not enabled -> Not starting Flow"); - } - - while (autostartIsEnabled) - { - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs - time_t roundStartTime = getUpTime(); - - std::string _zw = "Round #" + std::to_string(++countRounds) + " started"; - LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw); - - fr_start = esp_timer_get_time(); - - if (flowisrunning) - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Autoflow: doFlow is already running!"); -#endif - } - else - { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Autoflow: doFlow is started"); -#endif - flowisrunning = true; - doflow(); -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "Remove older log files"); -#endif - LogFile.RemoveOldLogFile(); - LogFile.RemoveOldDataLog(); - } - - // Round finished -> Logfile - LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) + " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)"); - - // CPU Temp -> Logfile - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C"); - - // WIFI Signal Strength (RSSI) -> Logfile - LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm"); - - // Check if time is synchronized (if NTP is configured) - if (getUseNtp() && !getTimeIsSet()) - { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time server is configured, but time is not yet set!"); - StatusLED(TIME_CHECK, 1, false); - } - -#if (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES) - wifiRoamingQuery(); -#endif - -// Scan channels and check if an AP with better RSSI is available, then disconnect and try to reconnect to AP with better RSSI -// NOTE: Keep this direct before the following task delay, because scan is done in blocking mode and this takes ca. 1,5 - 2s. -#ifdef WLAN_USE_ROAMING_BY_SCANNING - wifiRoamByScanning(); -#endif - - fr_delta_ms = (esp_timer_get_time() - fr_start) / 1000; - - if (auto_interval > fr_delta_ms) - { - const TickType_t xDelay = (auto_interval - fr_delta_ms) / portTICK_PERIOD_MS; - ESP_LOGD(TAG, "Autoflow: sleep for: %ldms", (long)xDelay); - vTaskDelay(xDelay); - } - } - - while (1) - { - // Keep flow task running to handle necessary sub tasks like reboot handler, etc.. - vTaskDelay(2000 / portTICK_PERIOD_MS); - } - - vTaskDelete(NULL); // Delete this task if it exits from the loop above - xHandletask_autodoFlow = NULL; - - ESP_LOGD(TAG, "task_autodoFlow: end"); -} - -void InitializeFlowTask(void) -{ - BaseType_t xReturned; - - ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); - - uint32_t stackSize = 16 * 1024; - xReturned = xTaskCreatePinnedToCore(&task_autodoFlow, "task_autodoFlow", stackSize, NULL, tskIDLE_PRIORITY + 2, &xHandletask_autodoFlow, 0); - - if (xReturned != pdPASS) - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Creation task_autodoFlow failed. Requested stack size:" + std::to_string(stackSize)); - LogFile.WriteHeapInfo("Creation task_autodoFlow failed"); - } - - ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); -} - -void register_server_main_flow_task_uri(httpd_handle_t server) -{ - ESP_LOGI(TAG, "server_main_flow_task - Registering URI handlers"); - - httpd_uri_t camuri = {}; - camuri.method = HTTP_GET; - - camuri.uri = "/doinit"; - camuri.handler = handler_init; - camuri.user_ctx = (void *)"Light On"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/setPreValue" - camuri.uri = "/setPreValue.html"; - camuri.handler = handler_prevalue; - camuri.user_ctx = (void *)"Prevalue"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/setPreValue"; - camuri.handler = handler_prevalue; - camuri.user_ctx = (void *)"Prevalue"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/flow_start"; - camuri.handler = handler_flow_start; - camuri.user_ctx = (void *)"Flow Start"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/statusflow.html"; - camuri.handler = handler_statusflow; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/statusflow"; - camuri.handler = handler_statusflow; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/cpu_temperature" - camuri.uri = "/cputemp.html"; - camuri.handler = handler_cputemp; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/cpu_temperature"; - camuri.handler = handler_cputemp; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/rssi" - camuri.uri = "/rssi.html"; - camuri.handler = handler_rssi; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/rssi"; - camuri.handler = handler_rssi; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/uptime"; - camuri.handler = handler_uptime; - camuri.user_ctx = (void *)"Light Off"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/editflow"; - camuri.handler = handler_editflow; - camuri.user_ctx = (void *)"EditFlow"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/value" - camuri.uri = "/value.html"; - camuri.handler = handler_wasserzaehler; - camuri.user_ctx = (void *)"Value"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/value"; - camuri.handler = handler_wasserzaehler; - camuri.user_ctx = (void *)"Value"; - httpd_register_uri_handler(server, &camuri); - - // Legacy API => New: "/value" - camuri.uri = "/wasserzaehler.html"; - camuri.handler = handler_wasserzaehler; - camuri.user_ctx = (void *)"Wasserzaehler"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/json"; - camuri.handler = handler_json; - camuri.user_ctx = (void *)"JSON"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/heap"; - camuri.handler = handler_get_heap; - camuri.user_ctx = (void *)"Heap"; - httpd_register_uri_handler(server, &camuri); - - camuri.uri = "/stream"; - camuri.handler = handler_stream; - camuri.user_ctx = (void *)"stream"; - httpd_register_uri_handler(server, &camuri); -} +#include "MainFlowControl.h" + +#include +#include +#include "string.h" +#include "esp_log.h" +#include + +#include +#include + +#include "../../include/defines.h" +#include "Helper.h" +#include "statusled.h" + +#include "esp_camera.h" +#include "time_sntp.h" +#include "ClassControllCamera.h" + +#include "ClassFlowControll.h" + +#include "ClassLogFile.h" +#include "server_GPIO.h" + +#include "server_file.h" + +#include "read_wlanini.h" +#include "connect_wlan.h" +#include "psram.h" + +// support IDF 5.x +#ifndef portTICK_RATE_MS +#define portTICK_RATE_MS portTICK_PERIOD_MS +#endif + +ClassFlowControll flowctrl; +camera_flow_config_temp_t CFstatus; + +TaskHandle_t xHandletask_autodoFlow = NULL; + +bool bTaskAutoFlowCreated = false; +bool flowisrunning = false; + +long auto_interval = 0; +bool autostartIsEnabled = false; + +int countRounds = 0; +bool isPlannedReboot = false; + +static const char *TAG = "MAINCTRL"; + +// #define DEBUG_DETAIL_ON + +void CheckIsPlannedReboot(void) +{ + FILE *pfile; + + if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) + { + // LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Initial boot or not a planned reboot"); + isPlannedReboot = false; + } + else + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot"); + DeleteFile("/sdcard/reboot.txt"); // Prevent Boot Loop!!! + isPlannedReboot = true; + } +} + +bool getIsPlannedReboot(void) +{ + return isPlannedReboot; +} + +int getCountFlowRounds(void) +{ + return countRounds; +} + +esp_err_t GetJPG(std::string _filename, httpd_req_t *req) +{ + return flowctrl.GetJPGStream(_filename, req); +} + +esp_err_t GetRawJPG(httpd_req_t *req) +{ + return flowctrl.SendRawJPG(req); +} + +bool isSetupModusActive(void) +{ + return flowctrl.getStatusSetupModus(); +} + +void DeleteMainFlowTask(void) +{ +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "DeleteMainFlowTask: xHandletask_autodoFlow: %ld", (long)xHandletask_autodoFlow); +#endif + + if (xHandletask_autodoFlow != NULL) + { + vTaskDelete(xHandletask_autodoFlow); + xHandletask_autodoFlow = NULL; + } + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Killed: xHandletask_autodoFlow"); +#endif +} + +void doInit(void) +{ +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Start flowctrl.InitFlow(config);"); +#endif + flowctrl.InitFlow(CONFIG_FILE); +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Finished flowctrl.InitFlow(config);"); +#endif + + /* GPIO handler has to be initialized before MQTT init to ensure proper topic subscription */ + gpio_handler_init(); + +#ifdef ENABLE_MQTT + flowctrl.StartMQTTService(); +#endif // ENABLE_MQTT +} + +bool doflow(void) +{ + std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); + ESP_LOGD(TAG, "doflow - start %s", zw_time.c_str()); + flowisrunning = true; + flowctrl.doFlow(zw_time); + flowisrunning = false; + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "doflow - end %s", zw_time.c_str()); +#endif + + return true; +} + +esp_err_t setCCstatusToCFstatus(void) +{ + CFstatus.CamSensor_id = CCstatus.CamSensor_id; + + CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; + CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; + + CFstatus.ImageQuality = CCstatus.ImageQuality; + CFstatus.ImageBrightness = CCstatus.ImageBrightness; + CFstatus.ImageContrast = CCstatus.ImageContrast; + CFstatus.ImageSaturation = CCstatus.ImageSaturation; + CFstatus.ImageSharpness = CCstatus.ImageSharpness; + CFstatus.ImageAutoSharpness = CCstatus.ImageAutoSharpness; + CFstatus.ImageWbMode = CCstatus.ImageWbMode; + CFstatus.ImageAwb = CCstatus.ImageAwb; + CFstatus.ImageAwbGain = CCstatus.ImageAwbGain; + CFstatus.ImageAec = CCstatus.ImageAec; + CFstatus.ImageAec2 = CCstatus.ImageAec2; + CFstatus.ImageAeLevel = CCstatus.ImageAeLevel; + CFstatus.ImageAecValue = CCstatus.ImageAecValue; + CFstatus.ImageAgc = CCstatus.ImageAgc; + CFstatus.ImageAgcGain = CCstatus.ImageAgcGain; + CFstatus.ImageBpc = CCstatus.ImageBpc; + CFstatus.ImageWpc = CCstatus.ImageWpc; + CFstatus.ImageRawGma = CCstatus.ImageRawGma; + CFstatus.ImageLenc = CCstatus.ImageLenc; + CFstatus.ImageSpecialEffect = CCstatus.ImageSpecialEffect; + CFstatus.ImageHmirror = CCstatus.ImageHmirror; + CFstatus.ImageVflip = CCstatus.ImageVflip; + CFstatus.ImageDcw = CCstatus.ImageDcw; + CFstatus.ImageDenoiseLevel = CCstatus.ImageDenoiseLevel; + + CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; + + CFstatus.ImageZoomEnabled = CCstatus.ImageZoomEnabled; + CFstatus.ImageZoomOffsetX = CCstatus.ImageZoomOffsetX; + CFstatus.ImageZoomOffsetY = CCstatus.ImageZoomOffsetY; + CFstatus.ImageZoomSize = CCstatus.ImageZoomSize; + + CFstatus.WaitBeforePicture = CCstatus.WaitBeforePicture; + + return ESP_OK; +} + +esp_err_t setCFstatusToCCstatus(void) +{ + // CCstatus.CamSensor_id = CFstatus.CamSensor_id; + + CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; + CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; + + CCstatus.ImageQuality = CFstatus.ImageQuality; + CCstatus.ImageBrightness = CFstatus.ImageBrightness; + CCstatus.ImageContrast = CFstatus.ImageContrast; + CCstatus.ImageSaturation = CFstatus.ImageSaturation; + CCstatus.ImageSharpness = CFstatus.ImageSharpness; + CCstatus.ImageAutoSharpness = CFstatus.ImageAutoSharpness; + CCstatus.ImageWbMode = CFstatus.ImageWbMode; + CCstatus.ImageAwb = CFstatus.ImageAwb; + CCstatus.ImageAwbGain = CFstatus.ImageAwbGain; + CCstatus.ImageAec = CFstatus.ImageAec; + CCstatus.ImageAec2 = CFstatus.ImageAec2; + CCstatus.ImageAeLevel = CFstatus.ImageAeLevel; + CCstatus.ImageAecValue = CFstatus.ImageAecValue; + CCstatus.ImageAgc = CFstatus.ImageAgc; + CCstatus.ImageAgcGain = CFstatus.ImageAgcGain; + CCstatus.ImageBpc = CFstatus.ImageBpc; + CCstatus.ImageWpc = CFstatus.ImageWpc; + CCstatus.ImageRawGma = CFstatus.ImageRawGma; + CCstatus.ImageLenc = CFstatus.ImageLenc; + CCstatus.ImageSpecialEffect = CFstatus.ImageSpecialEffect; + CCstatus.ImageHmirror = CFstatus.ImageHmirror; + CCstatus.ImageVflip = CFstatus.ImageVflip; + CCstatus.ImageDcw = CFstatus.ImageDcw; + CCstatus.ImageDenoiseLevel = CFstatus.ImageDenoiseLevel; + + CCstatus.ImageLedIntensity = CFstatus.ImageLedIntensity; + + CCstatus.ImageZoomEnabled = CFstatus.ImageZoomEnabled; + CCstatus.ImageZoomOffsetX = CFstatus.ImageZoomOffsetX; + CCstatus.ImageZoomOffsetY = CFstatus.ImageZoomOffsetY; + CCstatus.ImageZoomSize = CFstatus.ImageZoomSize; + + CCstatus.WaitBeforePicture = CFstatus.WaitBeforePicture; + + return ESP_OK; +} + +esp_err_t setCFstatusToCam(void) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + s->set_framesize(s, CFstatus.ImageFrameSize); + s->set_gainceiling(s, CFstatus.ImageGainceiling); + + s->set_quality(s, CFstatus.ImageQuality); // 0 - 63 + + s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 + s->set_contrast(s, CFstatus.ImageContrast); // -2 to 2 + s->set_saturation(s, CFstatus.ImageSaturation); // -2 to 2 + // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 + Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); + + s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable + s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 + s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 + s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable + + s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable + s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 + + s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable + s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable + + s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable + s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable + + s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable + s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable + + s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable + + s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable + s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable + + s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + // special_effect muß als Letztes gesetzt werden, sonst geht es nicht + s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + + TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; + vTaskDelay(xDelay2); + + return ESP_OK; + } + else + { + return ESP_FAIL; + } +} + +esp_err_t handler_get_heap(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_get_heap - Start"); + ESP_LOGD(TAG, "handler_get_heap uri: %s", req->uri); +#endif + + std::string zw = "Heap info:
" + getESPHeapInfo(); + +#ifdef TASK_ANALYSIS_ON + char *pcTaskList = (char *)calloc_psram_heap(std::string(TAG) + "->pcTaskList", 1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + if (pcTaskList) + { + vTaskList(pcTaskList); + zw = zw + "

Task info:
Name | State | Prio | Lowest stacksize | Creation order | CPU (-1=NoAffinity)
" + std::string(pcTaskList) + "
"; + free_psram_heap(std::string(TAG) + "->pcTaskList", pcTaskList); + } + else + { + zw = zw + "

Task info:
ERROR - Allocation of TaskList buffer in PSRAM failed"; + } +#endif + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (zw.length() > 0) + { + httpd_resp_send(req, zw.c_str(), zw.length()); + } + else + { + httpd_resp_send(req, NULL, 0); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_get_heap - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_init(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_init - Start"); + ESP_LOGD(TAG, "handler_doinit uri: %s", req->uri); +#endif + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + const char *resp_str = "Init started
"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + + doInit(); + + resp_str = "Init done
"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_init - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_stream(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_stream - Start"); + ESP_LOGD(TAG, "handler_stream uri: %s", req->uri); +#endif + + char _query[50]; + char _value[10]; + bool flashlightOn = false; + + if (httpd_req_get_url_query_str(req, _query, 50) == ESP_OK) + { + // ESP_LOGD(TAG, "Query: %s", _query); + if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "flashlight is found%s", _value); +#endif + if (strlen(_value) > 0) + { + flashlightOn = true; + } + } + } + + Camera.CaptureToStream(req, flashlightOn); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_stream - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_flow_start(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_flow_start - Start"); +#endif + + ESP_LOGD(TAG, "handler_flow_start uri: %s", req->uri); + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (autostartIsEnabled) + { + xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by REST API /flow_start"); + const char *resp_str = "The flow is going to be started immediately or is already running"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + else + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by REST API, but flow is not active!"); + const char *resp_str = "WARNING: Flow start triggered by REST API, but flow is not active"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_flow_start - Done"); +#endif + + return ESP_OK; +} + +#ifdef ENABLE_MQTT +esp_err_t MQTTCtrlFlowStart(std::string _topic) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Start"); +#endif + + ESP_LOGD(TAG, "MQTTCtrlFlowStart: topic %s", _topic.c_str()); + + if (autostartIsEnabled) + { + xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by MQTT topic " + _topic); + } + else + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by MQTT topic " + _topic + ", but flow is not active!"); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Done"); +#endif + + return ESP_OK; +} +#endif // ENABLE_MQTT + +esp_err_t handler_json(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_json - Start"); +#endif + + ESP_LOGD(TAG, "handler_JSON uri: %s", req->uri); + + if (bTaskAutoFlowCreated) + { + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_type(req, "application/json"); + + std::string zw = flowctrl.getJSON(); + if (zw.length() > 0) + { + httpd_resp_send(req, zw.c_str(), zw.length()); + } + else + { + httpd_resp_send(req, NULL, 0); + } + } + else + { + httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /json not yet available!"); + return ESP_ERR_NOT_FOUND; + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_JSON - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_wasserzaehler(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler water counter - Start"); +#endif + + if (bTaskAutoFlowCreated) + { + bool _rawValue = false; + bool _noerror = false; + bool _all = false; + std::string _type = "value"; + string zw; + + ESP_LOGD(TAG, "handler water counter uri: %s", req->uri); + + char _query[100]; + char _size[10]; + + if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) + { + // ESP_LOGD(TAG, "Query: %s", _query); + if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "all is found%s", _size); +#endif + _all = true; + } + + if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "all is found: %s", _size); +#endif + _type = std::string(_size); + } + + if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "rawvalue is found: %s", _size); +#endif + _rawValue = true; + } + + if (httpd_query_key_value(_query, "noerror", _size, 10) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "noerror is found: %s", _size); +#endif + _noerror = true; + } + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (_all) + { + httpd_resp_set_type(req, "text/plain"); + ESP_LOGD(TAG, "TYPE: %s", _type.c_str()); + int _intype = READOUT_TYPE_VALUE; + + if (_type == "prevalue") + { + _intype = READOUT_TYPE_PREVALUE; + } + + if (_type == "raw") + { + _intype = READOUT_TYPE_RAWVALUE; + } + + if (_type == "error") + { + _intype = READOUT_TYPE_ERROR; + } + + zw = flowctrl.getReadoutAll(_intype); + ESP_LOGD(TAG, "ZW: %s", zw.c_str()); + + if (zw.length() > 0) + { + httpd_resp_send(req, zw.c_str(), zw.length()); + } + + return ESP_OK; + } + + std::string *status = flowctrl.getActStatus(); + string query = std::string(_query); + // ESP_LOGD(TAG, "Query: %s, query.c_str()); + + if (query.find("full") != std::string::npos) + { + string txt; + txt = ""; + + if ((countRounds <= 1) && (*status != std::string("Flow finished"))) + { + // First round not completed yet + txt += "

Please wait for the first round to complete!

Current state: " + *status + "

\n"; + } + else + { + txt += "

Value

"; + } + + httpd_resp_sendstr_chunk(req, txt.c_str()); + } + + zw = flowctrl.getReadout(_rawValue, _noerror, 0); + + if (zw.length() > 0) + { + httpd_resp_sendstr_chunk(req, zw.c_str()); + } + + if (query.find("full") != std::string::npos) + { + string txt, zw; + + if ((countRounds <= 1) && (*status != std::string("Flow finished"))) + { + // First round not completed yet + // Nothing to do + } + else + { + /* Digital ROIs */ + txt = ""; + txt += "

Recognized Digit ROIs (previous round)

\n"; + txt += "\n"; + + std::vector htmlinfodig; + htmlinfodig = flowctrl.GetAllDigital(); + + for (int i = 0; i < htmlinfodig.size(); ++i) + { + if (flowctrl.GetTypeDigital() == Digital) + { + if (htmlinfodig[i]->val >= 10) + { + zw = "NaN"; + } + else + { + zw = to_string((int)htmlinfodig[i]->val); + } + + txt += "\n"; + } + else + { + std::stringstream stream; + stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val; + zw = stream.str(); + + if (std::stod(zw) >= 10) + { + zw = "NaN"; + } + + txt += "\n"; + } + delete htmlinfodig[i]; + } + + htmlinfodig.clear(); + + txt += "

" + zw + "

filename + "\">

" + zw + "

filename + "\">

\n"; + httpd_resp_sendstr_chunk(req, txt.c_str()); + + /* Analog ROIs */ + txt = "

Recognized Analog ROIs (previous round)

\n"; + txt += "\n"; + + std::vector htmlinfoana; + htmlinfoana = flowctrl.GetAllAnalog(); + + for (int i = 0; i < htmlinfoana.size(); ++i) + { + std::stringstream stream; + stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val; + zw = stream.str(); + + if (std::stod(zw) >= 10) + { + zw = "NaN"; + } + + txt += "\n"; + delete htmlinfoana[i]; + } + + htmlinfoana.clear(); + + txt += "\n

" + zw + "

filename + "\">

\n"; + httpd_resp_sendstr_chunk(req, txt.c_str()); + + /* Full Image + * Only show it after the image got taken and aligned */ + txt = "

Aligned Image (current round)

\n"; + + if ((*status == std::string("Initialization")) || + (*status == std::string("Initialization (delayed)")) || + (*status == std::string("Take Image"))) + { + txt += "

Current state: " + *status + "

\n"; + } + else + { + txt += "\n"; + } + httpd_resp_sendstr_chunk(req, txt.c_str()); + } + } + + /* Respond with an empty chunk to signal HTTP response completion */ + httpd_resp_sendstr_chunk(req, NULL); + } + else + { + httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /value not available!"); + return ESP_ERR_NOT_FOUND; + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_wasserzaehler - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_editflow(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_editflow - Start"); +#endif + + ESP_LOGD(TAG, "handler_editflow uri: %s", req->uri); + + char _query[200]; + char _valuechar[30]; + string _task; + + if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) + { + if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "task is found: %s", _valuechar); +#endif + _task = string(_valuechar); + } + } + + if (_task.compare("namenumbers") == 0) + { + ESP_LOGD(TAG, "Get NUMBER list"); + return get_numbers_file_handler(req); + } + + if (_task.compare("data") == 0) + { + ESP_LOGD(TAG, "Get data list"); + return get_data_file_handler(req); + } + + if (_task.compare("tflite") == 0) + { + ESP_LOGD(TAG, "Get tflite list"); + return get_tflite_file_handler(req); + } + + if (_task.compare("copy") == 0) + { + string in, out, zw; + + httpd_query_key_value(_query, "in", _valuechar, 30); + in = string(_valuechar); + httpd_query_key_value(_query, "out", _valuechar, 30); + out = string(_valuechar); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "in: %s", in.c_str()); + ESP_LOGD(TAG, "out: %s", out.c_str()); +#endif + + in = "/sdcard" + in; + out = "/sdcard" + out; + + CopyFile(in, out); + zw = "Copy Done"; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, zw.c_str(), zw.length()); + } + + if (_task.compare("cutref") == 0) + { + string in, out, zw; + int x, y, dx, dy; + bool enhance = false; + + httpd_query_key_value(_query, "in", _valuechar, 30); + in = string(_valuechar); + + httpd_query_key_value(_query, "out", _valuechar, 30); + out = string(_valuechar); + + httpd_query_key_value(_query, "x", _valuechar, 30); + string _x = string(_valuechar); + x = stoi(_x); + + httpd_query_key_value(_query, "y", _valuechar, 30); + string _y = string(_valuechar); + y = stoi(_y); + + httpd_query_key_value(_query, "dx", _valuechar, 30); + string _dx = string(_valuechar); + dx = stoi(_dx); + + httpd_query_key_value(_query, "dy", _valuechar, 30); + string _dy = string(_valuechar); + dy = stoi(_dy); + +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "in: %s", in.c_str()); + ESP_LOGD(TAG, "out: %s", out.c_str()); + ESP_LOGD(TAG, "x: %s", _x.c_str()); + ESP_LOGD(TAG, "y: %s", _y.c_str()); + ESP_LOGD(TAG, "dx: %s", _dx.c_str()); + ESP_LOGD(TAG, "dy: %s", _dy.c_str()); +#endif + + if (httpd_query_key_value(_query, "enhance", _valuechar, 10) == ESP_OK) + { + string _enhance = string(_valuechar); + + if (_enhance.compare("true") == 0) + { + enhance = true; + } + } + + in = "/sdcard" + in; + out = "/sdcard" + out; + + string out2 = out.substr(0, out.length() - 4) + "_org.jpg"; + + if ((flowctrl.SetupModeActive || (*flowctrl.getActStatus() == std::string("Flow finished"))) && psram_init_shared_memory_for_take_image_step()) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Taking image for Alignment Mark Update..."); + + CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in); + caic->CutAndSave(out2, x, y, dx, dy); + delete caic; + + CImageBasis *cim = new CImageBasis("cutref", out2); + + if (enhance) + { + cim->Contrast(90); + } + + cim->SaveToFile(out); + delete cim; + + psram_deinit_shared_memory_for_take_image_step(); + zw = "CutImage Done"; + } + else + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Taking image for Alignment Mark not possible while device") + " is busy with a round (Current State: '" + *flowctrl.getActStatus() + "')!"); + zw = "Device Busy"; + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, zw.c_str(), zw.length()); + } + + // wird beim Erstellen eines neuen Referenzbildes aufgerufen + std::string *sys_status = flowctrl.getActStatus(); + + if ((sys_status->c_str() != std::string("Take Image")) && (sys_status->c_str() != std::string("Aligning"))) + { + if ((_task.compare("test_take") == 0) || (_task.compare("cam_settings") == 0)) + { + std::string _host = ""; + + // laden der aktuellen Kameraeinstellungen(CCstatus) in den Zwischenspeicher(CFstatus) + setCCstatusToCFstatus(); // CCstatus >>> CFstatus + + if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) + { + _host = std::string(_valuechar); + } + + if (httpd_query_key_value(_query, "waitb", _valuechar, 30) == ESP_OK) + { + int _waitb = std::stoi(_valuechar); + if (_waitb != 0) + { + CFstatus.WaitBeforePicture = _waitb; + } + } + + if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) + { + int _qual = std::stoi(_valuechar); + CFstatus.ImageQuality = clipInt(_qual, 63, 6); + } + + if (httpd_query_key_value(_query, "bri", _valuechar, 30) == ESP_OK) + { + int _bri = std::stoi(_valuechar); + CFstatus.ImageBrightness = clipInt(_bri, 2, -2); + } + + if (httpd_query_key_value(_query, "con", _valuechar, 30) == ESP_OK) + { + int _con = std::stoi(_valuechar); + CFstatus.ImageContrast = clipInt(_con, 2, -2); + } + + if (httpd_query_key_value(_query, "sat", _valuechar, 30) == ESP_OK) + { + int _sat = std::stoi(_valuechar); + CFstatus.ImageSaturation = clipInt(_sat, 2, -2); + } + + if (httpd_query_key_value(_query, "shp", _valuechar, 30) == ESP_OK) + { + int _shp = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageSharpness = clipInt(_shp, 2, -2); + } + else + { + CFstatus.ImageSharpness = clipInt(_shp, 3, -3); + } + } + + if (httpd_query_key_value(_query, "ashp", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAutoSharpness = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "spe", _valuechar, 30) == ESP_OK) + { + int _spe = std::stoi(_valuechar); + CFstatus.ImageSpecialEffect = clipInt(_spe, 6, 0); + } + + if (httpd_query_key_value(_query, "wbm", _valuechar, 30) == ESP_OK) + { + int _wbm = std::stoi(_valuechar); + CFstatus.ImageWbMode = clipInt(_wbm, 4, 0); + } + + if (httpd_query_key_value(_query, "awb", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAwb = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "awbg", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAwbGain = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "aec", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAec = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "aec2", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAec2 = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "ael", _valuechar, 30) == ESP_OK) + { + int _ael = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageAeLevel = clipInt(_ael, 2, -2); + } + else + { + CFstatus.ImageAeLevel = clipInt(_ael, 5, -5); + } + } + + if (httpd_query_key_value(_query, "aecv", _valuechar, 30) == ESP_OK) + { + int _aecv = std::stoi(_valuechar); + CFstatus.ImageAecValue = clipInt(_aecv, 1200, 0); + } + + if (httpd_query_key_value(_query, "agc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageAgc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "agcg", _valuechar, 30) == ESP_OK) + { + int _agcg = std::stoi(_valuechar); + CFstatus.ImageAgcGain = clipInt(_agcg, 30, 0); + } + + if (httpd_query_key_value(_query, "bpc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageBpc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "wpc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageWpc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "rgma", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageRawGma = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "lenc", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageLenc = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "mirror", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageHmirror = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "flip", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageVflip = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "dcw", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageDcw = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "den", _valuechar, 30) == ESP_OK) + { + int _ImageDenoiseLevel = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CCstatus.ImageDenoiseLevel = 0; + } + else + { + CFstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0); + } + } + + if (httpd_query_key_value(_query, "zoom", _valuechar, 30) == ESP_OK) + { + CFstatus.ImageZoomEnabled = numericStrToBool(_valuechar); + } + + if (httpd_query_key_value(_query, "zoomx", _valuechar, 30) == ESP_OK) + { + int _ImageZoomOffsetX = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CFstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960); + } + } + + if (httpd_query_key_value(_query, "zoomy", _valuechar, 30) == ESP_OK) + { + int _ImageZoomOffsetY = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CFstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720); + } + } + + if (httpd_query_key_value(_query, "zooms", _valuechar, 30) == ESP_OK) + { + int _ImageZoomSize = std::stoi(_valuechar); + if (CCstatus.CamSensor_id == OV2640_PID) + { + CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0); + } + else if (CCstatus.CamSensor_id == OV3660_PID) + { + CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0); + } + else if (CCstatus.CamSensor_id == OV5640_PID) + { + CFstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0); + } + } + + if (httpd_query_key_value(_query, "ledi", _valuechar, 30) == ESP_OK) + { + float _ImageLedIntensity = std::stof(_valuechar); + Camera.SetLEDIntensity(_ImageLedIntensity); + CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; + } + + if (_task.compare("cam_settings") == 0) + { + // wird aufgerufen, wenn das Referenzbild + Kameraeinstellungen gespeichert wurden + setCFstatusToCCstatus(); // CFstatus >>> CCstatus + + // Kameraeinstellungen wurden verädert + CFstatus.changedCameraSettings = true; + + ESP_LOGD(TAG, "Cam Settings set"); + std::string _zw = "CamSettingsSet"; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, _zw.c_str(), _zw.length()); + } + else + { + // wird aufgerufen, wenn ein neues Referenzbild erstellt oder aktualisiert wurde + // CFstatus >>> Kamera + setCFstatusToCam(); + + Camera.SetQualityZoomSize(CFstatus.ImageQuality, CFstatus.ImageFrameSize, CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); + // Camera.SetZoomSize(CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); + + // Kameraeinstellungen wurden verädert + CFstatus.changedCameraSettings = true; + + ESP_LOGD(TAG, "test_take - vor TakeImage"); + std::string image_temp = flowctrl.doSingleStep("[TakeImage]", _host); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, image_temp.c_str(), image_temp.length()); + } + } + + if (_task.compare("test_align") == 0) + { + std::string _host = ""; + + if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) + { + _host = std::string(_valuechar); + } + + std::string zw = flowctrl.doSingleStep("[Alignment]", _host); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, zw.c_str(), zw.length()); + } + } + else + { + std::string _zw = "DeviceIsBusy"; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, _zw.c_str(), _zw.length()); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_editflow - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_statusflow(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_statusflow - Start"); +#endif + + const char *resp_str; + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (bTaskAutoFlowCreated) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "handler_statusflow: %s", req->uri); +#endif + + string *zw = flowctrl.getActStatusWithTime(); + resp_str = zw->c_str(); + + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + else + { + resp_str = "Flow task not yet created"; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_statusflow - Done"); +#endif + + return ESP_OK; +} + +esp_err_t handler_cputemp(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_cputemp - Start"); +#endif + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, std::to_string((int)temperatureRead()).c_str(), HTTPD_RESP_USE_STRLEN); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_cputemp - End"); +#endif + + return ESP_OK; +} + +esp_err_t handler_rssi(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_rssi - Start"); +#endif + + if (getWIFIisConnected()) + { + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, std::to_string(get_WIFI_RSSI()).c_str(), HTTPD_RESP_USE_STRLEN); + } + else + { + httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "WIFI not (yet) connected: REST API /rssi not available!"); + return ESP_ERR_NOT_FOUND; + } + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_rssi - End"); +#endif + + return ESP_OK; +} + +esp_err_t handler_uptime(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_uptime - Start"); +#endif + + std::string formatedUptime = getFormatedUptime(false); + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_send(req, formatedUptime.c_str(), formatedUptime.length()); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_uptime - End"); +#endif + + return ESP_OK; +} + +esp_err_t handler_prevalue(httpd_req_t *req) +{ +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_prevalue - Start"); + ESP_LOGD(TAG, "handler_prevalue: %s", req->uri); +#endif + + // Default usage message when handler gets called without any parameter + const std::string RESTUsageInfo = + "00: Handler usage:
" + "- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main
" + "- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678
" + "NOTE:
" + "value >= 0.0: Set PreValue to provided value
" + "value < 0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)"; + + // Default return error message when no return is programmed + std::string sReturnMessage = "E90: Uninitialized"; + + char _query[100]; + char _numbersname[50] = "default"; + char _value[20] = ""; + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Query: %s", _query); +#endif + + if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) + { + // If request is incomplete + sReturnMessage = "E91: Query parameter incomplete or not valid!
" + "Call /setPreValue to show REST API usage info and/or check documentation"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + + if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Value: %s", _value); +#endif + } + } + else + { + // if no parameter is provided, print handler usage + httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length()); + return ESP_OK; + } + + if (strlen(_value) == 0) + { + // If no value is povided --> return actual PreValue + sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); + + if (sReturnMessage.empty()) + { + sReturnMessage = "E92: Numbers name not found"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + } + else + { + // New value is positive: Set PreValue to provided value and return value + // New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) + ", value: " + std::string(_value)); + + if (!flowctrl.UpdatePrevalue(_value, _numbersname, true)) + { + sReturnMessage = "E93: Update request rejected. Please check device logs for more details"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + + sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname)); + + if (sReturnMessage.empty()) + { + sReturnMessage = "E94: Numbers name not found"; + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + return ESP_FAIL; + } + } + + httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length()); + +#ifdef DEBUG_DETAIL_ON + LogFile.WriteHeapInfo("handler_prevalue - End"); +#endif + + return ESP_OK; +} + +void task_autodoFlow(void *pvParameter) +{ + int64_t fr_start, fr_delta_ms; + + bTaskAutoFlowCreated = true; + + if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC)) + { + flowctrl.setActStatus("Initialization (delayed)"); + // #ifdef ENABLE_MQTT + // MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later + // #endif //ENABLE_MQTT + vTaskDelay(60 * 5000 / portTICK_PERIOD_MS); // Wait 5 minutes to give time to do an OTA update or fetch the log + } + + ESP_LOGD(TAG, "task_autodoFlow: start"); + doInit(); + + flowctrl.setAutoStartInterval(auto_interval); + autostartIsEnabled = flowctrl.getIsAutoStart(); + + if (isSetupModusActive()) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "We are in Setup Mode -> Not starting Auto Flow!"); + autostartIsEnabled = false; + // 15.7.0 Setup Wizard cannot take a Reference Picture #2953 + // std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT); + // flowctrl.doFlowTakeImageOnly(zw_time); + } + + if (autostartIsEnabled) + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Starting Flow..."); + } + else + { + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Autostart is not enabled -> Not starting Flow"); + } + + while (autostartIsEnabled) + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs + time_t roundStartTime = getUpTime(); + + std::string _zw = "Round #" + std::to_string(++countRounds) + " started"; + LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw); + + fr_start = esp_timer_get_time(); + + if (flowisrunning) + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Autoflow: doFlow is already running!"); +#endif + } + else + { +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Autoflow: doFlow is started"); +#endif + flowisrunning = true; + doflow(); +#ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "Remove older log files"); +#endif + LogFile.RemoveOldLogFile(); + LogFile.RemoveOldDataLog(); + } + + // Round finished -> Logfile + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) + " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)"); + + // CPU Temp -> Logfile + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C"); + + // WIFI Signal Strength (RSSI) -> Logfile + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm"); + + // Check if time is synchronized (if NTP is configured) + if (getUseNtp() && !getTimeIsSet()) + { + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time server is configured, but time is not yet set!"); + StatusLED(TIME_CHECK, 1, false); + } + +#if (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES) + wifiRoamingQuery(); +#endif + +// Scan channels and check if an AP with better RSSI is available, then disconnect and try to reconnect to AP with better RSSI +// NOTE: Keep this direct before the following task delay, because scan is done in blocking mode and this takes ca. 1,5 - 2s. +#ifdef WLAN_USE_ROAMING_BY_SCANNING + wifiRoamByScanning(); +#endif + + fr_delta_ms = (esp_timer_get_time() - fr_start) / 1000; + + if (auto_interval > fr_delta_ms) + { + const TickType_t xDelay = (auto_interval - fr_delta_ms) / portTICK_PERIOD_MS; + ESP_LOGD(TAG, "Autoflow: sleep for: %ldms", (long)xDelay); + vTaskDelay(xDelay); + } + } + + while (1) + { + // Keep flow task running to handle necessary sub tasks like reboot handler, etc.. + vTaskDelay(2000 / portTICK_PERIOD_MS); + } + + vTaskDelete(NULL); // Delete this task if it exits from the loop above + xHandletask_autodoFlow = NULL; + + ESP_LOGD(TAG, "task_autodoFlow: end"); +} + +void InitializeFlowTask(void) +{ + BaseType_t xReturned; + + ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); + + uint32_t stackSize = 16 * 1024; + xReturned = xTaskCreatePinnedToCore(&task_autodoFlow, "task_autodoFlow", stackSize, NULL, tskIDLE_PRIORITY + 2, &xHandletask_autodoFlow, 0); + + if (xReturned != pdPASS) + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Creation task_autodoFlow failed. Requested stack size:" + std::to_string(stackSize)); + LogFile.WriteHeapInfo("Creation task_autodoFlow failed"); + } + + ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str()); +} + +void register_server_main_flow_task_uri(httpd_handle_t server) +{ + ESP_LOGI(TAG, "server_main_flow_task - Registering URI handlers"); + + httpd_uri_t camuri = {}; + camuri.method = HTTP_GET; + + camuri.uri = "/doinit"; + camuri.handler = handler_init; + camuri.user_ctx = (void *)"Light On"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/setPreValue" + camuri.uri = "/setPreValue.html"; + camuri.handler = handler_prevalue; + camuri.user_ctx = (void *)"Prevalue"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/setPreValue"; + camuri.handler = handler_prevalue; + camuri.user_ctx = (void *)"Prevalue"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/flow_start"; + camuri.handler = handler_flow_start; + camuri.user_ctx = (void *)"Flow Start"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/statusflow.html"; + camuri.handler = handler_statusflow; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/statusflow"; + camuri.handler = handler_statusflow; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/cpu_temperature" + camuri.uri = "/cputemp.html"; + camuri.handler = handler_cputemp; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/cpu_temperature"; + camuri.handler = handler_cputemp; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/rssi" + camuri.uri = "/rssi.html"; + camuri.handler = handler_rssi; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/rssi"; + camuri.handler = handler_rssi; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/uptime"; + camuri.handler = handler_uptime; + camuri.user_ctx = (void *)"Light Off"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/editflow"; + camuri.handler = handler_editflow; + camuri.user_ctx = (void *)"EditFlow"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/value" + camuri.uri = "/value.html"; + camuri.handler = handler_wasserzaehler; + camuri.user_ctx = (void *)"Value"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/value"; + camuri.handler = handler_wasserzaehler; + camuri.user_ctx = (void *)"Value"; + httpd_register_uri_handler(server, &camuri); + + // Legacy API => New: "/value" + camuri.uri = "/wasserzaehler.html"; + camuri.handler = handler_wasserzaehler; + camuri.user_ctx = (void *)"Wasserzaehler"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/json"; + camuri.handler = handler_json; + camuri.user_ctx = (void *)"JSON"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/heap"; + camuri.handler = handler_get_heap; + camuri.user_ctx = (void *)"Heap"; + httpd_register_uri_handler(server, &camuri); + + camuri.uri = "/stream"; + camuri.handler = handler_stream; + camuri.user_ctx = (void *)"stream"; + httpd_register_uri_handler(server, &camuri); +} diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.h b/code/components/jomjol_flowcontroll/MainFlowControl.h index 3596325f3..aaf81e101 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.h +++ b/code/components/jomjol_flowcontroll/MainFlowControl.h @@ -1,90 +1,90 @@ -#pragma once - -#ifndef MAINFLOWCONTROL_H -#define MAINFLOWCONTROL_H - -#include -#include - -#include -#include "CImageBasis.h" -#include "ClassFlowControll.h" - -typedef struct -{ - uint16_t CamSensor_id; - - framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 - gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - - int ImageQuality; // 0 - 63 - int ImageBrightness; // (-2 to 2) - set brightness - int ImageContrast; //-2 - 2 - int ImageSaturation; //-2 - 2 - int ImageSharpness; //-2 - 2 - bool ImageAutoSharpness; - int ImageSpecialEffect; // 0 - 6 - int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - int ImageAwb; // white balance enable (0 or 1) - int ImageAwbGain; // Auto White Balance enable (0 or 1) - int ImageAec; // auto exposure off (1 or 0) - int ImageAec2; // automatic exposure sensor (0 or 1) - int ImageAeLevel; // auto exposure levels (-2 to 2) - int ImageAecValue; // set exposure manually (0-1200) - int ImageAgc; // auto gain off (1 or 0) - int ImageAgcGain; // set gain manually (0 - 30) - int ImageBpc; // black pixel correction - int ImageWpc; // white pixel correction - int ImageRawGma; // (1 or 0) - int ImageLenc; // lens correction (1 or 0) - int ImageHmirror; // (0 or 1) flip horizontally - int ImageVflip; // Invert image (0 or 1) - int ImageDcw; // downsize enable (1 or 0) - - int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - int ImageWidth; - int ImageHeight; - - int ImageLedIntensity; - - bool ImageZoomEnabled; - int ImageZoomOffsetX; - int ImageZoomOffsetY; - int ImageZoomSize; - - int WaitBeforePicture; - bool isImageSize; - - bool CameraInitSuccessful; - bool changedCameraSettings; - bool DemoMode; - bool SaveAllFiles; -} camera_flow_config_temp_t; - -extern camera_flow_config_temp_t CFstatus; -extern ClassFlowControll flowctrl; - -esp_err_t setCCstatusToCFstatus(void); // CCstatus >>> CFstatus -esp_err_t setCFstatusToCCstatus(void); // CFstatus >>> CCstatus -esp_err_t setCFstatusToCam(void); // CFstatus >>> Kamera - -void register_server_main_flow_task_uri(httpd_handle_t server); - -void CheckIsPlannedReboot(void); -bool getIsPlannedReboot(void); - -void InitializeFlowTask(void); -void DeleteMainFlowTask(void); -bool isSetupModusActive(void); - -int getCountFlowRounds(void); - -#ifdef ENABLE_MQTT -esp_err_t MQTTCtrlFlowStart(std::string _topic); -#endif // ENABLE_MQTT - -esp_err_t GetRawJPG(httpd_req_t *req); -esp_err_t GetJPG(std::string _filename, httpd_req_t *req); - -#endif // MAINFLOWCONTROL_H +#pragma once + +#ifndef MAINFLOWCONTROL_H +#define MAINFLOWCONTROL_H + +#include +#include + +#include +#include "CImageBasis.h" +#include "ClassFlowControll.h" + +typedef struct +{ + uint16_t CamSensor_id; + + framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 + gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + + int ImageQuality; // 0 - 63 + int ImageBrightness; // (-2 to 2) - set brightness + int ImageContrast; //-2 - 2 + int ImageSaturation; //-2 - 2 + int ImageSharpness; //-2 - 2 + bool ImageAutoSharpness; + int ImageSpecialEffect; // 0 - 6 + int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + int ImageAwb; // white balance enable (0 or 1) + int ImageAwbGain; // Auto White Balance enable (0 or 1) + int ImageAec; // auto exposure off (1 or 0) + int ImageAec2; // automatic exposure sensor (0 or 1) + int ImageAeLevel; // auto exposure levels (-2 to 2) + int ImageAecValue; // set exposure manually (0-1200) + int ImageAgc; // auto gain off (1 or 0) + int ImageAgcGain; // set gain manually (0 - 30) + int ImageBpc; // black pixel correction + int ImageWpc; // white pixel correction + int ImageRawGma; // (1 or 0) + int ImageLenc; // lens correction (1 or 0) + int ImageHmirror; // (0 or 1) flip horizontally + int ImageVflip; // Invert image (0 or 1) + int ImageDcw; // downsize enable (1 or 0) + + int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + int ImageWidth; + int ImageHeight; + + int ImageLedIntensity; + + bool ImageZoomEnabled; + int ImageZoomOffsetX; + int ImageZoomOffsetY; + int ImageZoomSize; + + int WaitBeforePicture; + bool isImageSize; + + bool CameraInitSuccessful; + bool changedCameraSettings; + bool DemoMode; + bool SaveAllFiles; +} camera_flow_config_temp_t; + +extern camera_flow_config_temp_t CFstatus; +extern ClassFlowControll flowctrl; + +esp_err_t setCCstatusToCFstatus(void); // CCstatus >>> CFstatus +esp_err_t setCFstatusToCCstatus(void); // CFstatus >>> CCstatus +esp_err_t setCFstatusToCam(void); // CFstatus >>> Kamera + +void register_server_main_flow_task_uri(httpd_handle_t server); + +void CheckIsPlannedReboot(void); +bool getIsPlannedReboot(void); + +void InitializeFlowTask(void); +void DeleteMainFlowTask(void); +bool isSetupModusActive(void); + +int getCountFlowRounds(void); + +#ifdef ENABLE_MQTT +esp_err_t MQTTCtrlFlowStart(std::string _topic); +#endif // ENABLE_MQTT + +esp_err_t GetRawJPG(httpd_req_t *req); +esp_err_t GetJPG(std::string _filename, httpd_req_t *req); + +#endif // MAINFLOWCONTROL_H diff --git a/param-docs/expert-params.txt b/param-docs/expert-params.txt index 235a74d8c..056b71288 100644 --- a/param-docs/expert-params.txt +++ b/param-docs/expert-params.txt @@ -1,47 +1,47 @@ -WaitBeforeTakingPicture -CamFrameSize -CamGainceiling -CamQuality -CamAutoSharpness -CamSharpness -CamSpecialEffect -CamWbMode -CamAwb -CamAwbGain -CamAec -CamAec2 -CamAeLevel -CamAecValue -CamAgc -CamAgcGain -CamBpc -CamWpc -CamRawGma -CamLenc -CamDcw -CamDenoise -CamZoom -CamZoomSize -CamZoomOffsetX -CamZoomOffsetY -demo -SearchFieldX -SearchFieldY -AlignmentAlgo -CNNGoodThreshold -PreValueAgeStartup -ErrorMessage -CheckDigitIncreaseConsistency -IO0 -IO1 -IO3 -IO4 -IO12 -IO13 -AutoStart -Hostname -RSSIThreshold -TimeServer -CACert -ClientCert -ClientKey +WaitBeforeTakingPicture +CamFrameSize +CamGainceiling +CamQuality +CamAutoSharpness +CamSharpness +CamSpecialEffect +CamWbMode +CamAwb +CamAwbGain +CamAec +CamAec2 +CamAeLevel +CamAecValue +CamAgc +CamAgcGain +CamBpc +CamWpc +CamRawGma +CamLenc +CamDcw +CamDenoise +CamZoom +CamZoomSize +CamZoomOffsetX +CamZoomOffsetY +demo +SearchFieldX +SearchFieldY +AlignmentAlgo +CNNGoodThreshold +PreValueAgeStartup +ErrorMessage +CheckDigitIncreaseConsistency +IO0 +IO1 +IO3 +IO4 +IO12 +IO13 +AutoStart +Hostname +RSSIThreshold +TimeServer +CACert +ClientCert +ClientKey diff --git a/param-docs/parameter-pages/TakeImage/CamAeLevel.md b/param-docs/parameter-pages/TakeImage/CamAeLevel.md index e7d5fd079..332f687cb 100644 --- a/param-docs/parameter-pages/TakeImage/CamAeLevel.md +++ b/param-docs/parameter-pages/TakeImage/CamAeLevel.md @@ -1,16 +1,16 @@ -# Parameter `CamAeLevel` -Default Value: `0` - -!!! Warning - This is an **Expert Parameter**! Only change it if you understand what it does! - -!!! Note - This parameter can also be set on the Reference Image configuration page! - -!!! Note - After changing this parameter you need to update your reference image and alignment markers! - -Auto-Exposure Compensation. Lower values produce darker image. - -available range on OV2640 (`-2` .. `2`) -available range on OV3660 and OV5640 (`-5` .. `5`) +# Parameter `CamAeLevel` +Default Value: `0` + +!!! Warning + This is an **Expert Parameter**! Only change it if you understand what it does! + +!!! Note + This parameter can also be set on the Reference Image configuration page! + +!!! Note + After changing this parameter you need to update your reference image and alignment markers! + +Auto-Exposure Compensation. Lower values produce darker image. + +available range on OV2640 (`-2` .. `2`) +available range on OV3660 and OV5640 (`-5` .. `5`) diff --git a/param-docs/parameter-pages/TakeImage/CamDenoise.md b/param-docs/parameter-pages/TakeImage/CamDenoise.md index 917af00c7..f51b8ec4a 100644 --- a/param-docs/parameter-pages/TakeImage/CamDenoise.md +++ b/param-docs/parameter-pages/TakeImage/CamDenoise.md @@ -1,12 +1,12 @@ -# Parameter `CamDenoise` -Default Value: `0` - -!!! Warning - This is an **Expert Parameter**! Only change it if you understand what it does! - -!!! Note - After changing this parameter you need to update your reference image and alignment markers! - -Denoise Image, is only supported by OV3660 and OV5640 - -Range (`0` .. `8`) +# Parameter `CamDenoise` +Default Value: `0` + +!!! Warning + This is an **Expert Parameter**! Only change it if you understand what it does! + +!!! Note + After changing this parameter you need to update your reference image and alignment markers! + +Denoise Image, is only supported by OV3660 and OV5640 + +Range (`0` .. `8`) diff --git a/sd-card/html/edit_config_template.html b/sd-card/html/edit_config_template.html index 314fc88c9..c67d545e5 100644 --- a/sd-card/html/edit_config_template.html +++ b/sd-card/html/edit_config_template.html @@ -1,3173 +1,3173 @@ - - - -Configuration - - - - - - - - - - - - - - - - - - -
-
-
- -

Configuration

- -
- CLICK HERE for usage description. More infos in documentation: - Parameter - -

- This page lists all available configuration parameters of the device.
- The description of each parameter can be shown by hovering over or by clicking the icon. -

-

- The page gets opened with the default view which should be sufficient for regular configuration tasks. Enabling the "Show Expert Parameters" - some expert parameters (light red background color) will be added to the parameter list. Additionally the button "Edit "Config.ini" File" - to edit the underlaying configuration file (config.ini) manually is now shown on top of the page. This function should be only used for special cases. -

-

- Sections (entire functionality) or single parameters having a checkbox can be enabled or disabled. - Disabling a complete section results in a disabled functionality. Whenever only a single parameter of a section is disabled - the hard-coded default value is used for the disabled parameter. -

-

- Don't forget to save the changes with the button "Save Config" at the bottom of this page.
- -

-
-
- - - - - - - - - - + + + +Configuration + + + + + + + + + + + + + + + + + + +
+
+
+ +

Configuration

+ +
+ CLICK HERE for usage description. More infos in documentation: + Parameter + +

+ This page lists all available configuration parameters of the device.
+ The description of each parameter can be shown by hovering over or by clicking the icon. +

+

+ The page gets opened with the default view which should be sufficient for regular configuration tasks. Enabling the "Show Expert Parameters" + some expert parameters (light red background color) will be added to the parameter list. Additionally the button "Edit "Config.ini" File" + to edit the underlaying configuration file (config.ini) manually is now shown on top of the page. This function should be only used for special cases. +

+

+ Sections (entire functionality) or single parameters having a checkbox can be enabled or disabled. + Disabling a complete section results in a disabled functionality. Whenever only a single parameter of a section is disabled + the hard-coded default value is used for the disabled parameter. +

+

+ Don't forget to save the changes with the button "Save Config" at the bottom of this page.
+ +

+
+
+ + + + + + + + + + diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index 2317ae946..0577642c7 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -1,1146 +1,1146 @@ -var config_gesamt = ""; -var config_split = []; -var param = []; -var category; -var ref = new Array(2); -var NUMBERS = new Array(0); -var REFERENCES = new Array(0); - - -function getNUMBERSList() { - _domainname = getDomainname(); - var namenumberslist = ""; - - var xhttp = new XMLHttpRequest(); - - xhttp.addEventListener('load', function(event) { - if (xhttp.status >= 200 && xhttp.status < 300) { - namenumberslist = xhttp.responseText; - } - else { - console.warn(request.statusText, request.responseText); - } - }); - - try { - url = _domainname + '/editflow?task=namenumbers'; - xhttp.open("GET", url, false); - xhttp.send(); - } catch (error) {} - - namenumberslist = namenumberslist.split("\t"); - - return namenumberslist; -} - - -function getDATAList() { - _domainname = getDomainname(); - datalist = ""; - - var xhttp = new XMLHttpRequest(); - - xhttp.addEventListener('load', function(event) { - if (xhttp.status >= 200 && xhttp.status < 300) { - datalist = xhttp.responseText; - } - else { - console.warn(request.statusText, request.responseText); - } - }); - - try { - url = _domainname + '/editflow?task=data'; - xhttp.open("GET", url, false); - xhttp.send(); - } catch (error) {} - - datalist = datalist.split("\t"); - datalist.pop(); - datalist.sort(); - - return datalist; -} - - -function getTFLITEList() { - _domainname = getDomainname(); - tflitelist = ""; - - var xhttp = new XMLHttpRequest(); - - xhttp.addEventListener('load', function(event) { - if (xhttp.status >= 200 && xhttp.status < 300) { - tflitelist = xhttp.responseText; - } - else { - console.warn(request.statusText, request.responseText); - } - }); - - try { - url = _domainname + '/editflow?task=tflite'; - xhttp.open("GET", url, false); - xhttp.send(); - } catch (error) {} - - tflitelist = tflitelist.split("\t"); - tflitelist.sort(); - - return tflitelist; -} - - -function ParseConfig() { - config_split = config_gesamt.split("\n"); - var aktline = 0; - - param = new Object(); - category = new Object(); - - var catname = "TakeImage"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "RawImagesLocation"); - ParamAddValue(param, catname, "RawImagesRetention"); - ParamAddValue(param, catname, "WaitBeforeTakingPicture"); - ParamAddValue(param, catname, "CamGainceiling"); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - ParamAddValue(param, catname, "CamQuality"); // 0 - 63 - ParamAddValue(param, catname, "CamBrightness"); // (-2 to 2) - set brightness - ParamAddValue(param, catname, "CamContrast"); //-2 - 2 - ParamAddValue(param, catname, "CamSaturation"); //-2 - 2 - ParamAddValue(param, catname, "CamSharpness"); //-2 - 2 - ParamAddValue(param, catname, "CamAutoSharpness"); // (1 or 0) - ParamAddValue(param, catname, "CamSpecialEffect"); // 0 - 6 - ParamAddValue(param, catname, "CamWbMode"); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - ParamAddValue(param, catname, "CamAwb"); // white balance enable (0 or 1) - ParamAddValue(param, catname, "CamAwbGain"); // Auto White Balance enable (0 or 1) - ParamAddValue(param, catname, "CamAec"); // auto exposure off (1 or 0) - ParamAddValue(param, catname, "CamAec2"); // automatic exposure sensor (0 or 1) - ParamAddValue(param, catname, "CamAeLevel"); // auto exposure levels (-2 to 2) - ParamAddValue(param, catname, "CamAecValue"); // set exposure manually (0-1200) - ParamAddValue(param, catname, "CamAgc"); // auto gain off (1 or 0) - ParamAddValue(param, catname, "CamAgcGain"); // set gain manually (0 - 30) - ParamAddValue(param, catname, "CamBpc"); // black pixel correction - ParamAddValue(param, catname, "CamWpc"); // white pixel correction - ParamAddValue(param, catname, "CamRawGma"); // (1 or 0) - ParamAddValue(param, catname, "CamLenc"); // lens correction (1 or 0) - ParamAddValue(param, catname, "CamHmirror"); // (0 or 1) flip horizontally - ParamAddValue(param, catname, "CamVflip"); // Invert image (0 or 1) - ParamAddValue(param, catname, "CamDcw"); // downsize enable (1 or 0) - ParamAddValue(param, catname, "CamDenoise"); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - ParamAddValue(param, catname, "CamZoom"); - ParamAddValue(param, catname, "CamZoomOffsetX"); - ParamAddValue(param, catname, "CamZoomOffsetY"); - ParamAddValue(param, catname, "CamZoomSize"); - ParamAddValue(param, catname, "LEDIntensity"); - ParamAddValue(param, catname, "Demo"); - - var catname = "Alignment"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "InitialRotate"); - ParamAddValue(param, catname, "SearchFieldX"); - ParamAddValue(param, catname, "SearchFieldY"); - ParamAddValue(param, catname, "AlignmentAlgo"); - - var catname = "Digits"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Model"); - ParamAddValue(param, catname, "CNNGoodThreshold", 1); - ParamAddValue(param, catname, "ROIImagesLocation"); - ParamAddValue(param, catname, "ROIImagesRetention"); - - var catname = "Analog"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Model"); - ParamAddValue(param, catname, "ROIImagesLocation"); - ParamAddValue(param, catname, "ROIImagesRetention"); - - var catname = "PostProcessing"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "DecimalShift", 1, true); - ParamAddValue(param, catname, "AnalogDigitalTransitionStart", 1, true); - // ParamAddValue(param, catname, "PreValueUse", 1, true, "true"); - ParamAddValue(param, catname, "PreValueUse"); - ParamAddValue(param, catname, "PreValueAgeStartup"); - ParamAddValue(param, catname, "AllowNegativeRates", 1, true, "false"); - ParamAddValue(param, catname, "MaxRateValue", 1, true); - ParamAddValue(param, catname, "MaxRateType", 1, true); - ParamAddValue(param, catname, "ExtendedResolution", 1, true, "false"); - ParamAddValue(param, catname, "IgnoreLeadingNaN", 1, true, "false"); - // ParamAddValue(param, catname, "IgnoreAllNaN", 1, true, "false"); - ParamAddValue(param, catname, "ErrorMessage"); - ParamAddValue(param, catname, "CheckDigitIncreaseConsistency"); - - var catname = "MQTT"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "MainTopic", 1, false); - ParamAddValue(param, catname, "ClientID"); - ParamAddValue(param, catname, "user"); - ParamAddValue(param, catname, "password"); - ParamAddValue(param, catname, "RetainMessages"); - ParamAddValue(param, catname, "HomeassistantDiscovery"); - ParamAddValue(param, catname, "MeterType"); - ParamAddValue(param, catname, "CACert"); - ParamAddValue(param, catname, "ClientCert"); - ParamAddValue(param, catname, "ClientKey"); - - var catname = "InfluxDB"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "Database"); -// ParamAddValue(param, catname, "Measurement"); - ParamAddValue(param, catname, "user"); - ParamAddValue(param, catname, "password"); - ParamAddValue(param, catname, "Measurement", 1, true); - ParamAddValue(param, catname, "Field", 1, true); - - var catname = "InfluxDBv2"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Uri"); - ParamAddValue(param, catname, "Bucket"); -// ParamAddValue(param, catname, "Measurement"); - ParamAddValue(param, catname, "Org"); - ParamAddValue(param, catname, "Token"); - ParamAddValue(param, catname, "Measurement", 1, true); - ParamAddValue(param, catname, "Field", 1, true); - - var catname = "GPIO"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "IO0", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO1", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO3", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO4", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO12", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "IO13", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); - ParamAddValue(param, catname, "LEDType"); - ParamAddValue(param, catname, "LEDNumbers"); - ParamAddValue(param, catname, "LEDColor", 3); - // Default Values, um abwärtskompatiblität zu gewährleisten - param[catname]["LEDType"]["value1"] = "WS2812"; - param[catname]["LEDNumbers"]["value1"] = "2"; - param[catname]["LEDColor"]["value1"] = "50"; - param[catname]["LEDColor"]["value2"] = "50"; - param[catname]["LEDColor"]["value3"] = "50"; - - var catname = "AutoTimer"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "AutoStart"); - ParamAddValue(param, catname, "Interval"); - - var catname = "DataLogging"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "DataLogActive"); - ParamAddValue(param, catname, "DataFilesRetention"); - - var catname = "Debug"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "LogLevel"); - ParamAddValue(param, catname, "LogfilesRetention"); - - var catname = "System"; - category[catname] = new Object(); - category[catname]["enabled"] = false; - category[catname]["found"] = false; - param[catname] = new Object(); - ParamAddValue(param, catname, "Tooltip"); - ParamAddValue(param, catname, "TimeZone"); - ParamAddValue(param, catname, "TimeServer"); - ParamAddValue(param, catname, "Hostname"); - ParamAddValue(param, catname, "RSSIThreshold"); - ParamAddValue(param, catname, "CPUFrequency"); - ParamAddValue(param, catname, "SetupMode"); - - while (aktline < config_split.length){ - for (var cat in category) { - zw = cat.toUpperCase(); - zw1 = "[" + zw + "]"; - zw2 = ";[" + zw + "]"; - - if ((config_split[aktline].trim().toUpperCase() == zw1) || (config_split[aktline].trim().toUpperCase() == zw2)) { - if (config_split[aktline].trim().toUpperCase() == zw1) { - category[cat]["enabled"] = true; - } - - category[cat]["found"] = true; - category[cat]["line"] = aktline; - aktline = ParseConfigParamAll(aktline, cat); - continue; - } - } - - aktline++; - } - - // Make the downward compatiblity with DataLogging - if (category["DataLogging"]["found"] == false) { - category["DataLogging"]["found"] = true; - category["DataLogging"]["enabled"] = true; - - param["DataLogging"]["DataLogActive"]["found"] = true; - param["DataLogging"]["DataLogActive"]["enabled"] = true; - param["DataLogging"]["DataLogActive"]["value1"] = "true"; - - param["DataLogging"]["DataFilesRetention"]["found"] = true; - param["DataLogging"]["DataFilesRetention"]["enabled"] = true; - param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; - } - - if (category["DataLogging"]["enabled"] == false) { - category["DataLogging"]["enabled"] = true - } - - if (param["DataLogging"]["DataLogActive"]["enabled"] == false && param["DataLogging"]["DataLogActive"]["value1"] == "") { - param["DataLogging"]["DataLogActive"]["found"] = true; - param["DataLogging"]["DataLogActive"]["enabled"] = true; - param["DataLogging"]["DataLogActive"]["value1"] = "true"; - } - - if (param["DataLogging"]["DataFilesRetention"]["enabled"] == false && param["DataLogging"]["DataFilesRetention"]["value1"] == "") { - param["DataLogging"]["DataFilesRetention"]["found"] = true; - param["DataLogging"]["DataFilesRetention"]["enabled"] = true; - param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; - } - - // Downward compatibility: Create RSSIThreshold if not available - if (param["System"]["RSSIThreshold"]["found"] == false) { - param["System"]["RSSIThreshold"]["found"] = true; - param["System"]["RSSIThreshold"]["enabled"] = false; - param["System"]["RSSIThreshold"]["value1"] = "0"; - } -} - - -function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _defaultValue = "", _checkRegExList = null) { - param[_cat][_param] = new Object(); - param[_cat][_param]["found"] = false; - param[_cat][_param]["enabled"] = false; - param[_cat][_param]["line"] = -1; - param[_cat][_param]["anzParam"] = _anzParam; - param[_cat][_param]["defaultValue"] = _defaultValue; - param[_cat][_param]["Numbers"] = _isNUMBER; - param[_cat][_param].checkRegExList = _checkRegExList; -}; - - -function ParseConfigParamAll(_aktline, _catname) { - ++_aktline; - - while ((_aktline < config_split.length) && !(config_split[_aktline][0] == "[") && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { - var _input = config_split[_aktline]; - let [isCom, input] = isCommented(_input); - var linesplit = ZerlegeZeile(input); - ParamExtractValueAll(param, linesplit, _catname, _aktline, isCom); - - if (!isCom && (linesplit.length >= 5) && (_catname == 'Digits')) { - ExtractROIs(input, "digit"); - } - - if (!isCom && (linesplit.length >= 5) && (_catname == 'Analog')) { - ExtractROIs(input, "analog"); - } - - if (!isCom && (linesplit.length == 3) && (_catname == 'Alignment')) { - _newref = new Object(); - _newref["name"] = linesplit[0]; - _newref["x"] = linesplit[1]; - _newref["y"] = linesplit[2]; - REFERENCES.push(_newref); - } - - ++_aktline; - } - - return _aktline; -} - - -function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _iscom, _anzvalue = 1) { - if ((_linesplit[0].toUpperCase() == _paramname.toUpperCase()) && (_linesplit.length > _anzvalue)) { - _param[_catname][_paramname]["found"] = true; - _param[_catname][_paramname]["enabled"] = !_iscom; - _param[_catname][_paramname]["line"] = _aktline; - _param[_catname][_paramname]["anzpara"] = _anzvalue; - - for (var j = 1; j <= _anzvalue; ++j) { - _param[_catname][_paramname]["value"+j] = _linesplit[j]; - } - } -} - - -function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom) { - for (var paramname in _param[_catname]) { - _AktROI = "default"; - _AktPara = _linesplit[0]; - _pospunkt = _AktPara.indexOf ("."); - - if (_pospunkt > -1) { - _AktROI = _AktPara.substring(0, _pospunkt); - _AktPara = _AktPara.substring(_pospunkt+1); - } - - if (_AktPara.toUpperCase() == paramname.toUpperCase()) { - while (_linesplit.length <= _param[_catname][paramname]["anzParam"]) { - _linesplit.push(""); - } - - _param[_catname][paramname]["found"] = true; - _param[_catname][paramname]["enabled"] = !_iscom; - _param[_catname][paramname]["line"] = _aktline; - - if (_param[_catname][paramname]["Numbers"] == true) { // möglicher Multiusage - abc = getNUMBERS(_linesplit[0]); - abc[_catname][paramname] = new Object; - abc[_catname][paramname]["found"] = true; - abc[_catname][paramname]["enabled"] = !_iscom; - - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - abc[_catname][paramname]["value"+j] = _linesplit[j]; - } - - if (abc["name"] == "default") { - for (_num in NUMBERS) { // wert mit Default belegen - if (NUMBERS[_num][_catname][paramname]["found"] == false) { - NUMBERS[_num][_catname][paramname]["found"] = true; - NUMBERS[_num][_catname][paramname]["enabled"] = !_iscom; - NUMBERS[_num][_catname][paramname]["line"] = _aktline; - - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - NUMBERS[_num][_catname][paramname]["value"+j] = _linesplit[j]; - } - } - } - } - } - else { - _param[_catname][paramname]["found"] = true; - _param[_catname][paramname]["enabled"] = !_iscom; - _param[_catname][paramname]["line"] = _aktline; - - for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { - _param[_catname][paramname]["value"+j] = _linesplit[j]; - } - } - } - } -} - - -function getCamConfig() { - ParseConfig(); - - param["System"]["Tooltip"]["enabled"] = true; - param["Alignment"]["InitialRotate"]["enabled"] = true; - - param["TakeImage"]["WaitBeforeTakingPicture"]["enabled"] = true; - param["TakeImage"]["CamGainceiling"]["enabled"] = true; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - param["TakeImage"]["CamQuality"]["enabled"] = true; // 0 - 63 - param["TakeImage"]["CamBrightness"]["enabled"] = true; // (-2 to 2) - set brightness - param["TakeImage"]["CamContrast"]["enabled"] = true; //-2 - 2 - param["TakeImage"]["CamSaturation"]["enabled"] = true; //-2 - 2 - param["TakeImage"]["CamSharpness"]["enabled"] = true; //-2 - 2 - param["TakeImage"]["CamAutoSharpness"]["enabled"] = true; //(1 or 0) - param["TakeImage"]["CamSpecialEffect"]["enabled"] = true; // 0 - 6 - param["TakeImage"]["CamWbMode"]["enabled"] = true; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - param["TakeImage"]["CamAwb"]["enabled"] = true; // white balance enable (0 or 1) - param["TakeImage"]["CamAwbGain"]["enabled"] = true; // Auto White Balance enable (0 or 1) - param["TakeImage"]["CamAec"]["enabled"] = true; // auto exposure off (1 or 0) - param["TakeImage"]["CamAec2"]["enabled"] = true; // automatic exposure sensor (0 or 1) - param["TakeImage"]["CamAeLevel"]["enabled"] = true; // auto exposure levels (-2 to 2) - param["TakeImage"]["CamAecValue"]["enabled"] = true; // set exposure manually (0-1200) - param["TakeImage"]["CamAgc"]["enabled"] = true; // auto gain off (1 or 0) - param["TakeImage"]["CamAgcGain"]["enabled"] = true; // set gain manually (0 - 30) - param["TakeImage"]["CamBpc"]["enabled"] = true; // black pixel correction - param["TakeImage"]["CamWpc"]["enabled"] = true; // white pixel correction - param["TakeImage"]["CamRawGma"]["enabled"] = true; // (1 or 0) - param["TakeImage"]["CamLenc"]["enabled"] = true; // lens correction (1 or 0) - param["TakeImage"]["CamHmirror"]["enabled"] = true; // (0 or 1) flip horizontally - param["TakeImage"]["CamVflip"]["enabled"] = true; // Invert image (0 or 1) - param["TakeImage"]["CamDcw"]["enabled"] = true; // downsize enable (1 or 0) - param["TakeImage"]["CamDenoise"]["enabled"] = true; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - param["TakeImage"]["CamZoom"]["enabled"] = true; - param["TakeImage"]["CamZoomOffsetX"]["enabled"] = true; - param["TakeImage"]["CamZoomOffsetY"]["enabled"] = true; - param["TakeImage"]["CamZoomSize"]["enabled"] = true; - param["TakeImage"]["LEDIntensity"]["enabled"] = true; - - if (!param["System"]["Tooltip"]["found"]) { - param["System"]["Tooltip"]["found"] = true; - param["System"]["Tooltip"].value1 = 'true'; - } - - if (!param["Alignment"]["InitialRotate"]["found"]) { - param["Alignment"]["InitialRotate"]["found"] = true; - param["Alignment"]["InitialRotate"].value1 = 'false'; - } - - if (!param["TakeImage"]["WaitBeforeTakingPicture"]["found"]) { - param["TakeImage"]["WaitBeforeTakingPicture"]["found"] = true; - param["TakeImage"]["WaitBeforeTakingPicture"].value1 = '5'; - } - if (!param["TakeImage"]["CamGainceiling"]["found"]) { - param["TakeImage"]["CamGainceiling"]["found"] = true; - param["TakeImage"]["CamGainceiling"].value1 = '1'; - } - if (!param["TakeImage"]["CamQuality"]["found"]) { - param["TakeImage"]["CamQuality"]["found"] = true; - param["TakeImage"]["CamQuality"].value1 = '10'; - } - if (!param["TakeImage"]["CamBrightness"]["found"]) { - param["TakeImage"]["CamBrightness"]["found"] = true; - param["TakeImage"]["CamBrightness"].value1 = '0'; - } - if (!param["TakeImage"]["CamContrast"]["found"]) { - param["TakeImage"]["CamContrast"]["found"] = true; - param["TakeImage"]["CamContrast"].value1 = '0'; - } - if (!param["TakeImage"]["CamSaturation"]["found"]) { - param["TakeImage"]["CamSaturation"]["found"] = true; - param["TakeImage"]["CamSaturation"].value1 = '0'; - } - if (!param["TakeImage"]["CamSharpness"]["found"]) { - param["TakeImage"]["CamSharpness"]["found"] = true; - param["TakeImage"]["CamSharpness"].value1 = '0'; - } - if (!param["TakeImage"]["CamAutoSharpness"]["found"]) { - param["TakeImage"]["CamAutoSharpness"]["found"] = true; - param["TakeImage"]["CamAutoSharpness"].value1 = 'false'; - } - if (!param["TakeImage"]["CamSpecialEffect"]["found"]) { - param["TakeImage"]["CamSpecialEffect"]["found"] = true; - param["TakeImage"]["CamSpecialEffect"].value1 = 'no_effect'; - } - if (!param["TakeImage"]["CamWbMode"]["found"]) { - param["TakeImage"]["CamWbMode"]["found"] = true; - param["TakeImage"]["CamWbMode"].value1 = 'auto'; - } - if (!param["TakeImage"]["CamAwb"]["found"]) { - param["TakeImage"]["CamAwb"]["found"] = true; - param["TakeImage"]["CamAwb"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAwbGain"]["found"]) { - param["TakeImage"]["CamAwbGain"]["found"] = true; - param["TakeImage"]["CamAwbGain"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAec"]["found"]) { - param["TakeImage"]["CamAec"]["found"] = true; - param["TakeImage"]["CamAec"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAec2"]["found"]) { - param["TakeImage"]["CamAec2"]["found"] = true; - param["TakeImage"]["CamAec2"].value1 = 'false'; - } - if (!param["TakeImage"]["CamAeLevel"]["found"]) { - param["TakeImage"]["CamAeLevel"]["found"] = true; - param["TakeImage"]["CamAeLevel"].value1 = '0'; - } - if (!param["TakeImage"]["CamAecValue"]["found"]) { - param["TakeImage"]["CamAecValue"]["found"] = true; - param["TakeImage"]["CamAecValue"].value1 = '168'; - } - if (!param["TakeImage"]["CamAgc"]["found"]) { - param["TakeImage"]["CamAgc"]["found"] = true; - param["TakeImage"]["CamAgc"].value1 = 'true'; - } - if (!param["TakeImage"]["CamAgcGain"]["found"]) { - param["TakeImage"]["CamAgcGain"]["found"] = true; - param["TakeImage"]["CamAgcGain"].value1 = '0'; - } - if (!param["TakeImage"]["CamBpc"]["found"]) { - param["TakeImage"]["CamBpc"]["found"] = true; - param["TakeImage"]["CamBpc"].value1 = 'false'; - } - if (!param["TakeImage"]["CamWpc"]["found"]) { - param["TakeImage"]["CamWpc"]["found"] = true; - param["TakeImage"]["CamWpc"].value1 = 'true'; - } - if (!param["TakeImage"]["CamRawGma"]["found"]) { - param["TakeImage"]["CamRawGma"]["found"] = true; - param["TakeImage"]["CamRawGma"].value1 = 'true'; - } - if (!param["TakeImage"]["CamLenc"]["found"]) { - param["TakeImage"]["CamLenc"]["found"] = true; - param["TakeImage"]["CamLenc"].value1 = 'true'; - } - if (!param["TakeImage"]["CamHmirror"]["found"]) { - param["TakeImage"]["CamHmirror"]["found"] = true; - param["TakeImage"]["CamHmirror"].value1 = 'false'; - } - if (!param["TakeImage"]["CamVflip"]["found"]) { - param["TakeImage"]["CamVflip"]["found"] = true; - param["TakeImage"]["CamVflip"].value1 = 'false'; - } - if (!param["TakeImage"]["CamDcw"]["found"]) { - param["TakeImage"]["CamDcw"]["found"] = true; - param["TakeImage"]["CamDcw"].value1 = 'true'; - } - if (!param["TakeImage"]["CamDenoise"]["found"]) { - param["TakeImage"]["CamDenoise"]["found"] = true; - param["TakeImage"]["CamDenoise"].value1 = '0'; - } - if (!param["TakeImage"]["CamZoom"]["found"]) { - param["TakeImage"]["CamZoom"]["found"] = true; - param["TakeImage"]["CamZoom"].value1 = 'false'; - } - if (!param["TakeImage"]["CamZoomOffsetX"]["found"]) { - param["TakeImage"]["CamZoomOffsetX"]["found"] = true; - param["TakeImage"]["CamZoomOffsetX"].value1 = '0'; - } - if (!param["TakeImage"]["CamZoomOffsetY"]["found"]) { - param["TakeImage"]["CamZoomOffsetY"]["found"] = true; - param["TakeImage"]["CamZoomOffsetY"].value1 = '0'; - } - if (!param["TakeImage"]["CamZoomSize"]["found"]) { - param["TakeImage"]["CamZoomSize"]["found"] = true; - param["TakeImage"]["CamZoomSize"].value1 = '0'; - } - if (!param["TakeImage"]["LEDIntensity"]["found"]) { - param["TakeImage"]["LEDIntensity"]["found"] = true; - param["TakeImage"]["LEDIntensity"].value1 = '50'; - } - - return param; -} - - -function getConfigParameters() { - return param; -} - - -function WriteConfigININew() { - // Cleanup empty NUMBERS - for (var j = 0; j < NUMBERS.length; ++j) { - if ((NUMBERS[j]["digit"].length + NUMBERS[j]["analog"].length) == 0) { - NUMBERS.splice(j, 1); - } - } - - config_split = new Array(0); - - for (var cat in param) { - text = "[" + cat + "]"; - - if (!category[cat]["enabled"]) { - text = ";" + text; - } - - config_split.push(text); - - for (var name in param[cat]) { - if (param[cat][name]["Numbers"]) { - for (_num in NUMBERS) { - text = NUMBERS[_num]["name"] + "." + name; - - var text = text + " =" - - for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { - if (!(typeof NUMBERS[_num][cat][name]["value"+j] == 'undefined')) { - text = text + " " + NUMBERS[_num][cat][name]["value"+j]; - } - } - - if (!NUMBERS[_num][cat][name]["enabled"]) { - text = ";" + text; - } - - config_split.push(text); - } - } - else { - var text = name + " =" - - for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { - if (!(typeof param[cat][name]["value"+j] == 'undefined')) { - text = text + " " + param[cat][name]["value"+j]; - } - } - - if (!param[cat][name]["enabled"]) { - text = ";" + text; - } - - config_split.push(text); - } - } - - if (cat == "Digits") { - for (var _roi in NUMBERS) { - if (NUMBERS[_roi]["digit"].length > 0) { - for (var _roiddet in NUMBERS[_roi]["digit"]) { - text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["digit"][_roiddet]["name"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["x"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["y"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dx"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dy"]; - text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["CCW"]; - config_split.push(text); - } - } - } - } - - if (cat == "Analog") { - for (var _roi in NUMBERS) { - if (NUMBERS[_roi]["analog"].length > 0) { - for (var _roiddet in NUMBERS[_roi]["analog"]) { - text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["analog"][_roiddet]["name"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["x"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["y"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dx"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dy"]; - text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["CCW"]; - config_split.push(text); - } - } - } - } - - if (cat == "Alignment") { - for (var _roi in REFERENCES) { - text = REFERENCES[_roi]["name"]; - text = text + " " + REFERENCES[_roi]["x"]; - text = text + " " + REFERENCES[_roi]["y"]; - config_split.push(text); - } - } - - config_split.push(""); - } -} - - -function isCommented(input) { - let isComment = false; - - if (input.charAt(0) == ';') { - isComment = true; - input = input.substr(1, input.length-1); - } - - return [isComment, input]; -} - - -function SaveConfigToServer(_domainname){ - // leere Zeilen am Ende löschen - var zw = config_split.length - 1; - - while (config_split[zw] == "") { - config_split.pop(); - } - - var config_gesamt = ""; - - for (var i = 0; i < config_split.length; ++i) - { - config_gesamt = config_gesamt + config_split[i] + "\n"; - } - - FileDeleteOnServer("/config/config.ini", _domainname); - FileSendContent(config_gesamt, "/config/config.ini", _domainname); -} - - -function getConfig() { - return config_gesamt; -} - - -function getConfigCategory() { - return category; -} - - -function ExtractROIs(_aktline, _type){ - var linesplit = ZerlegeZeile(_aktline); - abc = getNUMBERS(linesplit[0], _type); - abc["pos_ref"] = _aktline; - abc["x"] = linesplit[1]; - abc["y"] = linesplit[2]; - abc["dx"] = linesplit[3]; - abc["dy"] = linesplit[4]; - abc["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); - abc["CCW"] = "false"; - - if (linesplit.length >= 6) { - abc["CCW"] = linesplit[5]; - } -} - - -function getNUMBERS(_name, _type, _create = true) { - _pospunkt = _name.indexOf ("."); - - if (_pospunkt > -1) { - _digit = _name.substring(0, _pospunkt); - _roi = _name.substring(_pospunkt+1); - } - else { - _digit = "default"; - _roi = _name; - } - - _ret = -1; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _digit) { - _ret = NUMBERS[i]; - } - } - - if (!_create) { // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück - return _ret; - } - - if (_ret == -1) { - _ret = new Object(); - _ret["name"] = _digit; - _ret['digit'] = new Array(); - _ret['analog'] = new Array(); - - for (_cat in param) { - for (_param in param[_cat]) { - if (param[_cat][_param]["Numbers"] == true){ - if (typeof _ret[_cat] == 'undefined') { - _ret[_cat] = new Object(); - } - - _ret[_cat][_param] = new Object(); - _ret[_cat][_param]["found"] = false; - _ret[_cat][_param]["enabled"] = false; - _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; - } - } - } - - NUMBERS.push(_ret); - } - - if (typeof _type == 'undefined') { // muss schon existieren !!! - also erst nach Digits / Analog aufrufen - return _ret; - } - - neuroi = new Object(); - neuroi["name"] = _roi; - _ret[_type].push(neuroi); - - return neuroi; -} - - -function CopyReferenceToImgTmp(_domainname) { - for (index = 0; index < 2; ++index) { - _filenamevon = REFERENCES[index]["name"]; - _filenamenach = _filenamevon.replace("/config/", "/img_tmp/"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - } -} - - -function GetReferencesInfo(){ - return REFERENCES; -} - - -function UpdateConfigReferences(_domainname){ - for (var index = 0; index < 2; ++index) { - _filenamenach = REFERENCES[index]["name"]; - _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - } -} - - -function UpdateConfigReference(_anzneueref, _domainname){ - var index = 0; - - if (_anzneueref == 1) { - index = 0; - } - - else if (_anzneueref == 2) { - index = 1; - } - - _filenamenach = REFERENCES[index]["name"]; - _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); - - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); - - _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); - _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); - - FileDeleteOnServer(_filenamenach, _domainname); - FileCopyOnServer(_filenamevon, _filenamenach, _domainname); -} - - -function getNUMBERInfo(){ - return NUMBERS; -} - - -function RenameNUMBER(_alt, _neu){ - if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0)) { - return "Number sequence name must not contain , . \" or a space"; - } - - index = -1; - found = false; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _alt) { - index = i; - } - - if (NUMBERS[i]["name"] == _neu) { - found = true; - } - } - - if (found) { - return "Number sequence name is already existing, please choose another name"; - } - - NUMBERS[index]["name"] = _neu; - - return ""; -} - - -function DeleteNUMBER(_delete){ - if (NUMBERS.length == 1) { - return "One number sequence is mandatory. Therefore this cannot be deleted" - } - - index = -1; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _delete) { - index = i; - } - } - - if (index > -1) { - NUMBERS.splice(index, 1); - } - - return ""; -} - - -function CreateNUMBER(_numbernew){ - found = false; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _numbernew) { - found = true; - } - } - - if (found) { - return "Number sequence name is already existing, please choose another name"; - } - - _ret = new Object(); - _ret["name"] = _numbernew; - _ret['digit'] = new Array(); - _ret['analog'] = new Array(); - - for (_cat in param) { - for (_param in param[_cat]) { - if (param[_cat][_param]["Numbers"] == true) { - if (typeof (_ret[_cat]) === "undefined") { - _ret[_cat] = new Object(); - } - - _ret[_cat][_param] = new Object(); - - if (param[_cat][_param]["defaultValue"] === "") { - _ret[_cat][_param]["found"] = false; - _ret[_cat][_param]["enabled"] = false; - } - else { - _ret[_cat][_param]["found"] = true; - _ret[_cat][_param]["enabled"] = true; - _ret[_cat][_param]["value1"] = param[_cat][_param]["defaultValue"]; - - } - - _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; - } - } - } - - NUMBERS.push(_ret); - return ""; -} - - -function getROIInfo(_typeROI, _number){ - index = -1; - - for (var i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _number) { - index = i; - } - } - - if (index != -1) { - return NUMBERS[index][_typeROI]; - } - else { - return ""; - } -} - - -function RenameROI(_number, _type, _alt, _neu){ - if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) || (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || (_neu.includes("\""))) { - return "ROI name must not contain . : , ; = \" or space"; - } - - index = -1; - found = false; - _indexnumber = -1; - - for (j = 0; j < NUMBERS.length; ++j) { - if (NUMBERS[j]["name"] == _number) { - _indexnumber = j; - } - } - - if (_indexnumber == -1) { - return "Number sequence not existing. ROI cannot be renamed" - } - - for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { - if (NUMBERS[_indexnumber][_type][i]["name"] == _alt) { - index = i; - } - - if (NUMBERS[_indexnumber][_type][i]["name"] == _neu) { - found = true; - } - } - - if (found) { - return "ROI name is already existing, please choose another name"; - } - - NUMBERS[_indexnumber][_type][index]["name"] = _neu; - - return ""; -} - - -function DeleteNUMBER(_delte) { - if (NUMBERS.length == 1) { - return "The last number cannot be deleted" - } - - index = -1; - - for (i = 0; i < NUMBERS.length; ++i) { - if (NUMBERS[i]["name"] == _delte) { - index = i; - } - } - - if (index > -1) { - NUMBERS.splice(index, 1); - } - - return ""; -} - - -function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){ - _indexnumber = -1; - - for (j = 0; j < NUMBERS.length; ++j) { - if (NUMBERS[j]["name"] == _number) { - _indexnumber = j; - } - } - - if (_indexnumber == -1) { - return "Number sequence not existing. ROI cannot be created" - } - - found = false; - - for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { - if (NUMBERS[_indexnumber][_type][i]["name"] == _roinew) { - found = true; - } - } - - if (found) { - return "ROI name is already existing, please choose another name"; - } - - _ret = new Object(); - _ret["name"] = _roinew; - _ret["x"] = _x; - _ret["y"] = _y; - _ret["dx"] = _dx; - _ret["dy"] = _dy; - _ret["ar"] = _dx / _dy; - _ret["CCW"] = _CCW; - - NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret); - - return ""; -} +var config_gesamt = ""; +var config_split = []; +var param = []; +var category; +var ref = new Array(2); +var NUMBERS = new Array(0); +var REFERENCES = new Array(0); + + +function getNUMBERSList() { + _domainname = getDomainname(); + var namenumberslist = ""; + + var xhttp = new XMLHttpRequest(); + + xhttp.addEventListener('load', function(event) { + if (xhttp.status >= 200 && xhttp.status < 300) { + namenumberslist = xhttp.responseText; + } + else { + console.warn(request.statusText, request.responseText); + } + }); + + try { + url = _domainname + '/editflow?task=namenumbers'; + xhttp.open("GET", url, false); + xhttp.send(); + } catch (error) {} + + namenumberslist = namenumberslist.split("\t"); + + return namenumberslist; +} + + +function getDATAList() { + _domainname = getDomainname(); + datalist = ""; + + var xhttp = new XMLHttpRequest(); + + xhttp.addEventListener('load', function(event) { + if (xhttp.status >= 200 && xhttp.status < 300) { + datalist = xhttp.responseText; + } + else { + console.warn(request.statusText, request.responseText); + } + }); + + try { + url = _domainname + '/editflow?task=data'; + xhttp.open("GET", url, false); + xhttp.send(); + } catch (error) {} + + datalist = datalist.split("\t"); + datalist.pop(); + datalist.sort(); + + return datalist; +} + + +function getTFLITEList() { + _domainname = getDomainname(); + tflitelist = ""; + + var xhttp = new XMLHttpRequest(); + + xhttp.addEventListener('load', function(event) { + if (xhttp.status >= 200 && xhttp.status < 300) { + tflitelist = xhttp.responseText; + } + else { + console.warn(request.statusText, request.responseText); + } + }); + + try { + url = _domainname + '/editflow?task=tflite'; + xhttp.open("GET", url, false); + xhttp.send(); + } catch (error) {} + + tflitelist = tflitelist.split("\t"); + tflitelist.sort(); + + return tflitelist; +} + + +function ParseConfig() { + config_split = config_gesamt.split("\n"); + var aktline = 0; + + param = new Object(); + category = new Object(); + + var catname = "TakeImage"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "RawImagesLocation"); + ParamAddValue(param, catname, "RawImagesRetention"); + ParamAddValue(param, catname, "WaitBeforeTakingPicture"); + ParamAddValue(param, catname, "CamGainceiling"); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + ParamAddValue(param, catname, "CamQuality"); // 0 - 63 + ParamAddValue(param, catname, "CamBrightness"); // (-2 to 2) - set brightness + ParamAddValue(param, catname, "CamContrast"); //-2 - 2 + ParamAddValue(param, catname, "CamSaturation"); //-2 - 2 + ParamAddValue(param, catname, "CamSharpness"); //-2 - 2 + ParamAddValue(param, catname, "CamAutoSharpness"); // (1 or 0) + ParamAddValue(param, catname, "CamSpecialEffect"); // 0 - 6 + ParamAddValue(param, catname, "CamWbMode"); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + ParamAddValue(param, catname, "CamAwb"); // white balance enable (0 or 1) + ParamAddValue(param, catname, "CamAwbGain"); // Auto White Balance enable (0 or 1) + ParamAddValue(param, catname, "CamAec"); // auto exposure off (1 or 0) + ParamAddValue(param, catname, "CamAec2"); // automatic exposure sensor (0 or 1) + ParamAddValue(param, catname, "CamAeLevel"); // auto exposure levels (-2 to 2) + ParamAddValue(param, catname, "CamAecValue"); // set exposure manually (0-1200) + ParamAddValue(param, catname, "CamAgc"); // auto gain off (1 or 0) + ParamAddValue(param, catname, "CamAgcGain"); // set gain manually (0 - 30) + ParamAddValue(param, catname, "CamBpc"); // black pixel correction + ParamAddValue(param, catname, "CamWpc"); // white pixel correction + ParamAddValue(param, catname, "CamRawGma"); // (1 or 0) + ParamAddValue(param, catname, "CamLenc"); // lens correction (1 or 0) + ParamAddValue(param, catname, "CamHmirror"); // (0 or 1) flip horizontally + ParamAddValue(param, catname, "CamVflip"); // Invert image (0 or 1) + ParamAddValue(param, catname, "CamDcw"); // downsize enable (1 or 0) + ParamAddValue(param, catname, "CamDenoise"); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + ParamAddValue(param, catname, "CamZoom"); + ParamAddValue(param, catname, "CamZoomOffsetX"); + ParamAddValue(param, catname, "CamZoomOffsetY"); + ParamAddValue(param, catname, "CamZoomSize"); + ParamAddValue(param, catname, "LEDIntensity"); + ParamAddValue(param, catname, "Demo"); + + var catname = "Alignment"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "InitialRotate"); + ParamAddValue(param, catname, "SearchFieldX"); + ParamAddValue(param, catname, "SearchFieldY"); + ParamAddValue(param, catname, "AlignmentAlgo"); + + var catname = "Digits"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Model"); + ParamAddValue(param, catname, "CNNGoodThreshold", 1); + ParamAddValue(param, catname, "ROIImagesLocation"); + ParamAddValue(param, catname, "ROIImagesRetention"); + + var catname = "Analog"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Model"); + ParamAddValue(param, catname, "ROIImagesLocation"); + ParamAddValue(param, catname, "ROIImagesRetention"); + + var catname = "PostProcessing"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "DecimalShift", 1, true); + ParamAddValue(param, catname, "AnalogDigitalTransitionStart", 1, true); + // ParamAddValue(param, catname, "PreValueUse", 1, true, "true"); + ParamAddValue(param, catname, "PreValueUse"); + ParamAddValue(param, catname, "PreValueAgeStartup"); + ParamAddValue(param, catname, "AllowNegativeRates", 1, true, "false"); + ParamAddValue(param, catname, "MaxRateValue", 1, true); + ParamAddValue(param, catname, "MaxRateType", 1, true); + ParamAddValue(param, catname, "ExtendedResolution", 1, true, "false"); + ParamAddValue(param, catname, "IgnoreLeadingNaN", 1, true, "false"); + // ParamAddValue(param, catname, "IgnoreAllNaN", 1, true, "false"); + ParamAddValue(param, catname, "ErrorMessage"); + ParamAddValue(param, catname, "CheckDigitIncreaseConsistency"); + + var catname = "MQTT"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "MainTopic", 1, false); + ParamAddValue(param, catname, "ClientID"); + ParamAddValue(param, catname, "user"); + ParamAddValue(param, catname, "password"); + ParamAddValue(param, catname, "RetainMessages"); + ParamAddValue(param, catname, "HomeassistantDiscovery"); + ParamAddValue(param, catname, "MeterType"); + ParamAddValue(param, catname, "CACert"); + ParamAddValue(param, catname, "ClientCert"); + ParamAddValue(param, catname, "ClientKey"); + + var catname = "InfluxDB"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "Database"); +// ParamAddValue(param, catname, "Measurement"); + ParamAddValue(param, catname, "user"); + ParamAddValue(param, catname, "password"); + ParamAddValue(param, catname, "Measurement", 1, true); + ParamAddValue(param, catname, "Field", 1, true); + + var catname = "InfluxDBv2"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "Bucket"); +// ParamAddValue(param, catname, "Measurement"); + ParamAddValue(param, catname, "Org"); + ParamAddValue(param, catname, "Token"); + ParamAddValue(param, catname, "Measurement", 1, true); + ParamAddValue(param, catname, "Field", 1, true); + + var catname = "GPIO"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "IO0", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO1", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO3", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO4", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO12", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "IO13", 6, false, "", [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]); + ParamAddValue(param, catname, "LEDType"); + ParamAddValue(param, catname, "LEDNumbers"); + ParamAddValue(param, catname, "LEDColor", 3); + // Default Values, um abwärtskompatiblität zu gewährleisten + param[catname]["LEDType"]["value1"] = "WS2812"; + param[catname]["LEDNumbers"]["value1"] = "2"; + param[catname]["LEDColor"]["value1"] = "50"; + param[catname]["LEDColor"]["value2"] = "50"; + param[catname]["LEDColor"]["value3"] = "50"; + + var catname = "AutoTimer"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "AutoStart"); + ParamAddValue(param, catname, "Interval"); + + var catname = "DataLogging"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "DataLogActive"); + ParamAddValue(param, catname, "DataFilesRetention"); + + var catname = "Debug"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "LogLevel"); + ParamAddValue(param, catname, "LogfilesRetention"); + + var catname = "System"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Tooltip"); + ParamAddValue(param, catname, "TimeZone"); + ParamAddValue(param, catname, "TimeServer"); + ParamAddValue(param, catname, "Hostname"); + ParamAddValue(param, catname, "RSSIThreshold"); + ParamAddValue(param, catname, "CPUFrequency"); + ParamAddValue(param, catname, "SetupMode"); + + while (aktline < config_split.length){ + for (var cat in category) { + zw = cat.toUpperCase(); + zw1 = "[" + zw + "]"; + zw2 = ";[" + zw + "]"; + + if ((config_split[aktline].trim().toUpperCase() == zw1) || (config_split[aktline].trim().toUpperCase() == zw2)) { + if (config_split[aktline].trim().toUpperCase() == zw1) { + category[cat]["enabled"] = true; + } + + category[cat]["found"] = true; + category[cat]["line"] = aktline; + aktline = ParseConfigParamAll(aktline, cat); + continue; + } + } + + aktline++; + } + + // Make the downward compatiblity with DataLogging + if (category["DataLogging"]["found"] == false) { + category["DataLogging"]["found"] = true; + category["DataLogging"]["enabled"] = true; + + param["DataLogging"]["DataLogActive"]["found"] = true; + param["DataLogging"]["DataLogActive"]["enabled"] = true; + param["DataLogging"]["DataLogActive"]["value1"] = "true"; + + param["DataLogging"]["DataFilesRetention"]["found"] = true; + param["DataLogging"]["DataFilesRetention"]["enabled"] = true; + param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; + } + + if (category["DataLogging"]["enabled"] == false) { + category["DataLogging"]["enabled"] = true + } + + if (param["DataLogging"]["DataLogActive"]["enabled"] == false && param["DataLogging"]["DataLogActive"]["value1"] == "") { + param["DataLogging"]["DataLogActive"]["found"] = true; + param["DataLogging"]["DataLogActive"]["enabled"] = true; + param["DataLogging"]["DataLogActive"]["value1"] = "true"; + } + + if (param["DataLogging"]["DataFilesRetention"]["enabled"] == false && param["DataLogging"]["DataFilesRetention"]["value1"] == "") { + param["DataLogging"]["DataFilesRetention"]["found"] = true; + param["DataLogging"]["DataFilesRetention"]["enabled"] = true; + param["DataLogging"]["DataFilesRetention"]["value1"] = "3"; + } + + // Downward compatibility: Create RSSIThreshold if not available + if (param["System"]["RSSIThreshold"]["found"] == false) { + param["System"]["RSSIThreshold"]["found"] = true; + param["System"]["RSSIThreshold"]["enabled"] = false; + param["System"]["RSSIThreshold"]["value1"] = "0"; + } +} + + +function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _defaultValue = "", _checkRegExList = null) { + param[_cat][_param] = new Object(); + param[_cat][_param]["found"] = false; + param[_cat][_param]["enabled"] = false; + param[_cat][_param]["line"] = -1; + param[_cat][_param]["anzParam"] = _anzParam; + param[_cat][_param]["defaultValue"] = _defaultValue; + param[_cat][_param]["Numbers"] = _isNUMBER; + param[_cat][_param].checkRegExList = _checkRegExList; +}; + + +function ParseConfigParamAll(_aktline, _catname) { + ++_aktline; + + while ((_aktline < config_split.length) && !(config_split[_aktline][0] == "[") && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) { + var _input = config_split[_aktline]; + let [isCom, input] = isCommented(_input); + var linesplit = ZerlegeZeile(input); + ParamExtractValueAll(param, linesplit, _catname, _aktline, isCom); + + if (!isCom && (linesplit.length >= 5) && (_catname == 'Digits')) { + ExtractROIs(input, "digit"); + } + + if (!isCom && (linesplit.length >= 5) && (_catname == 'Analog')) { + ExtractROIs(input, "analog"); + } + + if (!isCom && (linesplit.length == 3) && (_catname == 'Alignment')) { + _newref = new Object(); + _newref["name"] = linesplit[0]; + _newref["x"] = linesplit[1]; + _newref["y"] = linesplit[2]; + REFERENCES.push(_newref); + } + + ++_aktline; + } + + return _aktline; +} + + +function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _iscom, _anzvalue = 1) { + if ((_linesplit[0].toUpperCase() == _paramname.toUpperCase()) && (_linesplit.length > _anzvalue)) { + _param[_catname][_paramname]["found"] = true; + _param[_catname][_paramname]["enabled"] = !_iscom; + _param[_catname][_paramname]["line"] = _aktline; + _param[_catname][_paramname]["anzpara"] = _anzvalue; + + for (var j = 1; j <= _anzvalue; ++j) { + _param[_catname][_paramname]["value"+j] = _linesplit[j]; + } + } +} + + +function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom) { + for (var paramname in _param[_catname]) { + _AktROI = "default"; + _AktPara = _linesplit[0]; + _pospunkt = _AktPara.indexOf ("."); + + if (_pospunkt > -1) { + _AktROI = _AktPara.substring(0, _pospunkt); + _AktPara = _AktPara.substring(_pospunkt+1); + } + + if (_AktPara.toUpperCase() == paramname.toUpperCase()) { + while (_linesplit.length <= _param[_catname][paramname]["anzParam"]) { + _linesplit.push(""); + } + + _param[_catname][paramname]["found"] = true; + _param[_catname][paramname]["enabled"] = !_iscom; + _param[_catname][paramname]["line"] = _aktline; + + if (_param[_catname][paramname]["Numbers"] == true) { // möglicher Multiusage + abc = getNUMBERS(_linesplit[0]); + abc[_catname][paramname] = new Object; + abc[_catname][paramname]["found"] = true; + abc[_catname][paramname]["enabled"] = !_iscom; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + abc[_catname][paramname]["value"+j] = _linesplit[j]; + } + + if (abc["name"] == "default") { + for (_num in NUMBERS) { // wert mit Default belegen + if (NUMBERS[_num][_catname][paramname]["found"] == false) { + NUMBERS[_num][_catname][paramname]["found"] = true; + NUMBERS[_num][_catname][paramname]["enabled"] = !_iscom; + NUMBERS[_num][_catname][paramname]["line"] = _aktline; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + NUMBERS[_num][_catname][paramname]["value"+j] = _linesplit[j]; + } + } + } + } + } + else { + _param[_catname][paramname]["found"] = true; + _param[_catname][paramname]["enabled"] = !_iscom; + _param[_catname][paramname]["line"] = _aktline; + + for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) { + _param[_catname][paramname]["value"+j] = _linesplit[j]; + } + } + } + } +} + + +function getCamConfig() { + ParseConfig(); + + param["System"]["Tooltip"]["enabled"] = true; + param["Alignment"]["InitialRotate"]["enabled"] = true; + + param["TakeImage"]["WaitBeforeTakingPicture"]["enabled"] = true; + param["TakeImage"]["CamGainceiling"]["enabled"] = true; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + param["TakeImage"]["CamQuality"]["enabled"] = true; // 0 - 63 + param["TakeImage"]["CamBrightness"]["enabled"] = true; // (-2 to 2) - set brightness + param["TakeImage"]["CamContrast"]["enabled"] = true; //-2 - 2 + param["TakeImage"]["CamSaturation"]["enabled"] = true; //-2 - 2 + param["TakeImage"]["CamSharpness"]["enabled"] = true; //-2 - 2 + param["TakeImage"]["CamAutoSharpness"]["enabled"] = true; //(1 or 0) + param["TakeImage"]["CamSpecialEffect"]["enabled"] = true; // 0 - 6 + param["TakeImage"]["CamWbMode"]["enabled"] = true; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + param["TakeImage"]["CamAwb"]["enabled"] = true; // white balance enable (0 or 1) + param["TakeImage"]["CamAwbGain"]["enabled"] = true; // Auto White Balance enable (0 or 1) + param["TakeImage"]["CamAec"]["enabled"] = true; // auto exposure off (1 or 0) + param["TakeImage"]["CamAec2"]["enabled"] = true; // automatic exposure sensor (0 or 1) + param["TakeImage"]["CamAeLevel"]["enabled"] = true; // auto exposure levels (-2 to 2) + param["TakeImage"]["CamAecValue"]["enabled"] = true; // set exposure manually (0-1200) + param["TakeImage"]["CamAgc"]["enabled"] = true; // auto gain off (1 or 0) + param["TakeImage"]["CamAgcGain"]["enabled"] = true; // set gain manually (0 - 30) + param["TakeImage"]["CamBpc"]["enabled"] = true; // black pixel correction + param["TakeImage"]["CamWpc"]["enabled"] = true; // white pixel correction + param["TakeImage"]["CamRawGma"]["enabled"] = true; // (1 or 0) + param["TakeImage"]["CamLenc"]["enabled"] = true; // lens correction (1 or 0) + param["TakeImage"]["CamHmirror"]["enabled"] = true; // (0 or 1) flip horizontally + param["TakeImage"]["CamVflip"]["enabled"] = true; // Invert image (0 or 1) + param["TakeImage"]["CamDcw"]["enabled"] = true; // downsize enable (1 or 0) + param["TakeImage"]["CamDenoise"]["enabled"] = true; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + param["TakeImage"]["CamZoom"]["enabled"] = true; + param["TakeImage"]["CamZoomOffsetX"]["enabled"] = true; + param["TakeImage"]["CamZoomOffsetY"]["enabled"] = true; + param["TakeImage"]["CamZoomSize"]["enabled"] = true; + param["TakeImage"]["LEDIntensity"]["enabled"] = true; + + if (!param["System"]["Tooltip"]["found"]) { + param["System"]["Tooltip"]["found"] = true; + param["System"]["Tooltip"].value1 = 'true'; + } + + if (!param["Alignment"]["InitialRotate"]["found"]) { + param["Alignment"]["InitialRotate"]["found"] = true; + param["Alignment"]["InitialRotate"].value1 = 'false'; + } + + if (!param["TakeImage"]["WaitBeforeTakingPicture"]["found"]) { + param["TakeImage"]["WaitBeforeTakingPicture"]["found"] = true; + param["TakeImage"]["WaitBeforeTakingPicture"].value1 = '5'; + } + if (!param["TakeImage"]["CamGainceiling"]["found"]) { + param["TakeImage"]["CamGainceiling"]["found"] = true; + param["TakeImage"]["CamGainceiling"].value1 = '1'; + } + if (!param["TakeImage"]["CamQuality"]["found"]) { + param["TakeImage"]["CamQuality"]["found"] = true; + param["TakeImage"]["CamQuality"].value1 = '10'; + } + if (!param["TakeImage"]["CamBrightness"]["found"]) { + param["TakeImage"]["CamBrightness"]["found"] = true; + param["TakeImage"]["CamBrightness"].value1 = '0'; + } + if (!param["TakeImage"]["CamContrast"]["found"]) { + param["TakeImage"]["CamContrast"]["found"] = true; + param["TakeImage"]["CamContrast"].value1 = '0'; + } + if (!param["TakeImage"]["CamSaturation"]["found"]) { + param["TakeImage"]["CamSaturation"]["found"] = true; + param["TakeImage"]["CamSaturation"].value1 = '0'; + } + if (!param["TakeImage"]["CamSharpness"]["found"]) { + param["TakeImage"]["CamSharpness"]["found"] = true; + param["TakeImage"]["CamSharpness"].value1 = '0'; + } + if (!param["TakeImage"]["CamAutoSharpness"]["found"]) { + param["TakeImage"]["CamAutoSharpness"]["found"] = true; + param["TakeImage"]["CamAutoSharpness"].value1 = 'false'; + } + if (!param["TakeImage"]["CamSpecialEffect"]["found"]) { + param["TakeImage"]["CamSpecialEffect"]["found"] = true; + param["TakeImage"]["CamSpecialEffect"].value1 = 'no_effect'; + } + if (!param["TakeImage"]["CamWbMode"]["found"]) { + param["TakeImage"]["CamWbMode"]["found"] = true; + param["TakeImage"]["CamWbMode"].value1 = 'auto'; + } + if (!param["TakeImage"]["CamAwb"]["found"]) { + param["TakeImage"]["CamAwb"]["found"] = true; + param["TakeImage"]["CamAwb"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAwbGain"]["found"]) { + param["TakeImage"]["CamAwbGain"]["found"] = true; + param["TakeImage"]["CamAwbGain"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAec"]["found"]) { + param["TakeImage"]["CamAec"]["found"] = true; + param["TakeImage"]["CamAec"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAec2"]["found"]) { + param["TakeImage"]["CamAec2"]["found"] = true; + param["TakeImage"]["CamAec2"].value1 = 'false'; + } + if (!param["TakeImage"]["CamAeLevel"]["found"]) { + param["TakeImage"]["CamAeLevel"]["found"] = true; + param["TakeImage"]["CamAeLevel"].value1 = '0'; + } + if (!param["TakeImage"]["CamAecValue"]["found"]) { + param["TakeImage"]["CamAecValue"]["found"] = true; + param["TakeImage"]["CamAecValue"].value1 = '168'; + } + if (!param["TakeImage"]["CamAgc"]["found"]) { + param["TakeImage"]["CamAgc"]["found"] = true; + param["TakeImage"]["CamAgc"].value1 = 'true'; + } + if (!param["TakeImage"]["CamAgcGain"]["found"]) { + param["TakeImage"]["CamAgcGain"]["found"] = true; + param["TakeImage"]["CamAgcGain"].value1 = '0'; + } + if (!param["TakeImage"]["CamBpc"]["found"]) { + param["TakeImage"]["CamBpc"]["found"] = true; + param["TakeImage"]["CamBpc"].value1 = 'false'; + } + if (!param["TakeImage"]["CamWpc"]["found"]) { + param["TakeImage"]["CamWpc"]["found"] = true; + param["TakeImage"]["CamWpc"].value1 = 'true'; + } + if (!param["TakeImage"]["CamRawGma"]["found"]) { + param["TakeImage"]["CamRawGma"]["found"] = true; + param["TakeImage"]["CamRawGma"].value1 = 'true'; + } + if (!param["TakeImage"]["CamLenc"]["found"]) { + param["TakeImage"]["CamLenc"]["found"] = true; + param["TakeImage"]["CamLenc"].value1 = 'true'; + } + if (!param["TakeImage"]["CamHmirror"]["found"]) { + param["TakeImage"]["CamHmirror"]["found"] = true; + param["TakeImage"]["CamHmirror"].value1 = 'false'; + } + if (!param["TakeImage"]["CamVflip"]["found"]) { + param["TakeImage"]["CamVflip"]["found"] = true; + param["TakeImage"]["CamVflip"].value1 = 'false'; + } + if (!param["TakeImage"]["CamDcw"]["found"]) { + param["TakeImage"]["CamDcw"]["found"] = true; + param["TakeImage"]["CamDcw"].value1 = 'true'; + } + if (!param["TakeImage"]["CamDenoise"]["found"]) { + param["TakeImage"]["CamDenoise"]["found"] = true; + param["TakeImage"]["CamDenoise"].value1 = '0'; + } + if (!param["TakeImage"]["CamZoom"]["found"]) { + param["TakeImage"]["CamZoom"]["found"] = true; + param["TakeImage"]["CamZoom"].value1 = 'false'; + } + if (!param["TakeImage"]["CamZoomOffsetX"]["found"]) { + param["TakeImage"]["CamZoomOffsetX"]["found"] = true; + param["TakeImage"]["CamZoomOffsetX"].value1 = '0'; + } + if (!param["TakeImage"]["CamZoomOffsetY"]["found"]) { + param["TakeImage"]["CamZoomOffsetY"]["found"] = true; + param["TakeImage"]["CamZoomOffsetY"].value1 = '0'; + } + if (!param["TakeImage"]["CamZoomSize"]["found"]) { + param["TakeImage"]["CamZoomSize"]["found"] = true; + param["TakeImage"]["CamZoomSize"].value1 = '0'; + } + if (!param["TakeImage"]["LEDIntensity"]["found"]) { + param["TakeImage"]["LEDIntensity"]["found"] = true; + param["TakeImage"]["LEDIntensity"].value1 = '50'; + } + + return param; +} + + +function getConfigParameters() { + return param; +} + + +function WriteConfigININew() { + // Cleanup empty NUMBERS + for (var j = 0; j < NUMBERS.length; ++j) { + if ((NUMBERS[j]["digit"].length + NUMBERS[j]["analog"].length) == 0) { + NUMBERS.splice(j, 1); + } + } + + config_split = new Array(0); + + for (var cat in param) { + text = "[" + cat + "]"; + + if (!category[cat]["enabled"]) { + text = ";" + text; + } + + config_split.push(text); + + for (var name in param[cat]) { + if (param[cat][name]["Numbers"]) { + for (_num in NUMBERS) { + text = NUMBERS[_num]["name"] + "." + name; + + var text = text + " =" + + for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { + if (!(typeof NUMBERS[_num][cat][name]["value"+j] == 'undefined')) { + text = text + " " + NUMBERS[_num][cat][name]["value"+j]; + } + } + + if (!NUMBERS[_num][cat][name]["enabled"]) { + text = ";" + text; + } + + config_split.push(text); + } + } + else { + var text = name + " =" + + for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) { + if (!(typeof param[cat][name]["value"+j] == 'undefined')) { + text = text + " " + param[cat][name]["value"+j]; + } + } + + if (!param[cat][name]["enabled"]) { + text = ";" + text; + } + + config_split.push(text); + } + } + + if (cat == "Digits") { + for (var _roi in NUMBERS) { + if (NUMBERS[_roi]["digit"].length > 0) { + for (var _roiddet in NUMBERS[_roi]["digit"]) { + text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["digit"][_roiddet]["name"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["x"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["y"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dx"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dy"]; + text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["CCW"]; + config_split.push(text); + } + } + } + } + + if (cat == "Analog") { + for (var _roi in NUMBERS) { + if (NUMBERS[_roi]["analog"].length > 0) { + for (var _roiddet in NUMBERS[_roi]["analog"]) { + text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["analog"][_roiddet]["name"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["x"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["y"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dx"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dy"]; + text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["CCW"]; + config_split.push(text); + } + } + } + } + + if (cat == "Alignment") { + for (var _roi in REFERENCES) { + text = REFERENCES[_roi]["name"]; + text = text + " " + REFERENCES[_roi]["x"]; + text = text + " " + REFERENCES[_roi]["y"]; + config_split.push(text); + } + } + + config_split.push(""); + } +} + + +function isCommented(input) { + let isComment = false; + + if (input.charAt(0) == ';') { + isComment = true; + input = input.substr(1, input.length-1); + } + + return [isComment, input]; +} + + +function SaveConfigToServer(_domainname){ + // leere Zeilen am Ende löschen + var zw = config_split.length - 1; + + while (config_split[zw] == "") { + config_split.pop(); + } + + var config_gesamt = ""; + + for (var i = 0; i < config_split.length; ++i) + { + config_gesamt = config_gesamt + config_split[i] + "\n"; + } + + FileDeleteOnServer("/config/config.ini", _domainname); + FileSendContent(config_gesamt, "/config/config.ini", _domainname); +} + + +function getConfig() { + return config_gesamt; +} + + +function getConfigCategory() { + return category; +} + + +function ExtractROIs(_aktline, _type){ + var linesplit = ZerlegeZeile(_aktline); + abc = getNUMBERS(linesplit[0], _type); + abc["pos_ref"] = _aktline; + abc["x"] = linesplit[1]; + abc["y"] = linesplit[2]; + abc["dx"] = linesplit[3]; + abc["dy"] = linesplit[4]; + abc["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]); + abc["CCW"] = "false"; + + if (linesplit.length >= 6) { + abc["CCW"] = linesplit[5]; + } +} + + +function getNUMBERS(_name, _type, _create = true) { + _pospunkt = _name.indexOf ("."); + + if (_pospunkt > -1) { + _digit = _name.substring(0, _pospunkt); + _roi = _name.substring(_pospunkt+1); + } + else { + _digit = "default"; + _roi = _name; + } + + _ret = -1; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _digit) { + _ret = NUMBERS[i]; + } + } + + if (!_create) { // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück + return _ret; + } + + if (_ret == -1) { + _ret = new Object(); + _ret["name"] = _digit; + _ret['digit'] = new Array(); + _ret['analog'] = new Array(); + + for (_cat in param) { + for (_param in param[_cat]) { + if (param[_cat][_param]["Numbers"] == true){ + if (typeof _ret[_cat] == 'undefined') { + _ret[_cat] = new Object(); + } + + _ret[_cat][_param] = new Object(); + _ret[_cat][_param]["found"] = false; + _ret[_cat][_param]["enabled"] = false; + _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; + } + } + } + + NUMBERS.push(_ret); + } + + if (typeof _type == 'undefined') { // muss schon existieren !!! - also erst nach Digits / Analog aufrufen + return _ret; + } + + neuroi = new Object(); + neuroi["name"] = _roi; + _ret[_type].push(neuroi); + + return neuroi; +} + + +function CopyReferenceToImgTmp(_domainname) { + for (index = 0; index < 2; ++index) { + _filenamevon = REFERENCES[index]["name"]; + _filenamenach = _filenamevon.replace("/config/", "/img_tmp/"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + } +} + + +function GetReferencesInfo(){ + return REFERENCES; +} + + +function UpdateConfigReferences(_domainname){ + for (var index = 0; index < 2; ++index) { + _filenamenach = REFERENCES[index]["name"]; + _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + } +} + + +function UpdateConfigReference(_anzneueref, _domainname){ + var index = 0; + + if (_anzneueref == 1) { + index = 0; + } + + else if (_anzneueref == 2) { + index = 1; + } + + _filenamenach = REFERENCES[index]["name"]; + _filenamevon = _filenamenach.replace("/config/", "/img_tmp/"); + + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); + + _filenamenach = _filenamenach.replace(".jpg", "_org.jpg"); + _filenamevon = _filenamevon.replace(".jpg", "_org.jpg"); + + FileDeleteOnServer(_filenamenach, _domainname); + FileCopyOnServer(_filenamevon, _filenamenach, _domainname); +} + + +function getNUMBERInfo(){ + return NUMBERS; +} + + +function RenameNUMBER(_alt, _neu){ + if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0)) { + return "Number sequence name must not contain , . \" or a space"; + } + + index = -1; + found = false; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _alt) { + index = i; + } + + if (NUMBERS[i]["name"] == _neu) { + found = true; + } + } + + if (found) { + return "Number sequence name is already existing, please choose another name"; + } + + NUMBERS[index]["name"] = _neu; + + return ""; +} + + +function DeleteNUMBER(_delete){ + if (NUMBERS.length == 1) { + return "One number sequence is mandatory. Therefore this cannot be deleted" + } + + index = -1; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _delete) { + index = i; + } + } + + if (index > -1) { + NUMBERS.splice(index, 1); + } + + return ""; +} + + +function CreateNUMBER(_numbernew){ + found = false; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _numbernew) { + found = true; + } + } + + if (found) { + return "Number sequence name is already existing, please choose another name"; + } + + _ret = new Object(); + _ret["name"] = _numbernew; + _ret['digit'] = new Array(); + _ret['analog'] = new Array(); + + for (_cat in param) { + for (_param in param[_cat]) { + if (param[_cat][_param]["Numbers"] == true) { + if (typeof (_ret[_cat]) === "undefined") { + _ret[_cat] = new Object(); + } + + _ret[_cat][_param] = new Object(); + + if (param[_cat][_param]["defaultValue"] === "") { + _ret[_cat][_param]["found"] = false; + _ret[_cat][_param]["enabled"] = false; + } + else { + _ret[_cat][_param]["found"] = true; + _ret[_cat][_param]["enabled"] = true; + _ret[_cat][_param]["value1"] = param[_cat][_param]["defaultValue"]; + + } + + _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; + } + } + } + + NUMBERS.push(_ret); + return ""; +} + + +function getROIInfo(_typeROI, _number){ + index = -1; + + for (var i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _number) { + index = i; + } + } + + if (index != -1) { + return NUMBERS[index][_typeROI]; + } + else { + return ""; + } +} + + +function RenameROI(_number, _type, _alt, _neu){ + if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) || (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || (_neu.includes("\""))) { + return "ROI name must not contain . : , ; = \" or space"; + } + + index = -1; + found = false; + _indexnumber = -1; + + for (j = 0; j < NUMBERS.length; ++j) { + if (NUMBERS[j]["name"] == _number) { + _indexnumber = j; + } + } + + if (_indexnumber == -1) { + return "Number sequence not existing. ROI cannot be renamed" + } + + for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { + if (NUMBERS[_indexnumber][_type][i]["name"] == _alt) { + index = i; + } + + if (NUMBERS[_indexnumber][_type][i]["name"] == _neu) { + found = true; + } + } + + if (found) { + return "ROI name is already existing, please choose another name"; + } + + NUMBERS[_indexnumber][_type][index]["name"] = _neu; + + return ""; +} + + +function DeleteNUMBER(_delte) { + if (NUMBERS.length == 1) { + return "The last number cannot be deleted" + } + + index = -1; + + for (i = 0; i < NUMBERS.length; ++i) { + if (NUMBERS[i]["name"] == _delte) { + index = i; + } + } + + if (index > -1) { + NUMBERS.splice(index, 1); + } + + return ""; +} + + +function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){ + _indexnumber = -1; + + for (j = 0; j < NUMBERS.length; ++j) { + if (NUMBERS[j]["name"] == _number) { + _indexnumber = j; + } + } + + if (_indexnumber == -1) { + return "Number sequence not existing. ROI cannot be created" + } + + found = false; + + for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) { + if (NUMBERS[_indexnumber][_type][i]["name"] == _roinew) { + found = true; + } + } + + if (found) { + return "ROI name is already existing, please choose another name"; + } + + _ret = new Object(); + _ret["name"] = _roinew; + _ret["x"] = _x; + _ret["y"] = _y; + _ret["dx"] = _dx; + _ret["dy"] = _dy; + _ret["ar"] = _dx / _dy; + _ret["CCW"] = _CCW; + + NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret); + + return ""; +} From ae6e7af7d34d3d97c22e7f9e158bfac9d49854b4 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Sat, 18 May 2024 22:00:17 +1000 Subject: [PATCH 13/20] Support enabling red blue swap via web interface --- .../ClassControllCamera.cpp | 118 ++++++++++-------- .../ClassControllCamera.h | 3 +- .../ClassFlowTakeImage.cpp | 5 + .../jomjol_flowcontroll/MainFlowControl.cpp | 7 ++ .../jomjol_flowcontroll/MainFlowControl.h | 5 +- param-docs/expert-params.txt | 1 + .../TakeImage/CamColorSwaped.md | 9 ++ sd-card/config/config.ini | 1 + sd-card/html/edit_config_template.html | 28 ++++- sd-card/html/readconfigparam.js | 6 + 10 files changed, 125 insertions(+), 58 deletions(-) create mode 100644 param-docs/parameter-pages/TakeImage/CamColorSwaped.md diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index d101f7f1b..a38d5f4e0 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -142,8 +142,8 @@ esp_err_t CCamera::InitCam(void) if (s != NULL) { - CCstatus.CamSensor_id = s->id.PID; - + CCstatus.CamSensor_id = s->id.PID; + // Dump camera module, warn for unsupported modules. switch (CCstatus.CamSensor_id) { @@ -298,8 +298,8 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) if (s != NULL) { - CCstatus.CamSensor_id = s->id.PID; - + CCstatus.CamSensor_id = s->id.PID; + CCstatus.ImageFrameSize = (framesize_t)s->status.framesize; CCstatus.ImageGainceiling = (gainceiling_t)s->status.gainceiling; @@ -325,7 +325,7 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) CCstatus.ImageHmirror = s->status.hmirror; CCstatus.ImageVflip = s->status.vflip; CCstatus.ImageDcw = s->status.dcw; - CCstatus.ImageDenoiseLevel = s->status.denoise; + CCstatus.ImageDenoiseLevel = s->status.denoise; return ESP_OK; } @@ -335,7 +335,6 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) } } - // - It always zooms to the image center when offsets are zero // - if imageSize = 0 then the image is not zoomed // - if imageSize = max value, then the image is fully zoomed in @@ -397,7 +396,6 @@ void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, } } - void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) { sensor_t *s = esp_camera_sensor_get(); @@ -416,48 +414,48 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in switch (CCstatus.CamSensor_id) { - case OV5640_PID: - frameSizeX = 2592; - frameSizeY = 1944; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 - // 59 = ((2560 - 640) / 8 / 4) - 1 - if (imageSize < 59) - { - _imageSize_temp = (59 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - case OV3660_PID: - frameSizeX = 2048; - frameSizeY = 1536; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 - // 43 = ((2048 - 640) / 8 / 4) - 1 - if (imageSize < 43) - { - _imageSize_temp = (43 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - case OV2640_PID: - frameSizeX = 1600; - frameSizeY = 1200; - // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 - // 29 = ((1600 - 640) / 8 / 4) - 1 - if (imageSize < 29) - { - _imageSize_temp = (29 - imageSize); - } - SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); - break; - - default: - // do nothing - break; + case OV5640_PID: + frameSizeX = 2592; + frameSizeY = 1944; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) - 1 + // 59 = ((2560 - 640) / 8 / 4) - 1 + if (imageSize < 59) + { + _imageSize_temp = (59 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case OV3660_PID: + frameSizeX = 2048; + frameSizeY = 1536; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 43 = ((2048 - 640) / 8 / 4) - 1 + if (imageSize < 43) + { + _imageSize_temp = (43 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + case OV2640_PID: + frameSizeX = 1600; + frameSizeY = 1200; + // max imageSize = ((frameSizeX - CCstatus.ImageWidth) / 8 / 4) -1 + // 29 = ((1600 - 640) / 8 / 4) - 1 + if (imageSize < 29) + { + _imageSize_temp = (29 - imageSize); + } + SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + break; + + default: + // do nothing + break; } } else @@ -482,7 +480,6 @@ void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, SetImageWidthHeightFromResolution(resol); - if (s != NULL) { s->set_quality(s, qual); @@ -538,14 +535,29 @@ void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOff { if (CCstatus.CamSensor_id == OV2640_PID) { - s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); + if (CCstatus.isImageColorSwaped == true) + { + s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal + 1, yTotal + 1, xOutput, yOutput, false, false); + } + else + { + s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); + } } else { // for CAMERA_OV5640 and CAMERA_OV3660 bool scale = !(xOutput == xTotal && yOutput == yTotal); - bool binning = (xTotal >= (frameSizeX>>1)); - s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); + bool binning = (xTotal >= (frameSizeX >> 1)); + + if (CCstatus.isImageColorSwaped == true) + { + s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal + 1, yOffset + yTotal + 1, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); + } + else + { + s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal, yOffset + yTotal, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); + } } } diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index c563c0a47..2d120dcce 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -46,10 +46,11 @@ typedef struct int ImageVflip; // Invert image (0 or 1) int ImageDcw; // downsize enable (1 or 0) - int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + int ImageDenoiseLevel; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) int ImageWidth; int ImageHeight; + bool isImageColorSwaped; int ImageLedIntensity; diff --git a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp index 42461ac48..81adf9d4e 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp @@ -117,6 +117,11 @@ bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) } } + else if ((toUpper(splitted[0]) == "CAMCOLORSWAPED") && (splitted.size() > 1)) + { + CCstatus.isImageColorSwaped = stringToBoolean(toUpper(splitted[1])); + } + else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1)) { std::string _ImageGainceiling = toUpper(splitted[1]); diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index ce548c83f..da1e10e4d 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -146,6 +146,7 @@ bool doflow(void) esp_err_t setCCstatusToCFstatus(void) { CFstatus.CamSensor_id = CCstatus.CamSensor_id; + CFstatus.isImageColorSwaped = CCstatus.isImageColorSwaped; CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; @@ -190,6 +191,7 @@ esp_err_t setCCstatusToCFstatus(void) esp_err_t setCFstatusToCCstatus(void) { // CCstatus.CamSensor_id = CFstatus.CamSensor_id; + CCstatus.isImageColorSwaped = CFstatus.isImageColorSwaped; CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; @@ -887,6 +889,11 @@ esp_err_t handler_editflow(httpd_req_t *req) } } + if (httpd_query_key_value(_query, "ics", _valuechar, 30) == ESP_OK) + { + CFstatus.isImageColorSwaped = numericStrToBool(_valuechar); + } + if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) { int _qual = std::stoi(_valuechar); diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.h b/code/components/jomjol_flowcontroll/MainFlowControl.h index aaf81e101..94274300e 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.h +++ b/code/components/jomjol_flowcontroll/MainFlowControl.h @@ -15,7 +15,7 @@ typedef struct uint16_t CamSensor_id; framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10 - gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) int ImageQuality; // 0 - 63 int ImageBrightness; // (-2 to 2) - set brightness @@ -41,10 +41,11 @@ typedef struct int ImageVflip; // Invert image (0 or 1) int ImageDcw; // downsize enable (1 or 0) - int ImageDenoiseLevel = 0; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + int ImageDenoiseLevel; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) int ImageWidth; int ImageHeight; + bool isImageColorSwaped; int ImageLedIntensity; diff --git a/param-docs/expert-params.txt b/param-docs/expert-params.txt index 056b71288..378a11dd6 100644 --- a/param-docs/expert-params.txt +++ b/param-docs/expert-params.txt @@ -1,4 +1,5 @@ WaitBeforeTakingPicture +CamColorSwaped CamFrameSize CamGainceiling CamQuality diff --git a/param-docs/parameter-pages/TakeImage/CamColorSwaped.md b/param-docs/parameter-pages/TakeImage/CamColorSwaped.md new file mode 100644 index 000000000..3754a6c0c --- /dev/null +++ b/param-docs/parameter-pages/TakeImage/CamColorSwaped.md @@ -0,0 +1,9 @@ +# Parameter `CamColorSwaped` +Default Value: `false` + +!!! Note + If the camera swaps the colors, this must be activated. + So far this only happens with the OV5640, there shouldn't be a problem with the OV2640. + +!!! Note + After changing this parameter you need to update your reference image and alignment markers! diff --git a/sd-card/config/config.ini b/sd-card/config/config.ini index 24b5c357b..1c41ed7ad 100644 --- a/sd-card/config/config.ini +++ b/sd-card/config/config.ini @@ -2,6 +2,7 @@ ;RawImagesLocation = /log/source ;RawImagesRetention = 15 WaitBeforeTakingPicture = 2 +CamColorSwaped = false CamGainceiling = x4 CamQuality = 8 CamBrightness = 0 diff --git a/sd-card/html/edit_config_template.html b/sd-card/html/edit_config_template.html index c67d545e5..8fbdad655 100644 --- a/sd-card/html/edit_config_template.html +++ b/sd-card/html/edit_config_template.html @@ -293,6 +293,19 @@

Configuration

$TOOLTIP_TakeImage_WaitBeforeTakingPicture + + + + isCamColorSwaped + + + + + $TOOLTIP_TakeImage_CamColorSwaped + @@ -2184,6 +2197,7 @@

Date: Mon, 20 May 2024 00:12:31 +1000 Subject: [PATCH 14/20] update jpeg quality limits --- .../jomjol_controlcamera/ClassControllCamera.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index a38d5f4e0..5de4b41e7 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -469,13 +469,17 @@ void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, { sensor_t *s = esp_camera_sensor_get(); + // OV2640 has no lower limit on jpeg quality if (CCstatus.CamSensor_id == OV5640_PID) { - qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) - } - else - { - qual = min(63, max(8, qual)); // Limit quality from 8..63 (values lower than 8 tent to be unstable) + if (CCstatus.isImageColorSwaped == true) + { + qual = min(63, max(8, qual)); + } + else + { + qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) + } } SetImageWidthHeightFromResolution(resol); From d3d5507080ebda009f061daf0071401dedb5868f Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Fri, 24 May 2024 15:03:08 +1000 Subject: [PATCH 15/20] remove color swap config; color swap workaround dependent on vflip --- .../ClassControllCamera.cpp | 36 ++++++------------- .../ClassControllCamera.h | 7 ++-- .../jomjol_controlcamera/server_camera.cpp | 6 ++-- .../ClassFlowTakeImage.cpp | 9 ++--- .../jomjol_flowcontroll/MainFlowControl.cpp | 11 ++---- .../jomjol_flowcontroll/MainFlowControl.h | 1 - param-docs/expert-params.txt | 1 - .../TakeImage/CamColorSwaped.md | 9 ----- sd-card/config/config.ini | 1 - sd-card/html/edit_config_template.html | 27 ++------------ sd-card/html/readconfigparam.js | 6 ---- 11 files changed, 23 insertions(+), 91 deletions(-) delete mode 100644 param-docs/parameter-pages/TakeImage/CamColorSwaped.md diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 5de4b41e7..816934b18 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -396,7 +396,7 @@ void CCamera::SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, } } -void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) +void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip) { sensor_t *s = esp_camera_sensor_get(); @@ -424,7 +424,7 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _imageSize_temp = (59 - imageSize); } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight, imageVflip); break; case OV3660_PID: @@ -437,7 +437,7 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _imageSize_temp = (43 - imageSize); } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight, imageVflip); break; case OV2640_PID: @@ -450,7 +450,7 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in _imageSize_temp = (29 - imageSize); } SanitizeZoomParams(_imageSize_temp, frameSizeX, frameSizeY, _imageWidth, _imageHeight, _offsetx, _offsety); - SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight); + SetCamWindow(s, frameSizeX, frameSizeY, _offsetx, _offsety, _imageWidth, _imageHeight, CCstatus.ImageWidth, CCstatus.ImageHeight, imageVflip); break; default: @@ -472,14 +472,7 @@ void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, // OV2640 has no lower limit on jpeg quality if (CCstatus.CamSensor_id == OV5640_PID) { - if (CCstatus.isImageColorSwaped == true) - { - qual = min(63, max(8, qual)); - } - else - { - qual = min(63, max(18, qual)); // Limit quality from 18..63 (values lower than 20 tent to be unstable) - } + qual = min(63, max(8, qual)); } SetImageWidthHeightFromResolution(resol); @@ -487,7 +480,7 @@ void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, if (s != NULL) { s->set_quality(s, qual); - SetZoomSize(zoomEnabled, zoomOffsetX, zoomOffsetY, imageSize); + SetZoomSize(zoomEnabled, zoomOffsetX, zoomOffsetY, imageSize, imageVflip); } else { @@ -535,18 +528,11 @@ void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) } } -void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput) +void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput, int imageVflip) { if (CCstatus.CamSensor_id == OV2640_PID) { - if (CCstatus.isImageColorSwaped == true) - { - s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal + 1, yTotal + 1, xOutput, yOutput, false, false); - } - else - { - s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); - } + s->set_res_raw(s, 0, 0, 0, 0, xOffset, yOffset, xTotal, yTotal, xOutput, yOutput, false, false); } else { @@ -554,9 +540,9 @@ void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOff bool scale = !(xOutput == xTotal && yOutput == yTotal); bool binning = (xTotal >= (frameSizeX >> 1)); - if (CCstatus.isImageColorSwaped == true) + if (imageVflip == true) { - s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal + 1, yOffset + yTotal + 1, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); + s->set_res_raw(s, xOffset, yOffset, xOffset + xTotal - 1, yOffset + yTotal - 1, 0, 0, frameSizeX, frameSizeY, xOutput, yOutput, scale, binning); } else { @@ -893,7 +879,7 @@ esp_err_t CCamera::CaptureToStream(httpd_req_t *req, bool FlashlightOn) if (CFstatus.changedCameraSettings) { Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip); CFstatus.changedCameraSettings = false; } diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index 2d120dcce..90130369e 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -50,7 +50,6 @@ typedef struct int ImageWidth; int ImageHeight; - bool isImageColorSwaped; int ImageLedIntensity; @@ -76,7 +75,7 @@ class CCamera void ledc_init(void); bool loadNextDemoImage(camera_fb_t *fb); long GetFileSize(std::string filename); - void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput); + void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput, int imageVflip); void SetImageWidthHeightFromResolution(framesize_t resol); void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY); @@ -93,8 +92,8 @@ class CCamera esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); - void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); - void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize); + void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip); + void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip); void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel); void SetLEDIntensity(float _intrel); diff --git a/code/components/jomjol_controlcamera/server_camera.cpp b/code/components/jomjol_controlcamera/server_camera.cpp index ed6d0d126..08affb128 100644 --- a/code/components/jomjol_controlcamera/server_camera.cpp +++ b/code/components/jomjol_controlcamera/server_camera.cpp @@ -100,7 +100,7 @@ esp_err_t handler_capture(httpd_req_t *req) if (CFstatus.changedCameraSettings) { Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip); CFstatus.changedCameraSettings = false; } @@ -158,7 +158,7 @@ esp_err_t handler_capture_with_light(httpd_req_t *req) if (CFstatus.changedCameraSettings) { Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip); CFstatus.changedCameraSettings = false; } @@ -240,7 +240,7 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req) if (CFstatus.changedCameraSettings) { Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip); CFstatus.changedCameraSettings = false; } diff --git a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp index 81adf9d4e..caf5158b9 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowTakeImage.cpp @@ -117,11 +117,6 @@ bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) } } - else if ((toUpper(splitted[0]) == "CAMCOLORSWAPED") && (splitted.size() > 1)) - { - CCstatus.isImageColorSwaped = stringToBoolean(toUpper(splitted[1])); - } - else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1)) { std::string _ImageGainceiling = toUpper(splitted[1]); @@ -426,7 +421,7 @@ bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph) } Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip); rawImage = new CImageBasis("rawImage"); rawImage->CreateEmptyImage(CCstatus.ImageWidth, CCstatus.ImageHeight, 3); @@ -469,7 +464,7 @@ bool ClassFlowTakeImage::doFlow(string zwtime) if (CFstatus.changedCameraSettings) { Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera - Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip); CFstatus.changedCameraSettings = false; } diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index da1e10e4d..87ecc3b64 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -146,7 +146,6 @@ bool doflow(void) esp_err_t setCCstatusToCFstatus(void) { CFstatus.CamSensor_id = CCstatus.CamSensor_id; - CFstatus.isImageColorSwaped = CCstatus.isImageColorSwaped; CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; @@ -191,7 +190,6 @@ esp_err_t setCCstatusToCFstatus(void) esp_err_t setCFstatusToCCstatus(void) { // CCstatus.CamSensor_id = CFstatus.CamSensor_id; - CCstatus.isImageColorSwaped = CFstatus.isImageColorSwaped; CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; @@ -889,11 +887,6 @@ esp_err_t handler_editflow(httpd_req_t *req) } } - if (httpd_query_key_value(_query, "ics", _valuechar, 30) == ESP_OK) - { - CFstatus.isImageColorSwaped = numericStrToBool(_valuechar); - } - if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) { int _qual = std::stoi(_valuechar); @@ -1128,8 +1121,8 @@ esp_err_t handler_editflow(httpd_req_t *req) // CFstatus >>> Kamera setCFstatusToCam(); - Camera.SetQualityZoomSize(CFstatus.ImageQuality, CFstatus.ImageFrameSize, CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); - // Camera.SetZoomSize(CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize); + Camera.SetQualityZoomSize(CFstatus.ImageQuality, CFstatus.ImageFrameSize, CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize, CFstatus.ImageVflip); + // Camera.SetZoomSize(CFstatus.ImageZoomEnabled, CFstatus.ImageZoomOffsetX, CFstatus.ImageZoomOffsetY, CFstatus.ImageZoomSize, CFstatus.ImageVflip); // Kameraeinstellungen wurden verädert CFstatus.changedCameraSettings = true; diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.h b/code/components/jomjol_flowcontroll/MainFlowControl.h index 94274300e..527f8238a 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.h +++ b/code/components/jomjol_flowcontroll/MainFlowControl.h @@ -45,7 +45,6 @@ typedef struct int ImageWidth; int ImageHeight; - bool isImageColorSwaped; int ImageLedIntensity; diff --git a/param-docs/expert-params.txt b/param-docs/expert-params.txt index 378a11dd6..056b71288 100644 --- a/param-docs/expert-params.txt +++ b/param-docs/expert-params.txt @@ -1,5 +1,4 @@ WaitBeforeTakingPicture -CamColorSwaped CamFrameSize CamGainceiling CamQuality diff --git a/param-docs/parameter-pages/TakeImage/CamColorSwaped.md b/param-docs/parameter-pages/TakeImage/CamColorSwaped.md deleted file mode 100644 index 3754a6c0c..000000000 --- a/param-docs/parameter-pages/TakeImage/CamColorSwaped.md +++ /dev/null @@ -1,9 +0,0 @@ -# Parameter `CamColorSwaped` -Default Value: `false` - -!!! Note - If the camera swaps the colors, this must be activated. - So far this only happens with the OV5640, there shouldn't be a problem with the OV2640. - -!!! Note - After changing this parameter you need to update your reference image and alignment markers! diff --git a/sd-card/config/config.ini b/sd-card/config/config.ini index 1c41ed7ad..24b5c357b 100644 --- a/sd-card/config/config.ini +++ b/sd-card/config/config.ini @@ -2,7 +2,6 @@ ;RawImagesLocation = /log/source ;RawImagesRetention = 15 WaitBeforeTakingPicture = 2 -CamColorSwaped = false CamGainceiling = x4 CamQuality = 8 CamBrightness = 0 diff --git a/sd-card/html/edit_config_template.html b/sd-card/html/edit_config_template.html index 8fbdad655..b57f7046b 100644 --- a/sd-card/html/edit_config_template.html +++ b/sd-card/html/edit_config_template.html @@ -293,19 +293,6 @@

Configuration

$TOOLTIP_TakeImage_WaitBeforeTakingPicture - - - - isCamColorSwaped - - - - - $TOOLTIP_TakeImage_CamColorSwaped - @@ -2197,7 +2184,6 @@

Date: Fri, 24 May 2024 23:12:23 +1000 Subject: [PATCH 16/20] fix missing commit --- code/components/jomjol_controlcamera/ClassControllCamera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 816934b18..eb1558479 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -465,7 +465,7 @@ void CCamera::SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, in } } -void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize) +void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip) { sensor_t *s = esp_camera_sensor_get(); From 11525cd99b38671d28af825ae6335c6c2c48296b Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Mon, 27 May 2024 11:01:50 +1000 Subject: [PATCH 17/20] fix gain ceiling --- .../ClassControllCamera.cpp | 60 +++++++++++++------ .../ClassControllCamera.h | 2 + .../jomjol_flowcontroll/MainFlowControl.cpp | 51 ++++++++++------ sd-card/html/edit_config_template.html | 3 +- 4 files changed, 79 insertions(+), 37 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index eb1558479..bd830ed92 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -242,8 +242,6 @@ esp_err_t CCamera::setSensorDatenFromCCstatus(void) if (s != NULL) { s->set_framesize(s, CCstatus.ImageFrameSize); - s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 @@ -252,36 +250,37 @@ esp_err_t CCamera::setSensorDatenFromCCstatus(void) // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); - s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable + s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 + s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 + + // s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + ov5640_set_gainceiling(s, CCstatus.ImageGainceiling); - s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable + s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable + s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable + s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable - s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable - s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 + s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable + s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable + s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable s->set_bpc(s, CCstatus.ImageBpc); // 0 = disable , 1 = enable s->set_wpc(s, CCstatus.ImageWpc); // 0 = disable , 1 = enable s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable - s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable - s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable - - s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable - - s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) s->set_awb_gain(s, CCstatus.ImageAwbGain); // 0 = disable , 1 = enable s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable - s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - // special_effect muß als Letztes gesetzt werden, sonst geht es nicht - s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable - TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; + TickType_t xDelay2 = 100 / portTICK_PERIOD_MS; vTaskDelay(xDelay2); return ESP_OK; @@ -335,6 +334,31 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) } } +// on the OV5640, gainceiling must be set with the real value (x2>>>level = 2, .... x128>>>level = 128) +int CCamera::ov5640_set_gainceiling(sensor_t *s, gainceiling_t level) +{ + int ret = 0; + + if (CCstatus.CamSensor_id == OV2640_PID) + { + ret = s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + } + else + { + int _level = (1 << ((int)level + 1)); + + ret = s->set_reg(s, 0x3A18, 0xFF, (_level >> 8) & 3) || s->set_reg(s, 0x3A19, 0xFF, _level & 0xFF); + + if (ret == 0) + { + // ESP_LOGD(TAG, "Set gainceiling to: %d", level); + s->status.gainceiling = level; + } + } + + return ret; +} + // - It always zooms to the image center when offsets are zero // - if imageSize = 0 then the image is not zoomed // - if imageSize = max value, then the image is fully zoomed in diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index 90130369e..cea057260 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -89,6 +89,8 @@ class CCamera esp_err_t setSensorDatenFromCCstatus(void); esp_err_t getSensorDatenToCCstatus(void); + int ov5640_set_gainceiling(sensor_t *s, gainceiling_t level); + esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index 87ecc3b64..271e8e33a 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -238,8 +238,6 @@ esp_err_t setCFstatusToCam(void) if (s != NULL) { s->set_framesize(s, CFstatus.ImageFrameSize); - s->set_gainceiling(s, CFstatus.ImageGainceiling); - s->set_quality(s, CFstatus.ImageQuality); // 0 - 63 s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 @@ -248,35 +246,37 @@ esp_err_t setCFstatusToCam(void) // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); - s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable + s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) + + s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 - s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable - - s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable - s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 + s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 - s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable - s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable + // s->set_gainceiling(s, CFstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + Camera.ov5640_set_gainceiling(s, CFstatus.ImageGainceiling); - s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable + s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable + s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable + s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable + s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable - s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable + s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable + s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable + + s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable - s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - // special_effect muß als Letztes gesetzt werden, sonst geht es nicht - s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable - TickType_t xDelay2 = 1000 / portTICK_PERIOD_MS; + TickType_t xDelay2 = 100 / portTICK_PERIOD_MS; vTaskDelay(xDelay2); return ESP_OK; @@ -887,6 +887,21 @@ esp_err_t handler_editflow(httpd_req_t *req) } } + if (httpd_query_key_value(_query, "aecgc", _valuechar, 30) == ESP_OK) + { + int _aecgc = std::stoi(_valuechar); + switch (_aecgc) + { + case 1: CFstatus.ImageGainceiling = GAINCEILING_4X; break; + case 2: CFstatus.ImageGainceiling = GAINCEILING_8X; break; + case 3: CFstatus.ImageGainceiling = GAINCEILING_16X; break; + case 4: CFstatus.ImageGainceiling = GAINCEILING_32X; break; + case 5: CFstatus.ImageGainceiling = GAINCEILING_64X; break; + case 6: CFstatus.ImageGainceiling = GAINCEILING_128X; break; + default: CFstatus.ImageGainceiling = GAINCEILING_2X; + } + } + if (httpd_query_key_value(_query, "qual", _valuechar, 30) == ESP_OK) { int _qual = std::stoi(_valuechar); diff --git a/sd-card/html/edit_config_template.html b/sd-card/html/edit_config_template.html index b57f7046b..207cc4ef3 100644 --- a/sd-card/html/edit_config_template.html +++ b/sd-card/html/edit_config_template.html @@ -2555,6 +2555,7 @@

1)) + else if ((toUpper(splitted[0]) == "CAMDENOISE") && (splitted.size() > 1)) { if (isStringNumeric(splitted[1])) { From bdf4a30ae3066e7ba810d5e6243707d05d858121 Mon Sep 17 00:00:00 2001 From: Joo Aun Saw Date: Tue, 27 Aug 2024 01:10:40 +1000 Subject: [PATCH 20/20] fix compile errors --- .../jomjol_flowcontroll/MainFlowControl.cpp | 8 +++---- code/components/jomjol_helper/Helper.cpp | 23 ------------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index 0d1e6bd46..78afddcf5 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -1027,11 +1027,11 @@ esp_err_t handler_editflow(httpd_req_t *req) int _shp_ = std::stoi(_valuechar); if (CCstatus.CamSensor_id == OV2640_PID) { - CFstatus.ImageSharpness = clipInt(_shp, 2, -2); + CFstatus.ImageSharpness = clipInt(_shp_, 2, -2); } else { - CFstatus.ImageSharpness = clipInt(_shp, 3, -3); + CFstatus.ImageSharpness = clipInt(_shp_, 3, -3); } } } @@ -1094,11 +1094,11 @@ esp_err_t handler_editflow(httpd_req_t *req) int _ael_ = std::stoi(_valuechar); if (CCstatus.CamSensor_id == OV2640_PID) { - CFstatus.ImageAeLevel = clipInt(_ael, 2, -2); + CFstatus.ImageAeLevel = clipInt(_ael_, 2, -2); } else { - CFstatus.ImageAeLevel = clipInt(_ael, 5, -5); + CFstatus.ImageAeLevel = clipInt(_ael_, 5, -5); } } } diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index 8929df1b6..78d359e38 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/code/components/jomjol_helper/Helper.cpp @@ -1207,29 +1207,6 @@ bool isInString(std::string &s, std::string const &toFind) return true; } -int clipInt(int input, int high, int low) -{ - if (input < low) - { - input = low; - } - else if (input > high) - { - input = high; - } - return input; -} - -bool numericStrToBool(char *input) -{ - return (std::stoi(input) != 0); -} - -bool stringToBoolean(std::string input) -{ - return (input == "TRUE"); -} - // from https://stackoverflow.com/a/14678800 void replaceAll(std::string& s, const std::string& toReplace, const std::string& replaceWith) {