Merge remote-tracking branch 'upstream/rolling' into analog-digit-early-digit-test

This commit is contained in:
Frank Haverland
2024-04-28 19:40:03 +02:00
215 changed files with 12845 additions and 7039 deletions

View File

@@ -15,7 +15,7 @@ jobs:
with: with:
concurrent_skipping: same_content_newer concurrent_skipping: same_content_newer
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: recursive submodules: recursive
@@ -25,28 +25,28 @@ jobs:
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Update PIP cache on every commit - name: Update PIP cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: ~/.cache/pip path: ~/.cache/pip
key: pip-${{ github.run_id }} key: pip-${{ github.run_id }}
restore-keys: pip # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: pip # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update PlatformIO cache on every commit - name: Update PlatformIO cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-${{ github.run_id }} key: platformio-${{ github.run_id }}
restore-keys: platformio # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: platformio # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update Build cache on every commit - name: Update Build cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: ./code/.pio/ path: ./code/.pio/
key: build-${{ github.run_id }} key: build-${{ github.run_id }}
restore-keys: build # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: build # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update generated-files cache on every commit - name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: | path: |
./code/.pio/build/esp32cam/firmware.bin ./code/.pio/build/esp32cam/firmware.bin
@@ -57,7 +57,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: '3.10' python-version: '3.10'
@@ -70,7 +70,7 @@ jobs:
#run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing #run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
run: cd code; platformio run --environment esp32cam run: cd code; platformio run --environment esp32cam
- name: Prepare Web UI (copy data from repo, generate tooltip pages and update hashes in all files) - name: Prepare Web UI (generate tooltip pages and update hashes in all files)
run: | run: |
rm -rf ./html rm -rf ./html
mkdir html mkdir html
@@ -79,7 +79,7 @@ jobs:
python -m pip install markdown python -m pip install markdown
mkdir html/param-tooltips mkdir html/param-tooltips
cd tools/parameter-tooltip-generator cd tools/parameter-tooltip-generator
bash generate-param-doc-tooltips.sh python generate-param-doc-tooltips.py
cd ../.. cd ../..
cp -r ./sd-card/html/* ./html/ cp -r ./sd-card/html/* ./html/
@@ -101,10 +101,10 @@ jobs:
needs: build needs: build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Update generated-files cache on every commit - name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: | path: |
./code/.pio/build/esp32cam/firmware.bin ./code/.pio/build/esp32cam/firmware.bin
@@ -115,7 +115,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update update cache on every commit - name: Update update cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: update path: update
key: update-${{ github.run_id }} key: update-${{ github.run_id }}
@@ -144,7 +144,7 @@ jobs:
cp ./sd-card/config/*.tflite ./update/config/ 2>/dev/null || true cp ./sd-card/config/*.tflite ./update/config/ 2>/dev/null || true
- name: Upload update as update.zip artifact (Firmware + Web UI + CNN) - name: Upload update as update.zip artifact (Firmware + Web UI + CNN)
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})" name: "AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./update/* path: ./update/*
@@ -164,10 +164,10 @@ jobs:
needs: build needs: build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Update generated-files cache on every commit - name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: | path: |
./code/.pio/build/esp32cam/firmware.bin ./code/.pio/build/esp32cam/firmware.bin
@@ -178,7 +178,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update remote_setup cache on every commit - name: Update remote_setup cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: remote_setup path: remote_setup
key: remote_setup-${{ github.run_id }} key: remote_setup-${{ github.run_id }}
@@ -205,7 +205,7 @@ jobs:
cp ./sd-card/config/* ./remote_setup/config/ 2>/dev/null || true cp ./sd-card/config/* ./remote_setup/config/ 2>/dev/null || true
- name: Upload remote_setup as remote_setup.zip artifact (Firmware + Web UI + Config) - name: Upload remote_setup as remote_setup.zip artifact (Firmware + Web UI + Config)
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})" name: "AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./remote_setup/* path: ./remote_setup/*
@@ -220,10 +220,10 @@ jobs:
needs: build needs: build
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Update generated-files cache on every commit - name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: | path: |
./code/.pio/build/esp32cam/firmware.bin ./code/.pio/build/esp32cam/firmware.bin
@@ -234,7 +234,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update manual_setup cache on every commit - name: Update manual_setup cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: manual_setup path: manual_setup
key: manual_setup-${{ github.run_id }} key: manual_setup-${{ github.run_id }}
@@ -263,7 +263,7 @@ jobs:
cd ./manual_setup cd ./manual_setup
- name: Upload manual_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI) - name: Upload manual_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: "AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})" name: "AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./manual_setup path: ./manual_setup
@@ -284,24 +284,24 @@ jobs:
id-token: write id-token: write
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Update update cache on every commit - name: Update update cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: update path: update
key: update-${{ github.run_id }} key: update-${{ github.run_id }}
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update remote_setup cache on every commit - name: Update remote_setup cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: remote_setup path: remote_setup
key: remote_setup-${{ github.run_id }} key: remote_setup-${{ github.run_id }}
restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update manual_setup cache on every commit - name: Update manual_setup cache on every commit
uses: actions/cache@v3.2.3 uses: actions/cache@v4
with: with:
path: manual_setup path: manual_setup
key: manual_setup-${{ github.run_id }} key: manual_setup-${{ github.run_id }}
@@ -396,7 +396,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Get version of last release - name: Get version of last release
id: last_release id: last_release
@@ -410,20 +410,21 @@ jobs:
run: | run: |
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..." echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
rm -f docs/binary/firmware.bin rm -f docs/binary/firmware.bin
wget https://github.com/jomjol/AI-on-the-edge-device/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip wget ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
cp -f firmware.bin docs/binary/firmware.bin cp -f firmware.bin docs/binary/firmware.bin
echo "Updating index and manifest file..." echo "Updating index and manifest file..."
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
- name: Setup Pages - name: Setup Pages
uses: actions/configure-pages@v2 uses: actions/configure-pages@v4
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v1 uses: actions/upload-pages-artifact@v2
with: with:
path: 'docs' path: 'docs'
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v1 uses: actions/deploy-pages@v3 # Note: v4 does not work!

View File

@@ -1,5 +1,5 @@
# Reply Bot # Reply Bot
# It uses the configuration in .github/label-commenter-config.yml # It uses the configuration in .github/label-commenter-config.yaml
# See https://github.com/peaceiris/actions-label-commenter # See https://github.com/peaceiris/actions-label-commenter
name: Reply-Bot name: Reply-Bot
@@ -25,7 +25,7 @@ jobs:
#################################################################### ####################################################################
## Remove labels again (issues only) ## Remove labels again (issues only)
## Make sure to also add the reply message to .github/label-commenter-config.yml! ## Make sure to also add the reply message to .github/label-commenter-config.yaml!
## This currently seems no longer to work due to changes on the actions-cool/issues-helper! ## This currently seems no longer to work due to changes on the actions-cool/issues-helper!
#################################################################### ####################################################################
# - name: Remove 'Logfile' label again (issues only) # - name: Remove 'Logfile' label again (issues only)
@@ -74,6 +74,7 @@ jobs:
## Write the response ## Write the response
#################################################################### ####################################################################
- name: Write Response - name: Write Response
uses: peaceiris/actions-label-commenter@c2d00660c86f2b9ed0fb35b372c451558eba85b3 uses: peaceiris/actions-label-commenter@v1
with: with:
repo-token: "${{ secrets.GITHUB_TOKEN }}" github_token: "${{ secrets.GITHUB_TOKEN }}"
config_file: .github/label-commenter-config.yaml

View File

@@ -1,8 +1,60 @@
## [unreleased] - 2023-12-21 ## [update] - 2024-03-30
### Changes For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.6.0...v15.7.0)
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/rolling...v15.3.0) #### Core Changes
- New tflite-Model for Analog (v13.0.0)
- New tflite-Model for Digital Hybrid (v7.0.0)
#### Bug Fixes
- tbd
## [15.7.0] - 2024-02-17
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.6.0...v15.7.0)
#### Core Changes
- Added new camera settings (See `Settings > Alignment > Reference Image and Camera Settings`). You might need to re-create the reference image and alignment marks. Note worthy:
- You can now crop the image
- Support to configure sharpness, grayscale, negatoive and exposure
- Enhanced various WebUI pages with better explanations and usability
- Add Firmware Version to MQTT
#### Bug Fixes
- Reverted "Implemented late analog / digital transition [#2778](https://github.com/jomjol/AI-on-the-edge-device/pull/2778) (introduced in `v15.5`) as is seems to cause issues for many users.
## [15.6.0] - 2024-02-09
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.5.0...v15.6.0)
#### Fixed
* Fixed issues with the SD-Card initialization
## [15.5.0] - 2024-02-02
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.4.0...v15.5.0)
#### Changed
- Update PlattformIO to v6.5.0, which means esp-idf to v5.1
- Enhance busy notification
- Implemented late analog / digital transition
#### Fixed
* ATA-TRIM: workaround for old SD-cards with no trim function to work with esp-idf v5.x
* InfluxDB: Modified the time conversions to be more stable (UTC vs. local time shifts)
* Fix negatives on extended resolution false
* Show chip infos on info page
* Fix memory leaks in tflite integration
## [15.4.0] - 2023-12-22
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.4.0)
#### Changed #### Changed
@@ -18,6 +70,8 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
- dig-class100-0167_s2_q.tflite - dig-class100-0167_s2_q.tflite
- dig-class11_1700_s2.tflite - dig-class11_1700_s2.tflite
- ana-cont_1208_s2_q.tflite - ana-cont_1208_s2_q.tflite
- Added config entries for MQTT TLS
#### Fixed #### Fixed
@@ -27,13 +81,10 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
* Minor html response bugfix * Minor html response bugfix
- Memory leakage (MQTT) - Memory leakage (MQTT)
## [15.3.0] - 2023-07-22 ## [15.3.0] - 2023-07-22
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4) For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4)
#### Changed #### Changed
@@ -43,13 +94,8 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
- ana-cont_1207_s2_q.tflite - ana-cont_1207_s2_q.tflite
- dig-cont_0620_s3_q.tflite - dig-cont_0620_s3_q.tflite
## [15.2.4] - 2023-05-02 ## [15.2.4] - 2023-05-02
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.1...v15.2.4) For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.1...v15.2.4)
#### Changed #### Changed
@@ -73,8 +119,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
## [15.2.0] - 2023-04-23 ## [15.2.0] - 2023-04-23
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0) For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0)
#### Added #### Added
@@ -104,8 +148,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
## [15.1.1] - 2023-03-23 ## [15.1.1] - 2023-03-23
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1) For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1)
#### Added #### Added

View File

@@ -69,3 +69,6 @@ pio device monitor -p /dev/ttyUSB0
- `pio run --target erase` to erase the flash - `pio run --target erase` to erase the flash
- `pio run --target upload` this will upload the `bootloader.bin, partitions.bin,firmware.bin` from the `code/.pio/build/esp32cam/` folder. - `pio run --target upload` this will upload the `bootloader.bin, partitions.bin,firmware.bin` from the `code/.pio/build/esp32cam/` folder.
- `pio device monitor` to observe the logs via uart - `pio device monitor` to observe the logs via uart
# Update Parameters
If you create or rename a parameter, make sure to update its documentation in `../param-docs/parameter-pages`! Check the `../param-docs/README.md` for more information.

File diff suppressed because it is too large Load Diff

View File

@@ -15,49 +15,100 @@
#include "CImageBasis.h" #include "CImageBasis.h"
#include "../../include/defines.h" #include "../../include/defines.h"
class CCamera { typedef enum
protected: {
int ActualQuality; OV2640_MODE_UXGA,
framesize_t ActualResolution; OV2640_MODE_SVGA,
int brightness, contrast, saturation; OV2640_MODE_CIF
bool isFixedExposure; } ov2640_sensor_mode_t;
int waitbeforepicture_org;
int led_intensity = 4095;
void ledc_init(void); typedef struct
bool CameraInitSuccessful = false; {
bool demoMode = false; framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10
gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128)
bool loadNextDemoImage(camera_fb_t *fb); int ImageQuality; // 0 - 63
long GetFileSize(std::string filename); 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)
public: int ImageWidth;
int image_height, image_width; int ImageHeight;
CCamera();
esp_err_t InitCam();
void LightOnOff(bool status); int ImageLedIntensity;
void LEDOnOff(bool status);
esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0);
esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn);
void SetQualitySize(int qual, framesize_t resol);
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation);
void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol);
void SetLEDIntensity(float _intrel);
bool testCamera(void);
void EnableAutoExposure(int flash_duration);
bool getCameraInitSuccessful();
void useDemoMode(void);
framesize_t TextToFramesize(const char * text); bool ImageZoomEnabled;
int ImageZoomMode;
int ImageZoomOffsetX;
int ImageZoomOffsetY;
int ImageZoomSize;
esp_err_t CaptureToFile(std::string nm, int delay = 0); int WaitBeforePicture;
esp_err_t CaptureToBasisImage(CImageBasis *_Image, int delay = 0); 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 resolution, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput);
void SetImageWidthHeightFromResolution(framesize_t resol);
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; extern CCamera Camera;
#endif #endif

View File

@@ -0,0 +1,152 @@
#include <stdint.h>
#include "esp_camera.h"
#include "ov2640_sharpness.h"
const static uint8_t OV2640_SHARPNESS_AUTO[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0x20, 0x20,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_MANUAL[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0x00, 0x20,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL0[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xC0, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL1[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xC1, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL2[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xC2, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL3[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xC4, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL4[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xC8, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL5[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xD0, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL6[]=
{
//reg, val, mask
0xFF, 0x00, 0xFF,
0x92, 0x01, 0xFF,
0x93, 0xDF, 0x1F,
0x00, 0x00, 0x00
};
const static uint8_t *OV2640_SETTING_SHARPNESS[]=
{
OV2640_SHARPNESS_LEVEL0, // -3 sharpness
OV2640_SHARPNESS_LEVEL1,
OV2640_SHARPNESS_LEVEL2,
OV2640_SHARPNESS_LEVEL3,
OV2640_SHARPNESS_LEVEL4,
OV2640_SHARPNESS_LEVEL5,
OV2640_SHARPNESS_LEVEL6 // +3 sharpness
};
#define OV2640_MAXLEVEL_SHARPNESS 6
static int table_mask_write(sensor_t *sensor, const uint8_t* ptab)
{
uint8_t address;
uint8_t value;
uint8_t orgval;
uint8_t mask;
const uint8_t *pdata = ptab;
if (pdata == NULL)
{
return -1;
}
while (1)
{
address = *pdata++;
value = *pdata++;
mask = *pdata++;
if ((address == 0) && (value == 0) && (mask == 0))
{
break;
}
sensor->set_reg(sensor, address, mask, value);
}
return 0;
}
int ov2640_enable_auto_sharpness(sensor_t *sensor)
{
table_mask_write(sensor, OV2640_SHARPNESS_AUTO);
return 0;
}
int ov2640_set_sharpness(sensor_t *sensor, int sharpness)
{
int sharpness_temp = 0;
if (sharpness < -3)
{
sharpness_temp = -3;
}
if (sharpness > OV2640_MAXLEVEL_SHARPNESS - 3)
{
sharpness_temp = OV2640_MAXLEVEL_SHARPNESS - 3;
}
table_mask_write(sensor, OV2640_SHARPNESS_MANUAL);
table_mask_write(sensor, OV2640_SETTING_SHARPNESS[sharpness_temp + 3]);
return 0;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#ifndef OV2640_SHARPNESS_H
#define OV2640_SHARPNESS_H
#include "esp_camera.h"
int ov2640_enable_auto_sharpness(sensor_t *sensor);
int ov2640_set_sharpness(sensor_t *sensor, int sharpness); // -3 to +3, -4 for auto-sharpness
#endif

View File

@@ -5,6 +5,7 @@
#include "esp_camera.h" #include "esp_camera.h"
#include "ClassControllCamera.h" #include "ClassControllCamera.h"
#include "MainFlowControl.h"
#include "ClassLogFile.h" #include "ClassLogFile.h"
#include "esp_log.h" #include "esp_log.h"
@@ -13,183 +14,183 @@
static const char *TAG = "server_cam"; static const char *TAG = "server_cam";
void PowerResetCamera()
{
ESP_LOGD(TAG, "Resetting camera by power down line");
gpio_config_t conf;
conf.intr_type = GPIO_INTR_DISABLE;
conf.pin_bit_mask = 1LL << GPIO_NUM_32;
conf.mode = GPIO_MODE_OUTPUT;
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&conf);
void PowerResetCamera(){ // carefull, logic is inverted compared to reset pin
gpio_set_level(GPIO_NUM_32, 1);
ESP_LOGD(TAG, "Resetting camera by power down line"); vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_config_t conf; gpio_set_level(GPIO_NUM_32, 0);
conf.intr_type = GPIO_INTR_DISABLE; vTaskDelay(1000 / portTICK_PERIOD_MS);
conf.pin_bit_mask = 1LL << GPIO_NUM_32;
conf.mode = GPIO_MODE_OUTPUT;
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&conf);
// carefull, logic is inverted compared to reset pin
gpio_set_level(GPIO_NUM_32, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_NUM_32, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
} }
esp_err_t handler_lightOn(httpd_req_t *req) esp_err_t handler_lightOn(httpd_req_t *req)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOn - Start"); LogFile.WriteHeapInfo("handler_lightOn - Start");
ESP_LOGD(TAG, "handler_lightOn uri: %s", req->uri); ESP_LOGD(TAG, "handler_lightOn uri: %s", req->uri);
#endif #endif
if (Camera.getCameraInitSuccessful()) if (Camera.getCameraInitSuccessful())
{ {
Camera.LightOnOff(true); Camera.LightOnOff(true);
const char* resp_str = (const char*) req->user_ctx; const char *resp_str = (const char *)req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str)); httpd_resp_send(req, resp_str, strlen(resp_str));
} }
else else
{ {
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lighton not available!"); httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lighton not available!");
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOn - Done"); LogFile.WriteHeapInfo("handler_lightOn - Done");
#endif #endif
return ESP_OK; return ESP_OK;
} }
esp_err_t handler_lightOff(httpd_req_t *req) esp_err_t handler_lightOff(httpd_req_t *req)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOff - Start"); LogFile.WriteHeapInfo("handler_lightOff - Start");
ESP_LOGD(TAG, "handler_lightOff uri: %s", req->uri); ESP_LOGD(TAG, "handler_lightOff uri: %s", req->uri);
#endif #endif
if (Camera.getCameraInitSuccessful()) if (Camera.getCameraInitSuccessful())
{ {
Camera.LightOnOff(false); Camera.LightOnOff(false);
const char* resp_str = (const char*) req->user_ctx; const char *resp_str = (const char *)req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str)); httpd_resp_send(req, resp_str, strlen(resp_str));
} }
else else
{ {
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lightoff not available!"); httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lightoff not available!");
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOff - Done"); LogFile.WriteHeapInfo("handler_lightOff - Done");
#endif #endif
return ESP_OK; return ESP_OK;
} }
esp_err_t handler_capture(httpd_req_t *req) esp_err_t handler_capture(httpd_req_t *req)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture - Start"); LogFile.WriteHeapInfo("handler_capture - Start");
#endif #endif
if (Camera.getCameraInitSuccessful()) if (Camera.getCameraInitSuccessful())
{ {
int quality; #ifdef DEBUG_DETAIL_ON
framesize_t res; ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
#endif
Camera.GetCameraParameter(req, quality, res); // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden
if (CFstatus.changedCameraSettings)
#ifdef DEBUG_DETAIL_ON {
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality); Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
#endif Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize);
CFstatus.changedCameraSettings = false;
Camera.SetQualitySize(quality, res); }
esp_err_t result; esp_err_t result;
result = Camera.CaptureToHTTP(req); result = Camera.CaptureToHTTP(req);
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture - Done"); LogFile.WriteHeapInfo("handler_capture - Done");
#endif #endif
return result; return result;
} }
else else
{ {
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture not available!"); httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture not available!");
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
} }
esp_err_t handler_capture_with_light(httpd_req_t *req) esp_err_t handler_capture_with_light(httpd_req_t *req)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_with_light - Start"); LogFile.WriteHeapInfo("handler_capture_with_light - Start");
#endif #endif
if (Camera.getCameraInitSuccessful()) if (Camera.getCameraInitSuccessful())
{ {
char _query[100]; char _query[100];
char _delay[10]; char _delay[10];
int quality;
framesize_t res;
int delay = 2500; int delay = 2500;
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
{ {
ESP_LOGD(TAG, "Query: %s", _query); ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK) if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Delay: %s", _delay); ESP_LOGD(TAG, "Delay: %s", _delay);
#endif #endif
delay = atoi(_delay); delay = atoi(_delay);
if (delay < 0) if (delay < 0)
{
delay = 0; delay = 0;
}
} }
} }
Camera.GetCameraParameter(req, quality, res); #ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
#endif
#ifdef DEBUG_DETAIL_ON // wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality); if (CFstatus.changedCameraSettings)
#endif {
Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize);
CFstatus.changedCameraSettings = false;
}
Camera.SetQualitySize(quality, res);
Camera.LightOnOff(true); Camera.LightOnOff(true);
const TickType_t xDelay = delay / portTICK_PERIOD_MS; const TickType_t xDelay = delay / portTICK_PERIOD_MS;
vTaskDelay( xDelay ); vTaskDelay(xDelay);
esp_err_t result; esp_err_t result;
result = Camera.CaptureToHTTP(req); result = Camera.CaptureToHTTP(req);
Camera.LightOnOff(false); Camera.LightOnOff(false);
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_with_light - Done"); LogFile.WriteHeapInfo("handler_capture_with_light - Done");
#endif #endif
return result; return result;
} }
else else
{ {
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture_with_flashlight not available!"); httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture_with_flashlight not available!");
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
} }
esp_err_t handler_capture_save_to_file(httpd_req_t *req) esp_err_t handler_capture_save_to_file(httpd_req_t *req)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_save_to_file - Start"); LogFile.WriteHeapInfo("handler_capture_save_to_file - Start");
#endif #endif
if (Camera.getCameraInitSuccessful()) if (Camera.getCameraInitSuccessful())
{ {
char _query[100]; char _query[100];
char _delay[10]; char _delay[10];
@@ -197,94 +198,102 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req)
char filename[100]; char filename[100];
std::string fn = "/sdcard/"; std::string fn = "/sdcard/";
int quality;
framesize_t res;
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
{ {
ESP_LOGD(TAG, "Query: %s", _query); ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "filename", filename, 100) == ESP_OK) if (httpd_query_key_value(_query, "filename", filename, 100) == ESP_OK)
{ {
fn.append(filename); fn.append(filename);
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Filename: %s", fn.c_str()); ESP_LOGD(TAG, "Filename: %s", fn.c_str());
#endif #endif
} }
else else
{
fn.append("noname.jpg"); fn.append("noname.jpg");
}
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK) if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Delay: %s", _delay); ESP_LOGD(TAG, "Delay: %s", _delay);
#endif #endif
delay = atoi(_delay); delay = atoi(_delay);
if (delay < 0) if (delay < 0)
{
delay = 0; delay = 0;
}
} }
} }
else else
{
fn.append("noname.jpg"); fn.append("noname.jpg");
}
Camera.GetCameraParameter(req, quality, res); #ifdef DEBUG_DETAIL_ON
#ifdef DEBUG_DETAIL_ON ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality); #endif
#endif
Camera.SetQualitySize(quality, res); // 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;
}
esp_err_t result; esp_err_t result;
result = Camera.CaptureToFile(fn, delay); result = Camera.CaptureToFile(fn, delay);
const char* resp_str = (const char*) fn.c_str(); const char *resp_str = (const char *)fn.c_str();
httpd_resp_send(req, resp_str, strlen(resp_str)); httpd_resp_send(req, resp_str, strlen(resp_str));
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_save_to_file - Done"); LogFile.WriteHeapInfo("handler_capture_save_to_file - Done");
#endif #endif
return result; return result;
} }
else else
{ {
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /save not available!"); httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /save not available!");
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
} }
void register_server_camera_uri(httpd_handle_t server) void register_server_camera_uri(httpd_handle_t server)
{ {
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
ESP_LOGI(TAG, "server_part_camera - Registering URI handlers"); ESP_LOGI(TAG, "server_part_camera - Registering URI handlers");
#endif #endif
httpd_uri_t camuri = { }; httpd_uri_t camuri = {};
camuri.method = HTTP_GET; camuri.method = HTTP_GET;
camuri.uri = "/lighton"; camuri.uri = "/lighton";
camuri.handler = handler_lightOn; camuri.handler = handler_lightOn;
camuri.user_ctx = (void*) "Light On"; camuri.user_ctx = (void *)"Light On";
httpd_register_uri_handler(server, &camuri); httpd_register_uri_handler(server, &camuri);
camuri.uri = "/lightoff"; camuri.uri = "/lightoff";
camuri.handler = handler_lightOff; camuri.handler = handler_lightOff;
camuri.user_ctx = (void*) "Light Off"; camuri.user_ctx = (void *)"Light Off";
httpd_register_uri_handler(server, &camuri); httpd_register_uri_handler(server, &camuri);
camuri.uri = "/capture"; camuri.uri = "/capture";
camuri.handler = handler_capture; camuri.handler = handler_capture;
camuri.user_ctx = NULL; camuri.user_ctx = NULL;
httpd_register_uri_handler(server, &camuri); httpd_register_uri_handler(server, &camuri);
camuri.uri = "/capture_with_flashlight"; camuri.uri = "/capture_with_flashlight";
camuri.handler = handler_capture_with_light; camuri.handler = handler_capture_with_light;
camuri.user_ctx = NULL; camuri.user_ctx = NULL;
httpd_register_uri_handler(server, &camuri); httpd_register_uri_handler(server, &camuri);
camuri.uri = "/save"; camuri.uri = "/save";
camuri.handler = handler_capture_save_to_file; camuri.handler = handler_capture_save_to_file;
camuri.user_ctx = NULL; camuri.user_ctx = NULL;
httpd_register_uri_handler(server, &camuri); httpd_register_uri_handler(server, &camuri);
} }

View File

@@ -10,7 +10,6 @@
//#include "ClassControllCamera.h" //#include "ClassControllCamera.h"
void register_server_camera_uri(httpd_handle_t server); void register_server_camera_uri(httpd_handle_t server);
void PowerResetCamera(); void PowerResetCamera();
#endif #endif

View File

@@ -153,7 +153,7 @@
/*#define MINIZ_NO_MALLOC */ /*#define MINIZ_NO_MALLOC */
#ifdef MINIZ_NO_INFLATE_APIS #ifdef MINIZ_NO_INFLATE_APIS
#define MINIZ_NO_ARCHIVE_APIS //#define MINIZ_NO_ARCHIVE_APIS
#endif #endif
#ifdef MINIZ_NO_DEFLATE_APIS #ifdef MINIZ_NO_DEFLATE_APIS

View File

@@ -547,7 +547,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
/* Get value of expected key from query string */ /* Get value of expected key from query string */
if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) { if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param); ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
readonly = param && strcmp(param,"true")==0; readonly = (strcmp(param,"true") == 0);
} }
} }
} }

View File

@@ -1,393 +1,402 @@
#include "ClassFlowAlignment.h" #include "ClassFlowAlignment.h"
#include "ClassFlowTakeImage.h" #include "ClassFlowTakeImage.h"
#include "ClassFlow.h" #include "ClassFlow.h"
#include "MainFlowControl.h" #include "MainFlowControl.h"
#include "CRotateImage.h" #include "CRotateImage.h"
#include "esp_log.h" #include "esp_log.h"
#include "ClassLogFile.h"
#include "ClassLogFile.h" #include "psram.h"
#include "psram.h" #include "../../include/defines.h"
#include "../../include/defines.h"
static const char *TAG = "ALIGN";
static const char *TAG = "ALIGN"; // #define DEBUG_DETAIL_ON
// #define DEBUG_DETAIL_ON void ClassFlowAlignment::SetInitialParameter(void)
{
initialrotate = 0;
void ClassFlowAlignment::SetInitialParameter(void) anz_ref = 0;
{ use_antialiasing = false;
initalrotate = 0; initialflip = false;
anz_ref = 0; SaveAllFiles = false;
initialmirror = false; namerawimage = "/sdcard/img_tmp/raw.jpg";
use_antialiasing = false; FileStoreRefAlignment = "/sdcard/config/align.txt";
initialflip = false; ListFlowControll = NULL;
SaveAllFiles = false; AlignAndCutImage = NULL;
namerawimage = "/sdcard/img_tmp/raw.jpg"; ImageBasis = NULL;
FileStoreRefAlignment = "/sdcard/config/align.txt"; ImageTMP = NULL;
ListFlowControll = NULL; #ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
AlignAndCutImage = NULL; AlgROI = (ImageData *)malloc_psram_heap(std::string(TAG) + "->AlgROI", sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
ImageBasis = NULL; #endif
ImageTMP = NULL; previousElement = NULL;
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG disabled = false;
AlgROI = (ImageData*)malloc_psram_heap(std::string(TAG) + "->AlgROI", sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); SAD_criteria = 0.05;
#endif }
previousElement = NULL;
disabled = false; ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow *> *lfc)
SAD_criteria = 0.05; {
} SetInitialParameter();
ListFlowControll = lfc;
ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc) for (int i = 0; i < ListFlowControll->size(); ++i)
{ {
SetInitialParameter(); if (((*ListFlowControll)[i])->name().compare("ClassFlowTakeImage") == 0)
ListFlowControll = lfc; {
ImageBasis = ((ClassFlowTakeImage *)(*ListFlowControll)[i])->rawImage;
for (int i = 0; i < ListFlowControll->size(); ++i) }
{ }
if (((*ListFlowControll)[i])->name().compare("ClassFlowTakeImage") == 0)
{ if (!ImageBasis) // the function take pictures does not exist --> must be created first ONLY FOR TEST PURPOSES
ImageBasis = ((ClassFlowTakeImage*) (*ListFlowControll)[i])->rawImage; {
} ESP_LOGD(TAG, "CImageBasis had to be created");
} ImageBasis = new CImageBasis("ImageBasis", namerawimage);
}
if (!ImageBasis) // the function take pictures does not exist --> must be created first ONLY FOR TEST PURPOSES }
{
ESP_LOGD(TAG, "CImageBasis had to be created"); bool ClassFlowAlignment::ReadParameter(FILE *pfile, string &aktparamgraph)
ImageBasis = new CImageBasis("ImageBasis", namerawimage); {
} std::vector<string> splitted;
} int suchex = 40;
int suchey = 40;
int alg_algo = 0; // default=0; 1 =HIGHACCURACY; 2= FAST; 3= OFF //add disable aligment algo |01.2023
bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
{ aktparamgraph = trim(aktparamgraph);
std::vector<string> splitted;
int suchex = 40; if (aktparamgraph.size() == 0)
int suchey = 40; {
int alg_algo = 0; //default=0; 1 =HIGHACCURACY; 2= FAST; 3= OFF //add disable aligment algo |01.2023 if (!this->GetNextParagraph(pfile, aktparamgraph))
{
return false;
aktparamgraph = trim(aktparamgraph); }
}
if (aktparamgraph.size() == 0)
if (!this->GetNextParagraph(pfile, aktparamgraph)) if (aktparamgraph.compare("[Alignment]") != 0)
return false; {
// Paragraph does not fit Alignment
if (aktparamgraph.compare("[Alignment]") != 0) //Paragraph does not fit Alignment return false;
return false; }
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{ {
splitted = ZerlegeZeile(aktparamgraph); splitted = ZerlegeZeile(aktparamgraph);
if ((toUpper(splitted[0]) == "FLIPIMAGESIZE") && (splitted.size() > 1))
{ if ((toUpper(splitted[0]) == "FLIPIMAGESIZE") && (splitted.size() > 1))
if (toUpper(splitted[1]) == "TRUE") {
initialflip = true; if (toUpper(splitted[1]) == "TRUE")
} {
if ((toUpper(splitted[0]) == "INITIALMIRROR") && (splitted.size() > 1)) initialflip = true;
{ }
if (toUpper(splitted[1]) == "TRUE") }
initialmirror = true; else if (((toUpper(splitted[0]) == "initialrotate") || (toUpper(splitted[0]) == "INITIALROTATE")) && (splitted.size() > 1))
} {
if (((toUpper(splitted[0]) == "INITALROTATE") || (toUpper(splitted[0]) == "INITIALROTATE")) && (splitted.size() > 1)) this->initialrotate = std::stod(splitted[1]);
{ }
this->initalrotate = std::stod(splitted[1]); else if ((toUpper(splitted[0]) == "SEARCHFIELDX") && (splitted.size() > 1))
} {
if ((toUpper(splitted[0]) == "SEARCHFIELDX") && (splitted.size() > 1)) suchex = std::stod(splitted[1]);
{ }
suchex = std::stod(splitted[1]); else if ((toUpper(splitted[0]) == "SEARCHFIELDY") && (splitted.size() > 1))
} {
if ((toUpper(splitted[0]) == "SEARCHFIELDY") && (splitted.size() > 1)) suchey = std::stod(splitted[1]);
{ }
suchey = std::stod(splitted[1]); else if ((toUpper(splitted[0]) == "ANTIALIASING") && (splitted.size() > 1))
} {
if ((toUpper(splitted[0]) == "ANTIALIASING") && (splitted.size() > 1)) if (toUpper(splitted[1]) == "TRUE")
{ {
if (toUpper(splitted[1]) == "TRUE") use_antialiasing = true;
use_antialiasing = true; }
} }
if ((splitted.size() == 3) && (anz_ref < 2)) else if ((splitted.size() == 3) && (anz_ref < 2))
{ {
References[anz_ref].image_file = FormatFileName("/sdcard" + splitted[0]); References[anz_ref].image_file = FormatFileName("/sdcard" + splitted[0]);
References[anz_ref].target_x = std::stod(splitted[1]); References[anz_ref].target_x = std::stod(splitted[1]);
References[anz_ref].target_y = std::stod(splitted[2]); References[anz_ref].target_y = std::stod(splitted[2]);
anz_ref++; anz_ref++;
} }
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
{ {
if (toUpper(splitted[1]) == "TRUE") if (toUpper(splitted[1]) == "TRUE")
SaveAllFiles = true; {
} SaveAllFiles = true;
if ((toUpper(splitted[0]) == "ALIGNMENTALGO") && (splitted.size() > 1)) }
{ }
#ifdef DEBUG_DETAIL_ON else if ((toUpper(splitted[0]) == "ALIGNMENTALGO") && (splitted.size() > 1))
std::string zw2 = "Alignment mode selected: " + splitted[1]; {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2); #ifdef DEBUG_DETAIL_ON
#endif std::string zw2 = "Alignment mode selected: " + splitted[1];
if (toUpper(splitted[1]) == "HIGHACCURACY") LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
alg_algo = 1; #endif
if (toUpper(splitted[1]) == "FAST") if (toUpper(splitted[1]) == "HIGHACCURACY")
alg_algo = 2; {
if (toUpper(splitted[1]) == "OFF") //no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 alg_algo = 1;
alg_algo = 3; }
} if (toUpper(splitted[1]) == "FAST")
} {
alg_algo = 2;
for (int i = 0; i < anz_ref; ++i) }
{ if (toUpper(splitted[1]) == "OFF")
References[i].search_x = suchex; {
References[i].search_y = suchey; // no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
References[i].fastalg_SAD_criteria = SAD_criteria; alg_algo = 3;
References[i].alignment_algo = alg_algo; }
#ifdef DEBUG_DETAIL_ON }
std::string zw2 = "Alignment mode written: " + std::to_string(alg_algo); }
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
#endif for (int i = 0; i < anz_ref; ++i)
} {
References[i].search_x = suchex;
//no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 References[i].search_y = suchey;
if(References[0].alignment_algo != 3){ References[i].fastalg_SAD_criteria = SAD_criteria;
LoadReferenceAlignmentValues(); References[i].alignment_algo = alg_algo;
} #ifdef DEBUG_DETAIL_ON
std::string zw2 = "Alignment mode written: " + std::to_string(alg_algo);
return true; LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
#endif
} }
// no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
string ClassFlowAlignment::getHTMLSingleStep(string host) if (References[0].alignment_algo != 3)
{ {
string result; LoadReferenceAlignmentValues();
}
result = "<p>Rotated Image: </p> <p><img src=\"" + host + "/img_tmp/rot.jpg\"></p>\n";
result = result + "<p>Found Alignment: </p> <p><img src=\"" + host + "/img_tmp/rot_roi.jpg\"></p>\n"; return true;
result = result + "<p>Aligned Image: </p> <p><img src=\"" + host + "/img_tmp/alg.jpg\"></p>\n"; }
return result;
} string ClassFlowAlignment::getHTMLSingleStep(string host)
{
string result;
bool ClassFlowAlignment::doFlow(string time)
{ result = "<p>Rotated Image: </p> <p><img src=\"" + host + "/img_tmp/rot.jpg\"></p>\n";
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG result = result + "<p>Found Alignment: </p> <p><img src=\"" + host + "/img_tmp/rot_roi.jpg\"></p>\n";
if (!AlgROI) // AlgROI needs to be allocated before ImageTMP to avoid heap fragmentation result = result + "<p>Aligned Image: </p> <p><img src=\"" + host + "/img_tmp/alg.jpg\"></p>\n";
{ return result;
AlgROI = (ImageData*)heap_caps_realloc(AlgROI, sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); }
if (!AlgROI)
{ bool ClassFlowAlignment::doFlow(string time)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlgROI"); {
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow"); #ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
} if (!AlgROI) // AlgROI needs to be allocated before ImageTMP to avoid heap fragmentation
} {
AlgROI = (ImageData *)heap_caps_realloc(AlgROI, sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
if (AlgROI)
{ if (!AlgROI)
ImageBasis->writeToMemoryAsJPG((ImageData*)AlgROI, 90); {
} LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlgROI");
#endif LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
}
if (!ImageTMP) }
{
ImageTMP = new CImageBasis("tmpImage", ImageBasis); // Make sure the name does not get change, it is relevant for the PSRAM allocation! if (AlgROI)
if (!ImageTMP) {
{ ImageBasis->writeToMemoryAsJPG((ImageData *)AlgROI, 90);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate tmpImage -> Exec this round aborted!"); }
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow"); #endif
return false;
} if (!ImageTMP)
} {
ImageTMP = new CImageBasis("tmpImage", ImageBasis); // Make sure the name does not get change, it is relevant for the PSRAM allocation!
delete AlignAndCutImage;
AlignAndCutImage = new CAlignAndCutImage("AlignAndCutImage", ImageBasis, ImageTMP); if (!ImageTMP)
if (!AlignAndCutImage) {
{ LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate tmpImage -> Exec this round aborted!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlignAndCutImage -> Exec this round aborted!"); LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow"); return false;
return false; }
} }
CRotateImage rt("rawImage", AlignAndCutImage, ImageTMP, initialflip); delete AlignAndCutImage;
if (initialflip) AlignAndCutImage = new CAlignAndCutImage("AlignAndCutImage", ImageBasis, ImageTMP);
{
int _zw = ImageBasis->height; if (!AlignAndCutImage)
ImageBasis->height = ImageBasis->width; {
ImageBasis->width = _zw; LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlignAndCutImage -> Exec this round aborted!");
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
_zw = ImageTMP->width; return false;
ImageTMP->width = ImageTMP->height; }
ImageTMP->height = _zw;
} CRotateImage rt("rawImage", AlignAndCutImage, ImageTMP, initialflip);
if (initialmirror) if (initialflip)
{ {
ESP_LOGD(TAG, "do mirror"); int _zw = ImageBasis->height;
rt.Mirror(); ImageBasis->height = ImageBasis->width;
ImageBasis->width = _zw;
if (SaveAllFiles)
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg")); _zw = ImageTMP->width;
} ImageTMP->width = ImageTMP->height;
ImageTMP->height = _zw;
if ((initalrotate != 0) || initialflip) }
{
if (use_antialiasing) if ((initialrotate != 0) || initialflip)
rt.RotateAntiAliasing(initalrotate); {
else if (use_antialiasing)
rt.Rotate(initalrotate); {
rt.RotateAntiAliasing(initialrotate);
if (SaveAllFiles) }
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg")); else
} {
rt.Rotate(initialrotate);
}
//no align algo if set to 3 = off //add disable aligment algo |01.2023
if(References[0].alignment_algo != 3){ if (SaveAllFiles)
if (!AlignAndCutImage->Align(&References[0], &References[1])) {
{ AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
SaveReferenceAlignmentValues(); }
} }
}// no align
// no align algo if set to 3 = off //add disable aligment algo |01.2023
if (References[0].alignment_algo != 3)
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG {
if (AlgROI) { if (!AlignAndCutImage->Align(&References[0], &References[1]))
//no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 {
if(References[0].alignment_algo != 3){ SaveReferenceAlignmentValues();
DrawRef(ImageTMP); }
} } // no align
flowctrl.DigitalDrawROI(ImageTMP);
flowctrl.AnalogDrawROI(ImageTMP); #ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
ImageTMP->writeToMemoryAsJPG((ImageData*)AlgROI, 90); if (AlgROI)
} {
#endif // no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
if (References[0].alignment_algo != 3)
if (SaveAllFiles) {
{ DrawRef(ImageTMP);
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg")); }
ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg"));
} flowctrl.DigitalDrawROI(ImageTMP);
flowctrl.AnalogDrawROI(ImageTMP);
// must be deleted to have memory space for loading tflite ImageTMP->writeToMemoryAsJPG((ImageData *)AlgROI, 90);
delete ImageTMP; }
ImageTMP = NULL; #endif
//no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 if (SaveAllFiles)
if(References[0].alignment_algo != 3){ {
LoadReferenceAlignmentValues(); AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg"));
} ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg"));
}
return true;
} // must be deleted to have memory space for loading tflite
delete ImageTMP;
ImageTMP = NULL;
void ClassFlowAlignment::SaveReferenceAlignmentValues()
{ // no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
FILE* pFile; if (References[0].alignment_algo != 3)
std::string zwtime, zwvalue; {
LoadReferenceAlignmentValues();
pFile = fopen(FileStoreRefAlignment.c_str(), "w"); }
if (strlen(zwtime.c_str()) == 0) return true;
{ }
time_t rawtime;
struct tm* timeinfo; void ClassFlowAlignment::SaveReferenceAlignmentValues()
char buffer[80]; {
FILE *pFile;
time(&rawtime); std::string zwtime, zwvalue;
timeinfo = localtime(&rawtime);
pFile = fopen(FileStoreRefAlignment.c_str(), "w");
strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
zwtime = std::string(buffer); if (strlen(zwtime.c_str()) == 0)
} {
time_t rawtime;
fputs(zwtime.c_str(), pFile); struct tm *timeinfo;
fputs("\n", pFile); char buffer[80];
zwvalue = std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_y); time(&rawtime);
zwvalue = zwvalue + "\t" +std::to_string(References[0].fastalg_SAD)+ "\t" +std::to_string(References[0].fastalg_min); timeinfo = localtime(&rawtime);
zwvalue = zwvalue + "\t" +std::to_string(References[0].fastalg_max)+ "\t" +std::to_string(References[0].fastalg_avg);
fputs(zwvalue.c_str(), pFile); strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
fputs("\n", pFile); zwtime = std::string(buffer);
}
zwvalue = std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_y);
zwvalue = zwvalue + "\t" +std::to_string(References[1].fastalg_SAD)+ "\t" +std::to_string(References[1].fastalg_min); fputs(zwtime.c_str(), pFile);
zwvalue = zwvalue + "\t" +std::to_string(References[1].fastalg_max)+ "\t" +std::to_string(References[1].fastalg_avg); fputs("\n", pFile);
fputs(zwvalue.c_str(), pFile);
fputs("\n", pFile); zwvalue = std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_y);
zwvalue = zwvalue + "\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
fclose(pFile); zwvalue = zwvalue + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
} fputs(zwvalue.c_str(), pFile);
fputs("\n", pFile);
bool ClassFlowAlignment::LoadReferenceAlignmentValues(void) zwvalue = std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_y);
{ zwvalue = zwvalue + "\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
FILE* pFile; zwvalue = zwvalue + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
char zw[1024]; fputs(zwvalue.c_str(), pFile);
string zwvalue; fputs("\n", pFile);
std::vector<string> splitted;
fclose(pFile);
}
pFile = fopen(FileStoreRefAlignment.c_str(), "r");
if (pFile == NULL) bool ClassFlowAlignment::LoadReferenceAlignmentValues(void)
return false; {
FILE *pFile;
fgets(zw, 1024, pFile); char zw[1024];
ESP_LOGD(TAG, "%s", zw); string zwvalue;
std::vector<string> splitted;
fgets(zw, 1024, pFile);
splitted = ZerlegeZeile(std::string(zw), " \t"); pFile = fopen(FileStoreRefAlignment.c_str(), "r");
if (splitted.size() < 6)
{ if (pFile == NULL)
fclose(pFile); return false;
return false;
} fgets(zw, 1024, pFile);
ESP_LOGD(TAG, "%s", zw);
References[0].fastalg_x = stoi(splitted[0]);
References[0].fastalg_y = stoi(splitted[1]); fgets(zw, 1024, pFile);
References[0].fastalg_SAD = stof(splitted[2]); splitted = ZerlegeZeile(std::string(zw), " \t");
References[0].fastalg_min = stoi(splitted[3]);
References[0].fastalg_max = stoi(splitted[4]); if (splitted.size() < 6)
References[0].fastalg_avg = stof(splitted[5]); {
fclose(pFile);
fgets(zw, 1024, pFile); return false;
splitted = ZerlegeZeile(std::string(zw)); }
if (splitted.size() < 6)
{ References[0].fastalg_x = stoi(splitted[0]);
fclose(pFile); References[0].fastalg_y = stoi(splitted[1]);
return false; References[0].fastalg_SAD = stof(splitted[2]);
} References[0].fastalg_min = stoi(splitted[3]);
References[0].fastalg_max = stoi(splitted[4]);
References[1].fastalg_x = stoi(splitted[0]); References[0].fastalg_avg = stof(splitted[5]);
References[1].fastalg_y = stoi(splitted[1]);
References[1].fastalg_SAD = stof(splitted[2]); fgets(zw, 1024, pFile);
References[1].fastalg_min = stoi(splitted[3]); splitted = ZerlegeZeile(std::string(zw));
References[1].fastalg_max = stoi(splitted[4]);
References[1].fastalg_avg = stof(splitted[5]); if (splitted.size() < 6)
{
fclose(pFile); fclose(pFile);
return false;
}
/*#ifdef DEBUG_DETAIL_ON
std::string _zw = "\tLoadReferences[0]\tx,y:\t" + std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_x); References[1].fastalg_x = stoi(splitted[0]);
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min); References[1].fastalg_y = stoi(splitted[1]);
_zw = _zw + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg); References[1].fastalg_SAD = stof(splitted[2]);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw); References[1].fastalg_min = stoi(splitted[3]);
_zw = "\tLoadReferences[1]\tx,y:\t" + std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_x); References[1].fastalg_max = stoi(splitted[4]);
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min); References[1].fastalg_avg = stof(splitted[5]);
_zw = _zw + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw); fclose(pFile);
#endif*/
/*#ifdef DEBUG_DETAIL_ON
return true; std::string _zw = "\tLoadReferences[0]\tx,y:\t" + std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_x);
} _zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
_zw = _zw + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
void ClassFlowAlignment::DrawRef(CImageBasis *_zw) _zw = "\tLoadReferences[1]\tx,y:\t" + std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_x);
{ _zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
if (_zw->ImageOkay()) _zw = _zw + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
{ LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
_zw->drawRect(References[0].target_x, References[0].target_y, References[0].width, References[0].height, 255, 0, 0, 2); #endif*/
_zw->drawRect(References[1].target_x, References[1].target_y, References[1].width, References[1].height, 255, 0, 0, 2);
} return true;
} }
void ClassFlowAlignment::DrawRef(CImageBasis *_zw)
{
if (_zw->ImageOkay())
{
_zw->drawRect(References[0].target_x, References[0].target_y, References[0].width, References[0].height, 255, 0, 0, 2);
_zw->drawRect(References[1].target_x, References[1].target_y, References[1].width, References[1].height, 255, 0, 0, 2);
}
}

View File

@@ -1,54 +1,51 @@
#pragma once #pragma once
#ifndef CLASSFLOWALIGNMENT_H #ifndef CLASSFLOWALIGNMENT_H
#define CLASSFLOWALIGNMENT_H #define CLASSFLOWALIGNMENT_H
#include "ClassFlow.h" #include "ClassFlow.h"
#include "Helper.h" #include "Helper.h"
#include "CAlignAndCutImage.h" #include "CAlignAndCutImage.h"
#include "CFindTemplate.h" #include "CFindTemplate.h"
#include <string> #include <string>
using namespace std; using namespace std;
class ClassFlowAlignment : class ClassFlowAlignment : public ClassFlow
public ClassFlow {
{ protected:
protected: float initialrotate;
float initalrotate; bool initialflip;
bool initialmirror; bool use_antialiasing;
bool initialflip; RefInfo References[2];
bool use_antialiasing; int anz_ref;
RefInfo References[2]; string namerawimage;
int anz_ref; bool SaveAllFiles;
string namerawimage; CAlignAndCutImage *AlignAndCutImage;
bool SaveAllFiles; std::string FileStoreRefAlignment;
CAlignAndCutImage *AlignAndCutImage; float SAD_criteria;
std::string FileStoreRefAlignment;
float SAD_criteria; void SetInitialParameter(void);
bool LoadReferenceAlignmentValues(void);
void SetInitialParameter(void); void SaveReferenceAlignmentValues();
bool LoadReferenceAlignmentValues(void);
void SaveReferenceAlignmentValues(); public:
CImageBasis *ImageBasis, *ImageTMP;
public: #ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
CImageBasis *ImageBasis, *ImageTMP; ImageData *AlgROI;
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG #endif
ImageData *AlgROI;
#endif ClassFlowAlignment(std::vector<ClassFlow *> *lfc);
ClassFlowAlignment(std::vector<ClassFlow*>* lfc); CAlignAndCutImage *GetAlignAndCutImage() { return AlignAndCutImage; };
CAlignAndCutImage* GetAlignAndCutImage(){return AlignAndCutImage;}; void DrawRef(CImageBasis *_zw);
void DrawRef(CImageBasis *_zw); bool ReadParameter(FILE *pfile, string &aktparamgraph);
bool doFlow(string time);
bool ReadParameter(FILE* pfile, string& aktparamgraph); string getHTMLSingleStep(string host);
bool doFlow(string time); string name() { return "ClassFlowAlignment"; };
string getHTMLSingleStep(string host); };
string name(){return "ClassFlowAlignment";};
}; #endif // CLASSFLOWALIGNMENT_H
#endif //CLASSFLOWALIGNMENT_H

View File

@@ -20,8 +20,7 @@ static const char* TAG = "CNN";
#endif #endif
ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNType _cnntype) : ClassFlowImage(NULL, TAG) ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNType _cnntype) : ClassFlowImage(NULL, TAG) {
{
string cnnmodelfile = ""; string cnnmodelfile = "";
modelxsize = 1; modelxsize = 1;
modelysize = 1; modelysize = 1;
@@ -38,16 +37,16 @@ ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNTy
} }
string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution, int prev, float _before_narrow_Analog, float analogDigitalTransitionStart) string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution, int prev, float _before_narrow_Analog, float analogDigitalTransitionStart) {
{
string result = ""; string result = "";
if (GENERAL[_analog]->ROI.size() == 0) if (GENERAL[_analog]->ROI.size() == 0) {
return result; return result;
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout _analog=" + std::to_string(_analog) + ", _extendedResolution=" + std::to_string(_extendedResolution) + ", prev=" + std::to_string(prev)); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout _analog=" + std::to_string(_analog) + ", _extendedResolution=" + std::to_string(_extendedResolution) + ", prev=" + std::to_string(prev));
if (CNNType == Analogue || CNNType == Analogue100) if (CNNType == Analogue || CNNType == Analogue100) {
{
float number = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float; float number = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
int result_after_decimal_point = ((int) floor(number * 10) + 10) % 10; int result_after_decimal_point = ((int) floor(number * 10) + 10) % 10;
@@ -55,37 +54,35 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(analog) number=" + std::to_string(number) + ", result_after_decimal_point=" + std::to_string(result_after_decimal_point) + ", prev=" + std::to_string(prev)); // LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(analog) number=" + std::to_string(number) + ", result_after_decimal_point=" + std::to_string(result_after_decimal_point) + ", prev=" + std::to_string(prev));
result = std::to_string(prev); result = std::to_string(prev);
if (_extendedResolution) if (_extendedResolution) {
result = result + std::to_string(result_after_decimal_point); result = result + std::to_string(result_after_decimal_point);
}
for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i) for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i) {
{
prev = PointerEvalAnalogNew(GENERAL[_analog]->ROI[i]->result_float, prev); prev = PointerEvalAnalogNew(GENERAL[_analog]->ROI[i]->result_float, prev);
result = std::to_string(prev) + result; result = std::to_string(prev) + result;
} }
return result; return result;
} }
if (CNNType == Digital) if (CNNType == Digital) {
{ for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i) {
for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i) if (GENERAL[_analog]->ROI[i]->result_klasse >= 10) {
{
if (GENERAL[_analog]->ROI[i]->result_klasse >= 10)
result = result + "N"; result = result + "N";
else }
else {
result = result + std::to_string(GENERAL[_analog]->ROI[i]->result_klasse); result = result + std::to_string(GENERAL[_analog]->ROI[i]->result_klasse);
}
} }
return result; return result;
} }
if ((CNNType == DoubleHyprid10) || (CNNType == Digital100)) if ((CNNType == DoubleHyprid10) || (CNNType == Digital100)) {
{
float number = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float; float number = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
if (number >= 0) // NaN? // NaN?
{ if (number >= 0) {
if (_extendedResolution) // is only set if it is the first digit (no analogue before!) // is only set if it is the first digit (no analogue before!)
{ if (_extendedResolution) {
int result_after_decimal_point = ((int) floor(number * 10)) % 10; int result_after_decimal_point = ((int) floor(number * 10)) % 10;
int result_before_decimal_point = ((int) floor(number)) % 10; int result_before_decimal_point = ((int) floor(number)) % 10;
@@ -93,36 +90,32 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
prev = result_before_decimal_point; prev = result_before_decimal_point;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100-ext) result_before_decimal_point=" + std::to_string(result_before_decimal_point) + ", result_after_decimal_point=" + std::to_string(result_after_decimal_point) + ", prev=" + std::to_string(prev)); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100-ext) result_before_decimal_point=" + std::to_string(result_before_decimal_point) + ", result_after_decimal_point=" + std::to_string(result_after_decimal_point) + ", prev=" + std::to_string(prev));
} }
else else {
{ if (_before_narrow_Analog >= 0) {
if (_before_narrow_Analog >= 0)
prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, _before_narrow_Analog, prev, true, analogDigitalTransitionStart); prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, _before_narrow_Analog, prev, true, analogDigitalTransitionStart);
else }
else {
prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev, prev); prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev, prev);
}
result = std::to_string(prev); result = std::to_string(prev);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100) prev=" + std::to_string(prev)); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(dig100) prev=" + std::to_string(prev));
} }
} }
else else {
{
result = "N"; result = "N";
if (_extendedResolution && (CNNType != Digital)) if (_extendedResolution && (CNNType != Digital)) {
result = "NN"; result = "NN";
}
} }
for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i) for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i) {
{ if (GENERAL[_analog]->ROI[i]->result_float >= 0) {
if (GENERAL[_analog]->ROI[i]->result_float >= 0)
{
prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[i]->result_float, GENERAL[_analog]->ROI[i+1]->result_float, prev); prev = PointerEvalHybridNew(GENERAL[_analog]->ROI[i]->result_float, GENERAL[_analog]->ROI[i+1]->result_float, prev);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#PointerEvalHybridNew()= " + std::to_string(prev)); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#PointerEvalHybridNew()= " + std::to_string(prev));
result = std::to_string(prev) + result; result = std::to_string(prev) + result;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#result= " + result); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout#result= " + result);
} }
else else {
{
prev = -1; prev = -1;
result = "N" + result; result = "N" + result;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(result_float<0 /'N') result_float=" + std::to_string(GENERAL[_analog]->ROI[i]->result_float)); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(result_float<0 /'N') result_float=" + std::to_string(GENERAL[_analog]->ROI[i]->result_float));
@@ -134,15 +127,28 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
return result; return result;
} }
/**
int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart) * @brief Determines the number of an ROI in connection with previous ROI results
{ *
* @param number: is the current ROI as float value from recognition
* @param number_of_predecessors: is the last (lower) ROI as float from recognition
* @param eval_predecessors: is the evaluated number. Sometimes a much lower value can change higer values
* example: 9.8, 9.9, 0.1
* 0.1 => 0 (eval_predecessors)
* The 0 makes a 9.9 to 0 (eval_predecessors)
* The 0 makes a 9.8 to 0
* @param Analog_Predecessors false/true if the last ROI is an analog or digital ROI (default=false)
* runs in special handling because analog is much less precise
* @param digitalAnalogTransitionStart start of the transitionlogic begins on number_of_predecessor (default=9.2)
*
* @return int the determined number of the current ROI
*/
int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart) {
int result; int result;
int result_after_decimal_point = ((int) floor(number * 10)) % 10; int result_after_decimal_point = ((int) floor(number * 10)) % 10;
int result_before_decimal_point = ((int) floor(number) + 10) % 10; int result_before_decimal_point = ((int) floor(number) + 10) % 10;
if (eval_predecessors < 0) if (eval_predecessors < 0) {
{
// on first digit is no spezial logic for transition needed // on first digit is no spezial logic for transition needed
// we use the recognition as given. The result is the int value of the recognition // we use the recognition as given. The result is the int value of the recognition
// add precisition of 2 digits and round before trunc // add precisition of 2 digits and round before trunc
@@ -153,8 +159,7 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
return result; return result;
} }
if (Analog_Predecessors) if (Analog_Predecessors) {
{
result = PointerEvalAnalogToDigitNew(number, number_of_predecessors, eval_predecessors, digitalAnalogTransitionStart); result = PointerEvalAnalogToDigitNew(number, number_of_predecessors, eval_predecessors, digitalAnalogTransitionStart);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - Analog predecessor, evaluation over PointerEvalAnalogNew = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - Analog predecessor, evaluation over PointerEvalAnalogNew = " + std::to_string(result) +
" number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty)); " number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty));
@@ -164,26 +169,31 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
if ((number_of_predecessors > Digital_Transition_Area_Predecessor ) && (number_of_predecessors < (10.0 - Digital_Transition_Area_Predecessor))) if ((number_of_predecessors > Digital_Transition_Area_Predecessor ) && (number_of_predecessors < (10.0 - Digital_Transition_Area_Predecessor)))
{ {
// no digit change, because predecessor is far enough away (0+/-DigitalTransitionRangePredecessor) --> number is rounded // no digit change, because predecessor is far enough away (0+/-DigitalTransitionRangePredecessor) --> number is rounded
if ((result_after_decimal_point <= DigitalBand) || (result_after_decimal_point >= (10-DigitalBand))) // Band around the digit --> Round off, as digit reaches inaccuracy in the frame // Band around the digit --> Round off, as digit reaches inaccuracy in the frame
if ((result_after_decimal_point <= DigitalBand) || (result_after_decimal_point >= (10-DigitalBand))) {
result = ((int) round(number) + 10) % 10; result = ((int) round(number) + 10) % 10;
else }
else {
result = ((int) trunc(number) + 10) % 10; result = ((int) trunc(number) + 10) % 10;
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - NO analogue predecessor, no change of digits, as pre-decimal point far enough away = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - NO analogue predecessor, no change of digits, as pre-decimal point far enough away = " + std::to_string(result) +
" number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty)); " number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty));
return result; return result;
} }
if (eval_predecessors <= 1) // Zero crossing at the predecessor has taken place (! evaluation via Prev_value and not number!) --> round up here (2.8 --> 3, but also 3.1 --> 3) // Zero crossing at the predecessor has taken place (! evaluation via Prev_value and not number!) --> round up here (2.8 --> 3, but also 3.1 --> 3)
{ if (eval_predecessors <= 1) {
// We simply assume that the current digit after the zero crossing of the predecessor // We simply assume that the current digit after the zero crossing of the predecessor
// has passed through at least half (x.5) // has passed through at least half (x.5)
if (result_after_decimal_point > 5) if (result_after_decimal_point > 5) {
// The current digit does not yet have a zero crossing, but the predecessor does.. // The current digit does not yet have a zero crossing, but the predecessor does..
result = (result_before_decimal_point + 1) % 10; result = (result_before_decimal_point + 1) % 10;
else }
else {
// Act. digit and predecessor have zero crossing // Act. digit and predecessor have zero crossing
result = result_before_decimal_point % 10; result = result_before_decimal_point % 10;
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - NO analogue predecessor, zero crossing has taken placen = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - NO analogue predecessor, zero crossing has taken placen = " + std::to_string(result) +
" number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty)); " number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty));
return result; return result;
@@ -199,10 +209,12 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
|| result_after_decimal_point >= 4) || result_after_decimal_point >= 4)
// The current digit, like the previous digit, does not yet have a zero crossing. // The current digit, like the previous digit, does not yet have a zero crossing.
result = result_before_decimal_point % 10; result = result_before_decimal_point % 10;
else }
else {
// current digit precedes the smaller digit (9.x). So already >=x.0 while the previous digit has not yet // current digit precedes the smaller digit (9.x). So already >=x.0 while the previous digit has not yet
// has no zero crossing. Therefore, it is reduced by 1. // has no zero crossing. Therefore, it is reduced by 1.
result = (result_before_decimal_point - 1 + 10) % 10; result = (result_before_decimal_point - 1 + 10) % 10;
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - O analogue predecessor, >= 9.5 --> no zero crossing yet = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - O analogue predecessor, >= 9.5 --> no zero crossing yet = " + std::to_string(result) +
" number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty) + " result_after_decimal_point = " + std::to_string(result_after_decimal_point)); " number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty) + " result_after_decimal_point = " + std::to_string(result_after_decimal_point));
@@ -210,8 +222,7 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
} }
int ClassFlowCNNGeneral::PointerEvalAnalogToDigitNew(float number, float numeral_preceder, int eval_predecessors, float analogDigitalTransitionStart) int ClassFlowCNNGeneral::PointerEvalAnalogToDigitNew(float number, float numeral_preceder, int eval_predecessors, float analogDigitalTransitionStart) {
{
int result; int result;
int result_after_decimal_point = ((int) floor(number * 10)) % 10; int result_after_decimal_point = ((int) floor(number * 10)) % 10;
int result_before_decimal_point = ((int) floor(number) + 10) % 10; int result_before_decimal_point = ((int) floor(number) + 10) % 10;
@@ -253,21 +264,17 @@ int ClassFlowCNNGeneral::PointerEvalAnalogToDigitNew(float number, float numeral
" number: " + std::to_string(number) + " number: " + std::to_string(number) +
" numeral_preceder = " + std::to_string(numeral_preceder) + " numeral_preceder = " + std::to_string(numeral_preceder) +
" eerg after comma = " + std::to_string(result_after_decimal_point)); " eerg after comma = " + std::to_string(result_after_decimal_point));
} }
return result; return result;
} }
int ClassFlowCNNGeneral::PointerEvalAnalogNew(float number, int numeral_preceder) int ClassFlowCNNGeneral::PointerEvalAnalogNew(float number, int numeral_preceder) {
{
float number_min, number_max; float number_min, number_max;
int result; int result;
if (numeral_preceder == -1) if (numeral_preceder == -1) {
{
result = (int) floor(number); result = (int) floor(number);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - No predecessor - Result = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - No predecessor - Result = " + std::to_string(result) +
" number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error)); " number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error));
@@ -277,17 +284,14 @@ int ClassFlowCNNGeneral::PointerEvalAnalogNew(float number, int numeral_preceder
number_min = number - Analog_error / 10.0; number_min = number - Analog_error / 10.0;
number_max = number + Analog_error / 10.0; number_max = number + Analog_error / 10.0;
if ((int) floor(number_max) - (int) floor(number_min) != 0) if ((int) floor(number_max) - (int) floor(number_min) != 0) {
{ if (numeral_preceder <= Analog_error) {
if (numeral_preceder <= Analog_error)
{
result = ((int) floor(number_max) + 10) % 10; result = ((int) floor(number_max) + 10) % 10;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - number ambiguous, correction upwards - result = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - number ambiguous, correction upwards - result = " + std::to_string(result) +
" number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error)); " number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error));
return result; return result;
} }
if (numeral_preceder >= 10 - Analog_error) if (numeral_preceder >= 10 - Analog_error) {
{
result = ((int) floor(number_min) + 10) % 10; result = ((int) floor(number_min) + 10) % 10;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - number ambiguous, downward correction - result = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - number ambiguous, downward correction - result = " + std::to_string(result) +
" number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error)); " number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error));
@@ -295,7 +299,6 @@ int ClassFlowCNNGeneral::PointerEvalAnalogNew(float number, int numeral_preceder
} }
} }
result = ((int) floor(number) + 10) % 10; result = ((int) floor(number) + 10) % 10;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - number unambiguous, no correction necessary - result = " + std::to_string(result) + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalAnalogNew - number unambiguous, no correction necessary - result = " + std::to_string(result) +
" number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error)); " number: " + std::to_string(number) + " numeral_preceder = " + std::to_string(numeral_preceder) + " Analog_error = " + std::to_string(Analog_error));
@@ -304,25 +307,25 @@ int ClassFlowCNNGeneral::PointerEvalAnalogNew(float number, int numeral_preceder
} }
bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph) bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph) {
{
std::vector<string> splitted; std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph); aktparamgraph = trim(aktparamgraph);
if (aktparamgraph.size() == 0) if (aktparamgraph.size() == 0) {
if (!this->GetNextParagraph(pfile, aktparamgraph)) if (!this->GetNextParagraph(pfile, aktparamgraph)) {
return false; return false;
}
}
if ((toUpper(aktparamgraph) != "[ANALOG]") && (toUpper(aktparamgraph) != ";[ANALOG]") if ((toUpper(aktparamgraph) != "[ANALOG]") && (toUpper(aktparamgraph) != ";[ANALOG]")
&& (toUpper(aktparamgraph) != "[DIGIT]") && (toUpper(aktparamgraph) != ";[DIGIT]") && (toUpper(aktparamgraph) != "[DIGIT]") && (toUpper(aktparamgraph) != ";[DIGIT]")
&& (toUpper(aktparamgraph) != "[DIGITS]") && (toUpper(aktparamgraph) != ";[DIGITS]") && (toUpper(aktparamgraph) != "[DIGITS]") && (toUpper(aktparamgraph) != ";[DIGITS]")) {
) // Paragraph passt nicht // Paragraph passt nicht
return false; return false;
}
if (aktparamgraph[0] == ';') if (aktparamgraph[0] == ';') {
{
disabled = true; disabled = true;
while (getNextLine(pfile, &aktparamgraph) && !isNewParagraph(aktparamgraph)); while (getNextLine(pfile, &aktparamgraph) && !isNewParagraph(aktparamgraph));
ESP_LOGD(TAG, "[Analog/Digit] is disabled!"); ESP_LOGD(TAG, "[Analog/Digit] is disabled!");
@@ -330,36 +333,31 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
} }
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) {
{
splitted = ZerlegeZeile(aktparamgraph); splitted = ZerlegeZeile(aktparamgraph);
if ((toUpper(splitted[0]) == "ROIIMAGESLOCATION") && (splitted.size() > 1)) if ((toUpper(splitted[0]) == "ROIIMAGESLOCATION") && (splitted.size() > 1)) {
{
this->imagesLocation = "/sdcard" + splitted[1]; this->imagesLocation = "/sdcard" + splitted[1];
this->isLogImage = true; this->isLogImage = true;
} }
if ((toUpper(splitted[0]) == "LOGIMAGESELECT") && (splitted.size() > 1))
{ if ((toUpper(splitted[0]) == "LOGIMAGESELECT") && (splitted.size() > 1)) {
LogImageSelect = splitted[1]; LogImageSelect = splitted[1];
isLogImageSelect = true; isLogImageSelect = true;
} }
if ((toUpper(splitted[0]) == "ROIIMAGESRETENTION") && (splitted.size() > 1)) if ((toUpper(splitted[0]) == "ROIIMAGESRETENTION") && (splitted.size() > 1)) {
{
this->imagesRetention = std::stoi(splitted[1]); this->imagesRetention = std::stoi(splitted[1]);
} }
if ((toUpper(splitted[0]) == "MODEL") && (splitted.size() > 1)) if ((toUpper(splitted[0]) == "MODEL") && (splitted.size() > 1)) {
{
this->cnnmodelfile = splitted[1]; this->cnnmodelfile = splitted[1];
} }
if ((toUpper(splitted[0]) == "CNNGOODTHRESHOLD") && (splitted.size() > 1)) if ((toUpper(splitted[0]) == "CNNGOODTHRESHOLD") && (splitted.size() > 1)) {
{
CNNGoodThreshold = std::stof(splitted[1]); CNNGoodThreshold = std::stof(splitted[1]);
} }
if (splitted.size() >= 5)
{ if (splitted.size() >= 5) {
general* _analog = GetGENERAL(splitted[0], true); general* _analog = GetGENERAL(splitted[0], true);
roi* neuroi = _analog->ROI[_analog->ROI.size()-1]; roi* neuroi = _analog->ROI[_analog->ROI.size()-1];
neuroi->posx = std::stoi(splitted[1]); neuroi->posx = std::stoi(splitted[1]);
@@ -367,19 +365,20 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
neuroi->deltax = std::stoi(splitted[3]); neuroi->deltax = std::stoi(splitted[3]);
neuroi->deltay = std::stoi(splitted[4]); neuroi->deltay = std::stoi(splitted[4]);
neuroi->CCW = false; neuroi->CCW = false;
if (splitted.size() >= 6)
{ if (splitted.size() >= 6) {
neuroi->CCW = toUpper(splitted[5]) == "TRUE"; neuroi->CCW = toUpper(splitted[5]) == "TRUE";
} }
neuroi->result_float = -1; neuroi->result_float = -1;
neuroi->image = NULL; neuroi->image = NULL;
neuroi->image_org = NULL; neuroi->image_org = NULL;
} }
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) {
{ if (toUpper(splitted[1]) == "TRUE") {
if (toUpper(splitted[1]) == "TRUE")
SaveAllFiles = true; SaveAllFiles = true;
}
} }
} }
@@ -390,55 +389,57 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
} }
for (int _ana = 0; _ana < GENERAL.size(); ++_ana) for (int _ana = 0; _ana < GENERAL.size(); ++_ana) {
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) {
{
GENERAL[_ana]->ROI[i]->image = new CImageBasis("ROI " + GENERAL[_ana]->ROI[i]->name, GENERAL[_ana]->ROI[i]->image = new CImageBasis("ROI " + GENERAL[_ana]->ROI[i]->name,
modelxsize, modelysize, modelchannel); modelxsize, modelysize, modelchannel);
GENERAL[_ana]->ROI[i]->image_org = new CImageBasis("ROI " + GENERAL[_ana]->ROI[i]->name + " original", GENERAL[_ana]->ROI[i]->image_org = new CImageBasis("ROI " + GENERAL[_ana]->ROI[i]->name + " original",
GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, 3); GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, 3);
} }
}
return true; return true;
} }
general* ClassFlowCNNGeneral::FindGENERAL(string _name_number) general* ClassFlowCNNGeneral::FindGENERAL(string _name_number) {
{ for (int i = 0; i < GENERAL.size(); ++i) {
for (int i = 0; i < GENERAL.size(); ++i) if (GENERAL[i]->name == _name_number) {
if (GENERAL[i]->name == _name_number)
return GENERAL[i]; return GENERAL[i];
}
}
return NULL; return NULL;
} }
general* ClassFlowCNNGeneral::GetGENERAL(string _name, bool _create = true) general* ClassFlowCNNGeneral::GetGENERAL(string _name, bool _create = true) {
{
string _analog, _roi; string _analog, _roi;
int _pospunkt = _name.find_first_of("."); int _pospunkt = _name.find_first_of(".");
if (_pospunkt > -1) if (_pospunkt > -1) {
{
_analog = _name.substr(0, _pospunkt); _analog = _name.substr(0, _pospunkt);
_roi = _name.substr(_pospunkt+1, _name.length() - _pospunkt - 1); _roi = _name.substr(_pospunkt+1, _name.length() - _pospunkt - 1);
} }
else else {
{
_analog = "default"; _analog = "default";
_roi = _name; _roi = _name;
} }
general *_ret = NULL; general *_ret = NULL;
for (int i = 0; i < GENERAL.size(); ++i) for (int i = 0; i < GENERAL.size(); ++i) {
if (GENERAL[i]->name == _analog) if (GENERAL[i]->name == _analog) {
_ret = GENERAL[i]; _ret = GENERAL[i];
}
}
if (!_create) // not found and should not be created // not found and should not be created
if (!_create) {
return _ret; return _ret;
}
if (_ret == NULL) if (_ret == NULL) {
{
_ret = new general; _ret = new general;
_ret->name = _analog; _ret->name = _analog;
GENERAL.push_back(_ret); GENERAL.push_back(_ret);
@@ -455,8 +456,7 @@ general* ClassFlowCNNGeneral::GetGENERAL(string _name, bool _create = true)
} }
string ClassFlowCNNGeneral::getHTMLSingleStep(string host) string ClassFlowCNNGeneral::getHTMLSingleStep(string host) {
{
string result, zw; string result, zw;
std::vector<HTMLInfo*> htmlinfo; std::vector<HTMLInfo*> htmlinfo;
@@ -464,8 +464,8 @@ string ClassFlowCNNGeneral::getHTMLSingleStep(string host)
result = result + "Analog Pointers: <p> "; result = result + "Analog Pointers: <p> ";
htmlinfo = GetHTMLInfo(); htmlinfo = GetHTMLInfo();
for (int i = 0; i < htmlinfo.size(); ++i)
{ for (int i = 0; i < htmlinfo.size(); ++i) {
std::stringstream stream; std::stringstream stream;
stream << std::fixed << std::setprecision(1) << htmlinfo[i]->val; stream << std::fixed << std::setprecision(1) << htmlinfo[i]->val;
zw = stream.str(); zw = stream.str();
@@ -473,15 +473,14 @@ string ClassFlowCNNGeneral::getHTMLSingleStep(string host)
result = result + "<img src=\"" + host + "/img_tmp/" + htmlinfo[i]->filename + "\"> " + zw; result = result + "<img src=\"" + host + "/img_tmp/" + htmlinfo[i]->filename + "\"> " + zw;
delete htmlinfo[i]; delete htmlinfo[i];
} }
htmlinfo.clear(); htmlinfo.clear();
return result; return result;
} }
bool ClassFlowCNNGeneral::doFlow(string time) bool ClassFlowCNNGeneral::doFlow(string time) {
{
#ifdef HEAP_TRACING_CLASS_FLOW_CNN_GENERAL_DO_ALING_AND_CUT #ifdef HEAP_TRACING_CLASS_FLOW_CNN_GENERAL_DO_ALING_AND_CUT
//register a buffer to record the memory trace //register a buffer to record the memory trace
ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) ); ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) );
@@ -489,8 +488,9 @@ bool ClassFlowCNNGeneral::doFlow(string time)
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
#endif #endif
if (disabled) if (disabled) {
return true; return true;
}
if (!doAlignAndCut(time)){ if (!doAlignAndCut(time)){
return false; return false;
@@ -511,79 +511,80 @@ bool ClassFlowCNNGeneral::doFlow(string time)
} }
bool ClassFlowCNNGeneral::doAlignAndCut(string time) bool ClassFlowCNNGeneral::doAlignAndCut(string time) {
{ if (disabled) {
if (disabled)
return true; return true;
}
CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage(); CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage();
for (int _ana = 0; _ana < GENERAL.size(); ++_ana) for (int _ana = 0; _ana < GENERAL.size(); ++_ana) {
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) {
{
ESP_LOGD(TAG, "General %d - Align&Cut", i); ESP_LOGD(TAG, "General %d - Align&Cut", i);
caic->CutAndSave(GENERAL[_ana]->ROI[i]->posx, GENERAL[_ana]->ROI[i]->posy, GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, GENERAL[_ana]->ROI[i]->image_org); caic->CutAndSave(GENERAL[_ana]->ROI[i]->posx, GENERAL[_ana]->ROI[i]->posy, GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, GENERAL[_ana]->ROI[i]->image_org);
if (SaveAllFiles) if (SaveAllFiles) {
{ if (GENERAL[_ana]->name == "default") {
if (GENERAL[_ana]->name == "default")
GENERAL[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".jpg")); GENERAL[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".jpg"));
else }
else {
GENERAL[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg")); GENERAL[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg"));
}
} }
GENERAL[_ana]->ROI[i]->image_org->Resize(modelxsize, modelysize, GENERAL[_ana]->ROI[i]->image); GENERAL[_ana]->ROI[i]->image_org->Resize(modelxsize, modelysize, GENERAL[_ana]->ROI[i]->image);
if (SaveAllFiles) if (SaveAllFiles) {
{ if (GENERAL[_ana]->name == "default") {
if (GENERAL[_ana]->name == "default")
GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".jpg")); GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".jpg"));
else }
else {
GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg")); GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg"));
}
} }
} }
}
return true; return true;
} }
void ClassFlowCNNGeneral::DrawROI(CImageBasis *_zw) void ClassFlowCNNGeneral::DrawROI(CImageBasis *_zw) {
{ if (_zw->ImageOkay()) {
if (_zw->ImageOkay()) if (CNNType == Analogue || CNNType == Analogue100) {
{
if (CNNType == Analogue || CNNType == Analogue100)
{
int r = 0; int r = 0;
int g = 255; int g = 255;
int b = 0; int b = 0;
for (int _ana = 0; _ana < GENERAL.size(); ++_ana) for (int _ana = 0; _ana < GENERAL.size(); ++_ana) {
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) {
{
_zw->drawRect(GENERAL[_ana]->ROI[i]->posx, GENERAL[_ana]->ROI[i]->posy, GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, r, g, b, 1); _zw->drawRect(GENERAL[_ana]->ROI[i]->posx, GENERAL[_ana]->ROI[i]->posy, GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, r, g, b, 1);
_zw->drawEllipse( (int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) (GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->deltay/2), r, g, b, 2); _zw->drawEllipse( (int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) (GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->deltay/2), r, g, b, 2);
_zw->drawLine((int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) GENERAL[_ana]->ROI[i]->posy, (int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay), r, g, b, 2); _zw->drawLine((int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) GENERAL[_ana]->ROI[i]->posy, (int) (GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax/2), (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay), r, g, b, 2);
_zw->drawLine((int) GENERAL[_ana]->ROI[i]->posx, (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax, (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), r, g, b, 2); _zw->drawLine((int) GENERAL[_ana]->ROI[i]->posx, (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), (int) GENERAL[_ana]->ROI[i]->posx + GENERAL[_ana]->ROI[i]->deltax, (int) (GENERAL[_ana]->ROI[i]->posy + GENERAL[_ana]->ROI[i]->deltay/2), r, g, b, 2);
} }
}
} }
else else {
{ for (int _dig = 0; _dig < GENERAL.size(); ++_dig) {
for (int _dig = 0; _dig < GENERAL.size(); ++_dig) for (int i = 0; i < GENERAL[_dig]->ROI.size(); ++i) {
for (int i = 0; i < GENERAL[_dig]->ROI.size(); ++i)
_zw->drawRect(GENERAL[_dig]->ROI[i]->posx, GENERAL[_dig]->ROI[i]->posy, GENERAL[_dig]->ROI[i]->deltax, GENERAL[_dig]->ROI[i]->deltay, 0, 0, (255 - _dig*100), 2); _zw->drawRect(GENERAL[_dig]->ROI[i]->posx, GENERAL[_dig]->ROI[i]->posy, GENERAL[_dig]->ROI[i]->deltax, GENERAL[_dig]->ROI[i]->deltay, 0, 0, (255 - _dig*100), 2);
}
}
} }
} }
} }
bool ClassFlowCNNGeneral::getNetworkParameter() bool ClassFlowCNNGeneral::getNetworkParameter() {
{ if (disabled) {
if (disabled)
return true; return true;
}
CTfLiteClass *tflite = new CTfLiteClass; CTfLiteClass *tflite = new CTfLiteClass;
string zwcnn = "/sdcard" + cnnmodelfile; string zwcnn = "/sdcard" + cnnmodelfile;
zwcnn = FormatFileName(zwcnn); zwcnn = FormatFileName(zwcnn);
ESP_LOGD(TAG, "%s", zwcnn.c_str()); ESP_LOGD(TAG, "%s", zwcnn.c_str());
if (!tflite->LoadModel(zwcnn)) { if (!tflite->LoadModel(zwcnn)) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't load tflite model " + cnnmodelfile + " -> Init aborted!"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't load tflite model " + cnnmodelfile + " -> Init aborted!");
LogFile.WriteHeapInfo("getNetworkParameter-LoadModel"); LogFile.WriteHeapInfo("getNetworkParameter-LoadModel");
@@ -598,16 +599,14 @@ bool ClassFlowCNNGeneral::getNetworkParameter()
return false; return false;
} }
if (CNNType == AutoDetect) if (CNNType == AutoDetect) {
{
tflite->GetInputDimension(false); tflite->GetInputDimension(false);
modelxsize = tflite->ReadInputDimenstion(0); modelxsize = tflite->ReadInputDimenstion(0);
modelysize = tflite->ReadInputDimenstion(1); modelysize = tflite->ReadInputDimenstion(1);
modelchannel = tflite->ReadInputDimenstion(2); modelchannel = tflite->ReadInputDimenstion(2);
int _anzoutputdimensions = tflite->GetAnzOutPut(); int _anzoutputdimensions = tflite->GetAnzOutPut();
switch (_anzoutputdimensions) switch (_anzoutputdimensions) {
{
case 2: case 2:
CNNType = Analogue; CNNType = Analogue;
ESP_LOGD(TAG, "TFlite-Type set to Analogue"); ESP_LOGD(TAG, "TFlite-Type set to Analogue");
@@ -633,7 +632,8 @@ bool ClassFlowCNNGeneral::getNetworkParameter()
if (modelxsize==32 && modelysize == 32) { if (modelxsize==32 && modelysize == 32) {
CNNType = Analogue100; CNNType = Analogue100;
ESP_LOGD(TAG, "TFlite-Type set to Analogue100"); ESP_LOGD(TAG, "TFlite-Type set to Analogue100");
} else { }
else {
CNNType = Digital100; CNNType = Digital100;
ESP_LOGD(TAG, "TFlite-Type set to Digital"); ESP_LOGD(TAG, "TFlite-Type set to Digital");
} }
@@ -648,10 +648,10 @@ bool ClassFlowCNNGeneral::getNetworkParameter()
} }
bool ClassFlowCNNGeneral::doNeuralNetwork(string time) bool ClassFlowCNNGeneral::doNeuralNetwork(string time) {
{ if (disabled) {
if (disabled)
return true; return true;
}
string logPath = CreateLogFolder(time); string logPath = CreateLogFolder(time);
@@ -674,11 +674,11 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
return false; return false;
} }
for (int n = 0; n < GENERAL.size(); ++n) // For each NUMBER // For each NUMBER
{ for (int n = 0; n < GENERAL.size(); ++n) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Processing Number '" + GENERAL[n]->name + "'"); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Processing Number '" + GENERAL[n]->name + "'");
for (int roi = 0; roi < GENERAL[n]->ROI.size(); ++roi) // For each ROI // For each ROI
{ for (int roi = 0; roi < GENERAL[n]->ROI.size(); ++roi) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ROI #" + std::to_string(roi) + " - TfLite"); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "ROI #" + std::to_string(roi) + " - TfLite");
//ESP_LOGD(TAG, "General %d - TfLite", i); //ESP_LOGD(TAG, "General %d - TfLite", i);
@@ -697,14 +697,17 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
f2 = tflite->GetOutputValue(1); f2 = tflite->GetOutputValue(1);
float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1); float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1);
if(GENERAL[n]->ROI[roi]->CCW) if(GENERAL[n]->ROI[roi]->CCW) {
GENERAL[n]->ROI[roi]->result_float = 10 - (result * 10); GENERAL[n]->ROI[roi]->result_float = 10 - (result * 10);
else }
else {
GENERAL[n]->ROI[roi]->result_float = result * 10; GENERAL[n]->ROI[roi]->result_float = result * 10;
}
ESP_LOGD(TAG, "General result (Analog)%i - CCW: %d - %f", roi, GENERAL[n]->ROI[roi]->CCW, GENERAL[n]->ROI[roi]->result_float); ESP_LOGD(TAG, "General result (Analog)%i - CCW: %d - %f", roi, GENERAL[n]->ROI[roi]->CCW, GENERAL[n]->ROI[roi]->result_float);
if (isLogImage) if (isLogImage) {
LogImage(logPath, GENERAL[n]->ROI[roi]->name, &GENERAL[n]->ROI[roi]->result_float, NULL, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, GENERAL[n]->ROI[roi]->name, &GENERAL[n]->ROI[roi]->result_float, NULL, time, GENERAL[n]->ROI[roi]->image_org);
}
} break; } break;
case Digital: case Digital:
@@ -714,22 +717,19 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
GENERAL[n]->ROI[roi]->result_klasse = tflite->GetClassFromImageBasis(GENERAL[n]->ROI[roi]->image); GENERAL[n]->ROI[roi]->result_klasse = tflite->GetClassFromImageBasis(GENERAL[n]->ROI[roi]->image);
ESP_LOGD(TAG, "General result (Digit)%i: %d", roi, GENERAL[n]->ROI[roi]->result_klasse); ESP_LOGD(TAG, "General result (Digit)%i: %d", roi, GENERAL[n]->ROI[roi]->result_klasse);
if (isLogImage) if (isLogImage) {
{
string _imagename = GENERAL[n]->name + "_" + GENERAL[n]->ROI[roi]->name; string _imagename = GENERAL[n]->name + "_" + GENERAL[n]->ROI[roi]->name;
if (isLogImageSelect) if (isLogImageSelect) {
{ if (LogImageSelect.find(GENERAL[n]->ROI[roi]->name) != std::string::npos) {
if (LogImageSelect.find(GENERAL[n]->ROI[roi]->name) != std::string::npos)
LogImage(logPath, _imagename, NULL, &GENERAL[n]->ROI[roi]->result_klasse, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, _imagename, NULL, &GENERAL[n]->ROI[roi]->result_klasse, time, GENERAL[n]->ROI[roi]->image_org);
}
} }
else else {
{
LogImage(logPath, _imagename, NULL, &GENERAL[n]->ROI[roi]->result_klasse, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, _imagename, NULL, &GENERAL[n]->ROI[roi]->result_klasse, time, GENERAL[n]->ROI[roi]->image_org);
} }
} }
} break; } break;
case DoubleHyprid10: case DoubleHyprid10:
{ {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CNN Type: DoubleHyprid10"); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CNN Type: DoubleHyprid10");
@@ -752,62 +752,56 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
float result = _num; float result = _num;
if (_valplus > _valminus) if (_valplus > _valminus) {
{
result = result + _valplus / (_valplus + _val); result = result + _valplus / (_valplus + _val);
_fit = _val + _valplus; _fit = _val + _valplus;
} }
else else {
{
result = result - _valminus / (_val + _valminus); result = result - _valminus / (_val + _valminus);
_fit = _val + _valminus; _fit = _val + _valminus;
} }
if (result >= 10)
if (result >= 10) {
result = result - 10; result = result - 10;
if (result < 0) }
if (result < 0) {
result = result + 10; result = result + 10;
}
string zw = "_num (p, m): " + to_string(_num) + " " + to_string(_numplus) + " " + to_string(_numminus); string zw = "_num (p, m): " + to_string(_num) + " " + to_string(_numplus) + " " + to_string(_numminus);
zw = zw + " _val (p, m): " + to_string(_val) + " " + to_string(_valplus) + " " + to_string(_valminus); zw = zw + " _val (p, m): " + to_string(_val) + " " + to_string(_valplus) + " " + to_string(_valminus);
zw = zw + " result: " + to_string(result) + " _fit: " + to_string(_fit); zw = zw + " result: " + to_string(result) + " _fit: " + to_string(_fit);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw);
_result_save_file = result; _result_save_file = result;
if (_fit < CNNGoodThreshold) if (_fit < CNNGoodThreshold) {
{
GENERAL[n]->ROI[roi]->isReject = true; GENERAL[n]->ROI[roi]->isReject = true;
result = -1; result = -1;
_result_save_file+= 100; // In case fit is not sufficient, the result should still be saved with "-10x.y". _result_save_file+= 100; // In case fit is not sufficient, the result should still be saved with "-10x.y".
string zw = "Value Rejected due to Threshold (Fit: " + to_string(_fit) + ", Threshold: " + to_string(CNNGoodThreshold) + ")"; string zw = "Value Rejected due to Threshold (Fit: " + to_string(_fit) + ", Threshold: " + to_string(CNNGoodThreshold) + ")";
LogFile.WriteToFile(ESP_LOG_WARN, TAG, zw); LogFile.WriteToFile(ESP_LOG_WARN, TAG, zw);
} }
else else {
{
GENERAL[n]->ROI[roi]->isReject = false; GENERAL[n]->ROI[roi]->isReject = false;
} }
GENERAL[n]->ROI[roi]->result_float = result; GENERAL[n]->ROI[roi]->result_float = result;
ESP_LOGD(TAG, "Result General(Analog)%i: %f", roi, GENERAL[n]->ROI[roi]->result_float); ESP_LOGD(TAG, "Result General(Analog)%i: %f", roi, GENERAL[n]->ROI[roi]->result_float);
if (isLogImage) if (isLogImage) {
{
string _imagename = GENERAL[n]->name + "_" + GENERAL[n]->ROI[roi]->name; string _imagename = GENERAL[n]->name + "_" + GENERAL[n]->ROI[roi]->name;
if (isLogImageSelect) if (isLogImageSelect) {
{ if (LogImageSelect.find(GENERAL[n]->ROI[roi]->name) != std::string::npos) {
if (LogImageSelect.find(GENERAL[n]->ROI[roi]->name) != std::string::npos)
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org);
}
} }
else else {
{
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org);
} }
} }
} } break;
break;
case Digital100: case Digital100:
case Analogue100: case Analogue100:
{ {
@@ -820,28 +814,27 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
_num = tflite->GetOutClassification(); _num = tflite->GetOutClassification();
if(GENERAL[n]->ROI[roi]->CCW) if(GENERAL[n]->ROI[roi]->CCW) {
GENERAL[n]->ROI[roi]->result_float = 10 - ((float)_num / 10.0); GENERAL[n]->ROI[roi]->result_float = 10 - ((float)_num / 10.0);
else }
else {
GENERAL[n]->ROI[roi]->result_float = (float)_num / 10.0; GENERAL[n]->ROI[roi]->result_float = (float)_num / 10.0;
}
_result_save_file = GENERAL[n]->ROI[roi]->result_float; _result_save_file = GENERAL[n]->ROI[roi]->result_float;
GENERAL[n]->ROI[roi]->isReject = false; GENERAL[n]->ROI[roi]->isReject = false;
ESP_LOGD(TAG, "Result General(Analog)%i - CCW: %d - %f", roi, GENERAL[n]->ROI[roi]->CCW, GENERAL[n]->ROI[roi]->result_float); ESP_LOGD(TAG, "Result General(Analog)%i - CCW: %d - %f", roi, GENERAL[n]->ROI[roi]->CCW, GENERAL[n]->ROI[roi]->result_float);
if (isLogImage) if (isLogImage) {
{
string _imagename = GENERAL[n]->name + "_" + GENERAL[n]->ROI[roi]->name; string _imagename = GENERAL[n]->name + "_" + GENERAL[n]->ROI[roi]->name;
if (isLogImageSelect) if (isLogImageSelect) {
{ if (LogImageSelect.find(GENERAL[n]->ROI[roi]->name) != std::string::npos) {
if (LogImageSelect.find(GENERAL[n]->ROI[roi]->name) != std::string::npos)
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org);
}
} }
else else {
{
LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org); LogImage(logPath, _imagename, &_result_save_file, NULL, time, GENERAL[n]->ROI[roi]->image_org);
} }
} }
@@ -860,93 +853,94 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
} }
bool ClassFlowCNNGeneral::isExtendedResolution(int _number) bool ClassFlowCNNGeneral::isExtendedResolution(int _number) {
{ if (CNNType == Digital) {
if (CNNType == Digital)
return false; return false;
}
return true; return true;
} }
std::vector<HTMLInfo*> ClassFlowCNNGeneral::GetHTMLInfo() std::vector<HTMLInfo*> ClassFlowCNNGeneral::GetHTMLInfo() {
{
std::vector<HTMLInfo*> result; std::vector<HTMLInfo*> result;
for (int _ana = 0; _ana < GENERAL.size(); ++_ana) for (int _ana = 0; _ana < GENERAL.size(); ++_ana) {
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i) {
{
ESP_LOGD(TAG, "Image: %d", (int) GENERAL[_ana]->ROI[i]->image); ESP_LOGD(TAG, "Image: %d", (int) GENERAL[_ana]->ROI[i]->image);
if (GENERAL[_ana]->ROI[i]->image) if (GENERAL[_ana]->ROI[i]->image) {
{ if (GENERAL[_ana]->name == "default") {
if (GENERAL[_ana]->name == "default")
GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".jpg")); GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->ROI[i]->name + ".jpg"));
else }
else {
GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg")); GENERAL[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg"));
}
} }
HTMLInfo *zw = new HTMLInfo; HTMLInfo *zw = new HTMLInfo;
if (GENERAL[_ana]->name == "default") if (GENERAL[_ana]->name == "default") {
{
zw->filename = GENERAL[_ana]->ROI[i]->name + ".jpg"; zw->filename = GENERAL[_ana]->ROI[i]->name + ".jpg";
zw->filename_org = GENERAL[_ana]->ROI[i]->name + ".jpg"; zw->filename_org = GENERAL[_ana]->ROI[i]->name + ".jpg";
} }
else else {
{
zw->filename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg"; zw->filename = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg";
zw->filename_org = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg"; zw->filename_org = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg";
} }
if (CNNType == Digital) if (CNNType == Digital) {
zw->val = GENERAL[_ana]->ROI[i]->result_klasse; zw->val = GENERAL[_ana]->ROI[i]->result_klasse;
else }
else {
zw->val = GENERAL[_ana]->ROI[i]->result_float; zw->val = GENERAL[_ana]->ROI[i]->result_float;
}
zw->image = GENERAL[_ana]->ROI[i]->image; zw->image = GENERAL[_ana]->ROI[i]->image;
zw->image_org = GENERAL[_ana]->ROI[i]->image_org; zw->image_org = GENERAL[_ana]->ROI[i]->image_org;
result.push_back(zw); result.push_back(zw);
} }
}
return result; return result;
} }
int ClassFlowCNNGeneral::getNumberGENERAL() int ClassFlowCNNGeneral::getNumberGENERAL() {
{
return GENERAL.size(); return GENERAL.size();
} }
string ClassFlowCNNGeneral::getNameGENERAL(int _analog) string ClassFlowCNNGeneral::getNameGENERAL(int _analog) {
{ if (_analog < GENERAL.size()) {
if (_analog < GENERAL.size())
return GENERAL[_analog]->name; return GENERAL[_analog]->name;
}
return "GENERAL DOES NOT EXIST"; return "GENERAL DOES NOT EXIST";
} }
general* ClassFlowCNNGeneral::GetGENERAL(int _analog) general* ClassFlowCNNGeneral::GetGENERAL(int _analog) {
{ if (_analog < GENERAL.size()) {
if (_analog < GENERAL.size())
return GENERAL[_analog]; return GENERAL[_analog];
}
return NULL; return NULL;
} }
void ClassFlowCNNGeneral::UpdateNameNumbers(std::vector<std::string> *_name_numbers) void ClassFlowCNNGeneral::UpdateNameNumbers(std::vector<std::string> *_name_numbers) {
{ for (int _dig = 0; _dig < GENERAL.size(); _dig++) {
for (int _dig = 0; _dig < GENERAL.size(); _dig++)
{
std::string _name = GENERAL[_dig]->name; std::string _name = GENERAL[_dig]->name;
bool found = false; bool found = false;
for (int i = 0; i < (*_name_numbers).size(); ++i)
{ for (int i = 0; i < (*_name_numbers).size(); ++i) {
if ((*_name_numbers)[i] == _name) if ((*_name_numbers)[i] == _name) {
found = true; found = true;
}
} }
if (!found) if (!found) {
(*_name_numbers).push_back(_name); (*_name_numbers).push_back(_name);
}
} }
} }
@@ -955,26 +949,25 @@ string ClassFlowCNNGeneral::getReadoutRawString(int _analog)
{ {
string rt = ""; string rt = "";
if (_analog >= GENERAL.size() || GENERAL[_analog]==NULL || GENERAL[_analog]->ROI.size() == 0) if (_analog >= GENERAL.size() || GENERAL[_analog]==NULL || GENERAL[_analog]->ROI.size() == 0) {
return rt; return rt;
}
for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i) for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i) {
{ if (CNNType == Analogue || CNNType == Analogue100) {
if (CNNType == Analogue || CNNType == Analogue100)
{
rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1); rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1);
} }
if (CNNType == Digital) if (CNNType == Digital) {
{ if (GENERAL[_analog]->ROI[i]->result_klasse >= 10) {
if (GENERAL[_analog]->ROI[i]->result_klasse == 10)
rt = rt + ",N"; rt = rt + ",N";
else }
else {
rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_klasse, 0); rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_klasse, 0);
}
} }
if ((CNNType == DoubleHyprid10) || (CNNType == Digital100)) if ((CNNType == DoubleHyprid10) || (CNNType == Digital100)) {
{
rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1); rt = rt + "," + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1);
} }
} }

View File

@@ -34,6 +34,7 @@ struct NumberPost {
bool AllowNegativeRates; bool AllowNegativeRates;
bool checkDigitIncreaseConsistency; bool checkDigitIncreaseConsistency;
time_t lastvalue; time_t lastvalue;
time_t timeStampTimeUTC;
string timeStamp; string timeStamp;
double FlowRateAct; // m3 / min double FlowRateAct; // m3 / min
double PreValue; // last value that was read out well double PreValue; // last value that was read out well

View File

@@ -137,6 +137,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
std::string resultraw = ""; std::string resultraw = "";
std::string resultrate = ""; std::string resultrate = "";
std::string resulttimestamp = ""; std::string resulttimestamp = "";
long int timeutc;
string zw = ""; string zw = "";
string namenumber = ""; string namenumber = "";
@@ -152,6 +153,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
resulterror = (*NUMBERS)[i]->ErrorMessageText; resulterror = (*NUMBERS)[i]->ErrorMessageText;
resultrate = (*NUMBERS)[i]->ReturnRateValue; resultrate = (*NUMBERS)[i]->ReturnRateValue;
resulttimestamp = (*NUMBERS)[i]->timeStamp; resulttimestamp = (*NUMBERS)[i]->timeStamp;
timeutc = (*NUMBERS)[i]->timeStampTimeUTC;
if ((*NUMBERS)[i]->FieldV1.length() > 0) if ((*NUMBERS)[i]->FieldV1.length() > 0)
{ {
@@ -167,7 +169,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
} }
if (result.length() > 0) if (result.length() > 0)
InfluxDBPublish(measurement, namenumber, result, resulttimestamp); InfluxDBPublish(measurement, namenumber, result, timeutc);
} }
} }

View File

@@ -196,6 +196,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
std::string resultraw = ""; std::string resultraw = "";
std::string resultrate = ""; std::string resultrate = "";
std::string resulttimestamp = ""; std::string resulttimestamp = "";
long int resulttimeutc = 0;
string zw = ""; string zw = "";
string namenumber = ""; string namenumber = "";
@@ -212,6 +213,8 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
resulterror = (*NUMBERS)[i]->ErrorMessageText; resulterror = (*NUMBERS)[i]->ErrorMessageText;
resultrate = (*NUMBERS)[i]->ReturnRateValue; resultrate = (*NUMBERS)[i]->ReturnRateValue;
resulttimestamp = (*NUMBERS)[i]->timeStamp; resulttimestamp = (*NUMBERS)[i]->timeStamp;
resulttimeutc = (*NUMBERS)[i]->timeStampTimeUTC;
if ((*NUMBERS)[i]->FieldV2.length() > 0) if ((*NUMBERS)[i]->FieldV2.length() > 0)
{ {
@@ -229,8 +232,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str()); printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
if (result.length() > 0) if (result.length() > 0)
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimestamp); InfluxDB_V2_Publish(measurement, namenumber, result, resulttimeutc);
// InfluxDB_V2_Publish(namenumber, result, resulttimestamp);
} }
} }

View File

@@ -1,9 +1,15 @@
#include <iostream>
#include <string>
#include <vector>
#include <regex>
#include "ClassFlowTakeImage.h" #include "ClassFlowTakeImage.h"
#include "Helper.h" #include "Helper.h"
#include "ClassLogFile.h" #include "ClassLogFile.h"
#include "CImageBasis.h" #include "CImageBasis.h"
#include "ClassControllCamera.h" #include "ClassControllCamera.h"
#include "MainFlowControl.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_log.h" #include "esp_log.h"
@@ -12,14 +18,14 @@
#include <time.h> #include <time.h>
// #define DEBUG_DETAIL_ON // #define DEBUG_DETAIL_ON
// #define WIFITURNOFF // #define WIFITURNOFF
static const char* TAG = "TAKEIMAGE"; static const char *TAG = "TAKEIMAGE";
esp_err_t ClassFlowTakeImage::camera_capture(){ esp_err_t ClassFlowTakeImage::camera_capture(void)
string nm = namerawimage; {
string nm = namerawimage;
Camera.CaptureToFile(nm); Camera.CaptureToFile(nm);
time(&TimeImageTaken); time(&TimeImageTaken);
localtime(&TimeImageTaken); localtime(&TimeImageTaken);
@@ -30,150 +36,480 @@ esp_err_t ClassFlowTakeImage::camera_capture(){
void ClassFlowTakeImage::takePictureWithFlash(int flash_duration) void ClassFlowTakeImage::takePictureWithFlash(int flash_duration)
{ {
// in case the image is flipped, it must be reset here // // in case the image is flipped, it must be reset here //
rawImage->width = image_width; rawImage->width = CCstatus.ImageWidth;
rawImage->height = image_height; rawImage->height = CCstatus.ImageHeight;
/////////////////////////////////////////////////////////////////////////////////////
ESP_LOGD(TAG, "flash_duration: %d", flash_duration); ESP_LOGD(TAG, "flash_duration: %d", flash_duration);
Camera.CaptureToBasisImage(rawImage, flash_duration); Camera.CaptureToBasisImage(rawImage, flash_duration);
time(&TimeImageTaken); time(&TimeImageTaken);
localtime(&TimeImageTaken); localtime(&TimeImageTaken);
if (SaveAllFiles) rawImage->SaveToFile(namerawimage); if (CCstatus.SaveAllFiles)
{
rawImage->SaveToFile(namerawimage);
}
} }
void ClassFlowTakeImage::SetInitialParameter(void) void ClassFlowTakeImage::SetInitialParameter(void)
{ {
waitbeforepicture = 5;
isImageSize = false;
ImageQuality = -1;
TimeImageTaken = 0; TimeImageTaken = 0;
ImageQuality = 5;
rawImage = NULL; rawImage = NULL;
ImageSize = FRAMESIZE_VGA;
SaveAllFiles = false;
disabled = false; disabled = false;
FixedExposure = false;
namerawimage = "/sdcard/img_tmp/raw.jpg"; 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
ClassFlowTakeImage::ClassFlowTakeImage(std::vector<ClassFlow*>* lfc) : ClassFlowImage(lfc, TAG) std::vector<string> 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<ClassFlow *> *lfc) : ClassFlowImage(lfc, TAG)
{ {
imagesLocation = "/log/source"; imagesLocation = "/log/source";
imagesRetention = 5; imagesRetention = 5;
SetInitialParameter(); SetInitialParameter();
} }
bool ClassFlowTakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph);
int _brightness = -100;
int _contrast = -100;
int _saturation = -100;
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;
}
if ((toUpper(splitted[0]) == "IMAGEQUALITY") && (splitted.size() > 1))
ImageQuality = std::stod(splitted[1]);
if ((toUpper(splitted[0]) == "IMAGESIZE") && (splitted.size() > 1))
{
ImageSize = Camera.TextToFramesize(splitted[1].c_str());
isImageSize = true;
}
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
SaveAllFiles = true;
}
if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1))
{
waitbeforepicture = stoi(splitted[1]);
}
if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1))
{
this->imagesRetention = std::stoi(splitted[1]);
}
if ((toUpper(splitted[0]) == "BRIGHTNESS") && (splitted.size() > 1))
{
_brightness = stoi(splitted[1]);
}
if ((toUpper(splitted[0]) == "CONTRAST") && (splitted.size() > 1))
{
_contrast = stoi(splitted[1]);
}
if ((toUpper(splitted[0]) == "SATURATION") && (splitted.size() > 1))
{
_saturation = stoi(splitted[1]);
}
if ((toUpper(splitted[0]) == "FIXEDEXPOSURE") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
FixedExposure = true;
}
if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1))
{
float ledintensity = stof(splitted[1]);
ledintensity = min((float) 100, ledintensity);
ledintensity = max((float) 0, ledintensity);
Camera.SetLEDIntensity(ledintensity);
}
if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
Camera.useDemoMode();
}
}
Camera.SetBrightnessContrastSaturation(_brightness, _contrast, _saturation);
Camera.SetQualitySize(ImageQuality, ImageSize);
image_width = Camera.image_width;
image_height = Camera.image_height;
rawImage = new CImageBasis("rawImage");
rawImage->CreateEmptyImage(image_width, image_height, 3);
waitbeforepicture_store = waitbeforepicture;
if (FixedExposure && (waitbeforepicture > 0))
{
// ESP_LOGD(TAG, "Fixed Exposure enabled!");
int flash_duration = (int) (waitbeforepicture * 1000);
Camera.EnableAutoExposure(flash_duration);
waitbeforepicture = 0.2;
// flash_duration = (int) (waitbeforepicture * 1000);
// takePictureWithFlash(flash_duration);
// rawImage->SaveToFile("/sdcard/init2.jpg");
}
return true;
}
string ClassFlowTakeImage::getHTMLSingleStep(string host) string ClassFlowTakeImage::getHTMLSingleStep(string host)
{ {
string result; string result;
@@ -181,74 +517,78 @@ string ClassFlowTakeImage::getHTMLSingleStep(string host)
return result; return result;
} }
// wird bei jeder Auswertrunde aufgerufen
bool ClassFlowTakeImage::doFlow(string zwtime) bool ClassFlowTakeImage::doFlow(string zwtime)
{ {
psram_init_shared_memory_for_take_image_step(); psram_init_shared_memory_for_take_image_step();
string logPath = CreateLogFolder(zwtime); string logPath = CreateLogFolder(zwtime);
int flash_duration = (int) (waitbeforepicture * 1000); int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash");
#endif
#ifdef WIFITURNOFF #ifdef WIFITURNOFF
esp_wifi_stop(); // to save power usage and esp_wifi_stop(); // to save power usage and
#endif #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); takePictureWithFlash(flash_duration);
#ifdef WIFITURNOFF #ifdef WIFITURNOFF
esp_wifi_start(); esp_wifi_start();
#endif #endif
#ifdef DEBUG_DETAIL_ON
#ifdef DEBUG_DETAIL_ON LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash");
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash"); #endif
#endif
LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage); LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage);
RemoveOldLogs(); RemoveOldLogs();
#ifdef DEBUG_DETAIL_ON #ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs"); LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs");
#endif #endif
psram_deinit_shared_memory_for_take_image_step(); psram_deinit_shared_memory_for_take_image_step();
return true; return true;
} }
esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req) esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req)
{ {
int flash_duration = (int) (waitbeforepicture * 1000); int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000);
time(&TimeImageTaken); time(&TimeImageTaken);
localtime(&TimeImageTaken); localtime(&TimeImageTaken);
return Camera.CaptureToHTTP(req, flash_duration); return Camera.CaptureToHTTP(req, flash_duration);
} }
ImageData *ClassFlowTakeImage::SendRawImage(void)
ImageData* ClassFlowTakeImage::SendRawImage()
{ {
CImageBasis *zw = new CImageBasis("SendRawImage", rawImage); CImageBasis *zw = new CImageBasis("SendRawImage", rawImage);
ImageData *id; ImageData *id;
int flash_duration = (int) (waitbeforepicture * 1000); int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000);
Camera.CaptureToBasisImage(zw, flash_duration); Camera.CaptureToBasisImage(zw, flash_duration);
time(&TimeImageTaken); time(&TimeImageTaken);
localtime(&TimeImageTaken); localtime(&TimeImageTaken);
id = zw->writeToMemoryAsJPG(); id = zw->writeToMemoryAsJPG();
delete zw; delete zw;
return id; return id;
} }
time_t ClassFlowTakeImage::getTimeImageTaken() time_t ClassFlowTakeImage::getTimeImageTaken(void)
{ {
return TimeImageTaken; return TimeImageTaken;
} }
@@ -257,4 +597,3 @@ ClassFlowTakeImage::~ClassFlowTakeImage(void)
{ {
delete rawImage; delete rawImage;
} }

View File

@@ -9,47 +9,32 @@
#include <string> #include <string>
class ClassFlowTakeImage : class ClassFlowTakeImage : public ClassFlowImage
public ClassFlowImage
{ {
protected: protected:
float waitbeforepicture;
float waitbeforepicture_store;
framesize_t ImageSize;
bool isImageSize;
int ImageQuality;
time_t TimeImageTaken; time_t TimeImageTaken;
string namerawimage; string namerawimage;
int image_height, image_width;
bool SaveAllFiles;
bool FixedExposure;
esp_err_t camera_capture(void);
void CopyFile(string input, string output);
esp_err_t camera_capture();
void takePictureWithFlash(int flash_duration); void takePictureWithFlash(int flash_duration);
void SetInitialParameter(void);
void SetInitialParameter(void);
public: public:
CImageBasis *rawImage; CImageBasis *rawImage;
ClassFlowTakeImage(std::vector<ClassFlow*>* lfc); ClassFlowTakeImage(std::vector<ClassFlow *> *lfc);
bool ReadParameter(FILE* pfile, string& aktparamgraph); bool ReadParameter(FILE *pfile, string &aktparamgraph);
bool doFlow(string time); bool doFlow(string time);
string getHTMLSingleStep(string host); string getHTMLSingleStep(string host);
time_t getTimeImageTaken(); time_t getTimeImageTaken(void);
string name(){return "ClassFlowTakeImage";}; string name() { return "ClassFlowTakeImage"; };
ImageData* SendRawImage(); ImageData *SendRawImage(void);
esp_err_t SendRawJPG(httpd_req_t *req); esp_err_t SendRawJPG(httpd_req_t *req);
~ClassFlowTakeImage(void); ~ClassFlowTakeImage(void);
}; };
#endif // CLASSFFLOWTAKEIMAGE_H
#endif //CLASSFFLOWTAKEIMAGE_H

File diff suppressed because it is too large Load Diff

View File

@@ -10,25 +10,78 @@
#include "CImageBasis.h" #include "CImageBasis.h"
#include "ClassFlowControll.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; 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 register_server_main_flow_task_uri(httpd_handle_t server);
void CheckIsPlannedReboot(); void CheckIsPlannedReboot(void);
bool getIsPlannedReboot(); bool getIsPlannedReboot(void);
void InitializeFlowTask(); void InitializeFlowTask(void);
void DeleteMainFlowTask(); void DeleteMainFlowTask(void);
bool isSetupModusActive(); bool isSetupModusActive(void);
int getCountFlowRounds(); int getCountFlowRounds(void);
#ifdef ENABLE_MQTT #ifdef ENABLE_MQTT
esp_err_t MQTTCtrlFlowStart(std::string _topic); esp_err_t MQTTCtrlFlowStart(std::string _topic);
#endif //ENABLE_MQTT #endif // ENABLE_MQTT
esp_err_t GetRawJPG(httpd_req_t *req); esp_err_t GetRawJPG(httpd_req_t *req);
esp_err_t GetJPG(std::string _filename, httpd_req_t *req); esp_err_t GetJPG(std::string _filename, httpd_req_t *req);
#endif //MAINFLOWCONTROL_H #endif // MAINFLOWCONTROL_H

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources} idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "." INCLUDE_DIRS "."
REQUIRES esp_timer esp-tflite-micro jomjol_logfile fatfs sdmmc) REQUIRES esp_timer esp-tflite-micro jomjol_logfile fatfs sdmmc vfs)

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include "sdmmc_cmd.h" #include "sdmmc_cmd.h"
using namespace std; using namespace std;

View File

@@ -3,6 +3,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <unistd.h>
#include <inttypes.h> #include <inttypes.h>
#include <sys/stat.h> #include <sys/stat.h>

View File

@@ -0,0 +1,651 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include "sdcard_init.h"
#include "esp_log.h"
#include "ffconf.h"
#include "esp_compiler.h"
#include "esp_vfs.h"
#include "vfs_fat_internal.h"
#include "diskio_impl.h"
#include "diskio_sdmmc.h"
#include "soc/soc_caps.h"
#include "driver/sdmmc_defs.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
static sdmmc_card_t* s_cards[FF_VOLUMES] = { NULL };
static bool s_disk_status_check_en[FF_VOLUMES] = { };
static const char* TAG = "sdcard_init";
#define CHECK_EXECUTE_RESULT(err, str) do { \
if ((err) !=ESP_OK) { \
ESP_LOGE(TAG, str" (0x%x).", err); \
goto cleanup; \
} \
} while(0)
typedef struct vfs_fat_sd_ctx_t {
BYTE pdrv; //Drive number that is mounted
esp_vfs_fat_mount_config_t mount_config; //Mount configuration
FATFS *fs; //FAT structure pointer that is registered
sdmmc_card_t *card; //Card info
char *base_path; //Path where partition is registered
} vfs_fat_sd_ctx_t;
static vfs_fat_sd_ctx_t *s_ctx[FF_VOLUMES] = {};
/**
* This `s_saved_ctx_id` is only used by `esp_vfs_fat_sdmmc_unmount`, which is deprecated.
* This variable together with `esp_vfs_fat_sdmmc_unmount` should be removed in next major version
*/
static uint32_t s_saved_ctx_id = FF_VOLUMES;
static void call_host_deinit_mh(const sdmmc_host_t *host_config);
static esp_err_t partition_card_mh(const esp_vfs_fat_mount_config_t *mount_config, const char *drv, sdmmc_card_t *card, BYTE pdrv);
//Check if SD/MMC card is present
static DSTATUS ff_sdmmc_card_available_mh(BYTE pdrv)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_get_status(card);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "Check status failed (0x%x)", err);
return STA_NOINIT;
}
return 0;
}
/**
* ff_sdmmc_status() and ff_sdmmc_initialize() return STA_NOINIT when sdmmc_get_status()
* fails. This error value is checked throughout the FATFS code.
* Both functions return 0 on success.
*/
DSTATUS ff_sdmmc_initialize_mh (BYTE pdrv)
{
return ff_sdmmc_card_available_mh(pdrv);
}
DSTATUS ff_sdmmc_status_mh(BYTE pdrv)
{
if (s_disk_status_check_en[pdrv]) {
return ff_sdmmc_card_available_mh(pdrv);
}
return 0;
}
DRESULT ff_sdmmc_read_mh (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_read_sectors(card, buff, sector, count);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_read_blocks failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_sdmmc_write_mh (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_write_sectors(card, buff, sector, count);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_write_blocks failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
#if FF_USE_TRIM
DRESULT ff_sdmmc_trim_mh (BYTE pdrv, DWORD start_sector, DWORD sector_count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
sdmmc_erase_arg_t arg;
arg = sdmmc_can_discard(card) == ESP_OK ? SDMMC_DISCARD_ARG : SDMMC_ERASE_ARG;
esp_err_t err = sdmmc_erase_sectors(card, start_sector, sector_count, arg);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_erase_sectors failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
#endif //FF_USE_TRIM
DRESULT ff_sdmmc_ioctl_mh (BYTE pdrv, BYTE cmd, void* buff)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
switch(cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD*) buff) = card->csd.capacity;
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD*) buff) = card->csd.sector_size;
return RES_OK;
case GET_BLOCK_SIZE:
return RES_ERROR;
#if FF_USE_TRIM
case CTRL_TRIM:
if (sdmmc_can_trim(card) != ESP_OK) {
return RES_PARERR;
}
return ff_sdmmc_trim_mh (pdrv, *((DWORD*)buff), //start_sector
(*((DWORD*)buff + 1) - *((DWORD*)buff) + 1)); //sector_count
#endif //FF_USE_TRIM
}
return RES_ERROR;
}
void ff_sdmmc_set_disk_status_check_mh(BYTE pdrv, bool enable)
{
s_disk_status_check_en[pdrv] = enable;
}
void ff_diskio_register_sdmmc_mh(BYTE pdrv, sdmmc_card_t* card)
{
static const ff_diskio_impl_t sdmmc_impl = {
.init = &ff_sdmmc_initialize_mh,
.status = &ff_sdmmc_status_mh,
.read = &ff_sdmmc_read_mh,
.write = &ff_sdmmc_write_mh,
.ioctl = &ff_sdmmc_ioctl_mh
};
s_cards[pdrv] = card;
s_disk_status_check_en[pdrv] = false;
ff_diskio_register(pdrv, &sdmmc_impl);
}
BYTE ff_diskio_get_pdrv_card_mh(const sdmmc_card_t* card)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (card == s_cards[i]) {
return i;
}
}
return 0xff;
}
static bool s_get_context_id_by_card_mh(const sdmmc_card_t *card, uint32_t *out_id)
{
vfs_fat_sd_ctx_t *p_ctx = NULL;
for (int i = 0; i < FF_VOLUMES; i++) {
p_ctx = s_ctx[i];
if (p_ctx) {
if (p_ctx->card == card) {
*out_id = i;
return true;
}
}
}
return false;
}
static uint32_t s_get_unused_context_id_mh(void)
{
for (uint32_t i = 0; i < FF_VOLUMES; i++) {
if (!s_ctx[i]) {
return i;
}
}
return FF_VOLUMES;
}
static esp_err_t mount_prepare_mem_mh(const char *base_path, BYTE *out_pdrv, char **out_dup_path, sdmmc_card_t** out_card)
{
esp_err_t err = ESP_OK;
char* dup_path = NULL;
sdmmc_card_t* card = NULL;
// connect SDMMC driver to FATFS
BYTE pdrv = FF_DRV_NOT_USED;
if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == FF_DRV_NOT_USED) {
ESP_LOGD(TAG, "the maximum count of volumes is already mounted");
return ESP_ERR_NO_MEM;
}
// not using ff_memalloc here, as allocation in internal RAM is preferred
card = (sdmmc_card_t*)malloc(sizeof(sdmmc_card_t));
if (card == NULL) {
ESP_LOGD(TAG, "could not locate new sdmmc_card_t");
err = ESP_ERR_NO_MEM;
goto cleanup;
}
dup_path = strdup(base_path);
if(!dup_path){
ESP_LOGD(TAG, "could not copy base_path");
err = ESP_ERR_NO_MEM;
goto cleanup;
}
*out_card = card;
*out_pdrv = pdrv;
*out_dup_path = dup_path;
return ESP_OK;
cleanup:
free(card);
free(dup_path);
return err;
}
static esp_err_t s_f_mount_mh(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config)
{
esp_err_t err = ESP_OK;
FRESULT res = f_mount(fs, drv, 1);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGW(TAG, "failed to mount card (%d)", res);
bool need_mount_again = (res == FR_NO_FILESYSTEM || res == FR_INT_ERR) && mount_config->format_if_mount_failed;
if (!need_mount_again) {
return ESP_FAIL;
}
err = partition_card_mh(mount_config, drv, card, pdrv);
if (err != ESP_OK) {
return err;
}
ESP_LOGW(TAG, "mounting again");
res = f_mount(fs, drv, 0);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res);
return err;
}
}
return ESP_OK;
}
static esp_err_t mount_to_vfs_fat_mh(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv, const char *base_path, FATFS **out_fs)
{
FATFS *fs = NULL;
esp_err_t err;
ff_diskio_register_sdmmc_mh(pdrv, card);
ff_sdmmc_set_disk_status_check_mh(pdrv, mount_config->disk_status_check_enable);
ESP_LOGD(TAG, "using pdrv=%i", pdrv);
char drv[3] = {(char)('0' + pdrv), ':', 0};
// connect FATFS to VFS
err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
*out_fs = fs;
if (err == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (err != ESP_OK) {
ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", err);
goto fail;
}
// Try to mount partition
err = s_f_mount_mh(card, fs, drv, pdrv, mount_config);
if (err != ESP_OK) {
goto fail;
}
return ESP_OK;
fail:
if (fs) {
f_mount(NULL, drv, 0);
}
esp_vfs_fat_unregister_path(base_path);
ff_diskio_unregister(pdrv);
return err;
}
static esp_err_t partition_card_mh(const esp_vfs_fat_mount_config_t *mount_config, const char *drv, sdmmc_card_t *card, BYTE pdrv)
{
FRESULT res = FR_OK;
esp_err_t err;
const size_t workbuf_size = 4096;
void* workbuf = NULL;
ESP_LOGW(TAG, "partitioning card");
workbuf = ff_memalloc(workbuf_size);
if (workbuf == NULL) {
return ESP_ERR_NO_MEM;
}
LBA_t plist[] = {100, 0, 0, 0};
res = f_fdisk(pdrv, plist, workbuf);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_fdisk failed (%d)", res);
goto fail;
}
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(card->csd.sector_size, mount_config->allocation_unit_size);
ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size);
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
res = f_mkfs(drv, &opt, workbuf, workbuf_size);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
goto fail;
}
free(workbuf);
return ESP_OK;
fail:
free(workbuf);
return err;
}
#if SOC_SDMMC_HOST_SUPPORTED
static esp_err_t init_sdmmc_host_mh(int slot, const void *slot_config, int *out_slot)
{
*out_slot = slot;
return sdmmc_host_init_slot(slot, (const sdmmc_slot_config_t*) slot_config);
}
esp_err_t esp_vfs_fat_sdmmc_mount_mh(const char* base_path, const sdmmc_host_t* host_config, const void* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card)
{
esp_err_t err;
vfs_fat_sd_ctx_t *ctx = NULL;
uint32_t ctx_id = FF_VOLUMES;
FATFS *fs = NULL;
int card_handle = -1; //uninitialized
sdmmc_card_t* card = NULL;
BYTE pdrv = FF_DRV_NOT_USED;
char* dup_path = NULL;
bool host_inited = false;
err = mount_prepare_mem_mh(base_path, &pdrv, &dup_path, &card);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount_prepare failed");
return err;
}
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
//deinit() needs to be called to revert the init
host_inited = true;
//If this failed (indicated by card_handle != -1), slot deinit needs to called()
//leave card_handle as is to indicate that (though slot deinit not implemented yet.
err = init_sdmmc_host_mh(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
// probe and initialize card
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
err = mount_to_vfs_fat_mh(mount_config, card, pdrv, dup_path, &fs);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
*out_card = card;
}
//For deprecation backward compatibility
if (s_saved_ctx_id == FF_VOLUMES) {
s_saved_ctx_id = 0;
}
ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
if (!ctx) {
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
}
ctx->pdrv = pdrv;
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
ctx->card = card;
ctx->base_path = dup_path;
ctx->fs = fs;
ctx_id = s_get_unused_context_id_mh();
assert(ctx_id != FF_VOLUMES);
s_ctx[ctx_id] = ctx;
return ESP_OK;
cleanup:
if (host_inited) {
call_host_deinit_mh(host_config);
}
free(card);
free(dup_path);
return err;
}
#endif
static esp_err_t init_sdspi_host_mh(int slot, const void *slot_config, int *out_slot)
{
esp_err_t err = sdspi_host_init_device((const sdspi_device_config_t*)slot_config, out_slot);
if (err != ESP_OK) {
ESP_LOGE(TAG,
"Failed to attach sdspi device onto an SPI bus (rc=0x%x), please initialize the \
bus first and check the device parameters."
, err);
}
return err;
}
esp_err_t esp_vfs_fat_sdspi_mount_mh(const char* base_path, const sdmmc_host_t* host_config_input, const sdspi_device_config_t* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card)
{
const sdmmc_host_t* host_config = host_config_input;
esp_err_t err;
vfs_fat_sd_ctx_t *ctx = NULL;
uint32_t ctx_id = FF_VOLUMES;
FATFS *fs = NULL;
int card_handle = -1; //uninitialized
bool host_inited = false;
BYTE pdrv = FF_DRV_NOT_USED;
sdmmc_card_t* card = NULL;
char* dup_path = NULL;
err = mount_prepare_mem_mh(base_path, &pdrv, &dup_path, &card);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount_prepare failed");
return err;
}
//the init() function is usually empty, doesn't require any deinit to revert it
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
err = init_sdspi_host_mh(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
//Set `host_inited` to true to indicate that host_config->deinit() needs
//to be called to revert `init_sdspi_host`
host_inited = true;
//The `slot` argument inside host_config should be replaced by the SD SPI handled returned
//above. But the input pointer is const, so create a new variable.
sdmmc_host_t new_config;
if (card_handle != host_config->slot) {
new_config = *host_config_input;
host_config = &new_config;
new_config.slot = card_handle;
}
// probe and initialize card
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
err = mount_to_vfs_fat_mh(mount_config, card, pdrv, dup_path, &fs);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
*out_card = card;
}
//For deprecation backward compatibility
if (s_saved_ctx_id == FF_VOLUMES) {
s_saved_ctx_id = 0;
}
ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
if (!ctx) {
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
}
ctx->pdrv = pdrv;
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
ctx->card = card;
ctx->base_path = dup_path;
ctx->fs = fs;
ctx_id = s_get_unused_context_id_mh();
assert(ctx_id != FF_VOLUMES);
s_ctx[ctx_id] = ctx;
return ESP_OK;
cleanup:
if (host_inited) {
call_host_deinit_mh(host_config);
}
free(card);
free(dup_path);
return err;
}
static void call_host_deinit_mh(const sdmmc_host_t *host_config)
{
if (host_config->flags & SDMMC_HOST_FLAG_DEINIT_ARG) {
host_config->deinit_p(host_config->slot);
} else {
host_config->deinit();
}
}
static esp_err_t unmount_card_core_mh(const char *base_path, sdmmc_card_t *card)
{
BYTE pdrv = ff_diskio_get_pdrv_card_mh(card);
if (pdrv == 0xff) {
return ESP_ERR_INVALID_ARG;
}
// unmount
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
// release SD driver
ff_diskio_unregister(pdrv);
call_host_deinit_mh(&card->host);
free(card);
esp_err_t err = esp_vfs_fat_unregister_path(base_path);
return err;
}
esp_err_t esp_vfs_fat_sdmmc_unmount_mh(void)
{
esp_err_t err = unmount_card_core_mh(s_ctx[s_saved_ctx_id]->base_path, s_ctx[s_saved_ctx_id]->card);
free(s_ctx[s_saved_ctx_id]);
s_ctx[s_saved_ctx_id] = NULL;
s_saved_ctx_id = FF_VOLUMES;
return err;
}
esp_err_t esp_vfs_fat_sdcard_unmount_mh(const char *base_path, sdmmc_card_t *card)
{
uint32_t id = FF_VOLUMES;
bool found = s_get_context_id_by_card_mh(card, &id);
if (!found) {
return ESP_ERR_INVALID_ARG;
}
free(s_ctx[id]);
s_ctx[id] = NULL;
esp_err_t err = unmount_card_core_mh(base_path, card);
return err;
}
esp_err_t esp_vfs_fat_sdcard_format_mh(const char *base_path, sdmmc_card_t *card)
{
esp_err_t ret = ESP_OK;
if (!card) {
ESP_LOGE(TAG, "card not initialized");
return ESP_ERR_INVALID_STATE;
}
BYTE pdrv = ff_diskio_get_pdrv_card_mh(card);
if (pdrv == 0xff) {
ESP_LOGE(TAG, "card driver not registered");
return ESP_ERR_INVALID_STATE;
}
const size_t workbuf_size = 4096;
void *workbuf = ff_memalloc(workbuf_size);
if (workbuf == NULL) {
return ESP_ERR_NO_MEM;
}
//unmount
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
//format
uint32_t id = FF_VOLUMES;
bool found = s_get_context_id_by_card_mh(card, &id);
assert(found);
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(card->csd.sector_size, s_ctx[id]->mount_config.allocation_unit_size);
ESP_LOGI(TAG, "Formatting card, allocation unit size=%d", alloc_unit_size);
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
FRESULT res = f_mkfs(drv, &opt, workbuf, workbuf_size);
free(workbuf);
if (res != FR_OK) {
ret = ESP_FAIL;
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
}
//mount back
esp_err_t err = s_f_mount_mh(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config);
if (err != ESP_OK) {
unmount_card_core_mh(base_path, card);
ESP_LOGE(TAG, "failed to format, resources recycled, please mount again");
}
return ret;
}

View File

@@ -0,0 +1,111 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_types.h"
#include "driver/sdspi_host.h"
#include "ff.h"
#include "esp_vfs_fat.h"
#include "wear_levelling.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
*
* This is an all-in-one function which does the following:
* - initializes SDMMC driver or SPI driver with configuration in host_config
* - initializes SD card with configuration in slot_config
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
* For real world applications, developers should implement the logic of
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
* with proper error checking and handling of exceptional conditions.
*
* @note Use this API to mount a card through SDSPI is deprecated. Please call
* `esp_vfs_fat_sdspi_mount()` instead for that case.
*
* @param base_path path where partition should be registered (e.g. "/sdcard")
* @param host_config Pointer to structure describing SDMMC host. When using
* SDMMC peripheral, this structure can be initialized using
* SDMMC_HOST_DEFAULT() macro. When using SPI peripheral,
* this structure can be initialized using SDSPI_HOST_DEFAULT()
* macro.
* @param slot_config Pointer to structure with slot configuration.
* For SDMMC peripheral, pass a pointer to sdmmc_slot_config_t
* structure initialized using SDMMC_SLOT_CONFIG_DEFAULT.
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] out_card if not NULL, pointer to the card information structure will be returned via this argument
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
*/
esp_err_t esp_vfs_fat_sdmmc_mount_mh(const char* base_path, const sdmmc_host_t* host_config, const void* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card);
/**
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
*
* This is an all-in-one function which does the following:
* - initializes an SPI Master device based on the SPI Master driver with configuration in
* slot_config, and attach it to an initialized SPI bus.
* - initializes SD card with configuration in host_config_input
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
* For real world applications, developers should implement the logic of
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
* with proper error checking and handling of exceptional conditions.
*
* @note This function try to attach the new SD SPI device to the bus specified in host_config.
* Make sure the SPI bus specified in `host_config->slot` have been initialized by
* `spi_bus_initialize()` before.
*
* @param base_path path where partition should be registered (e.g. "/sdcard")
* @param host_config_input Pointer to structure describing SDMMC host. This structure can be
* initialized using SDSPI_HOST_DEFAULT() macro.
* @param slot_config Pointer to structure with slot configuration.
* For SPI peripheral, pass a pointer to sdspi_device_config_t
* structure initialized using SDSPI_DEVICE_CONFIG_DEFAULT().
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] out_card If not NULL, pointer to the card information structure will be returned via
* this argument. It is suggested to hold this handle and use it to unmount the card later if
* needed. Otherwise it's not suggested to use more than one card at the same time and unmount one
* of them in your application.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
*/
esp_err_t esp_vfs_fat_sdspi_mount_mh(const char* base_path, const sdmmc_host_t* host_config_input, const sdspi_device_config_t* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card);
#ifdef __cplusplus
}
#endif

View File

@@ -443,7 +443,7 @@ void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
//free_psram_heap(std::string(TAG) + "->rgb_image (LoadFromMemory)", rgb_image); //free_psram_heap(std::string(TAG) + "->rgb_image (LoadFromMemory)", rgb_image);
} }
rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, 3); rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, STBI_rgb);
bpp = channels; bpp = channels;
ESP_LOGD(TAG, "Image loaded from memory: %d, %d, %d", width, height, channels); ESP_LOGD(TAG, "Image loaded from memory: %d, %d, %d", width, height, channels);
@@ -459,6 +459,44 @@ void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
} }
void CImageBasis::crop_image(unsigned short cropLeft, unsigned short cropRight, unsigned short cropTop, unsigned short cropBottom)
{
unsigned int maxTopIndex = cropTop * width * channels;
unsigned int minBottomIndex = ((width*height) - (cropBottom * width)) * channels;
unsigned short maxX = width - cropRight; // In pixels
unsigned short newWidth = width - cropLeft - cropRight;
unsigned short newHeight = height - cropTop - cropBottom;
unsigned int writeIndex = 0;
// Loop over all bytes
for (int i = 0; i < width * height * channels; i += channels) {
// Calculate current X, Y pixel position
int x = (i/channels) % width;
// Crop from the top
if (i < maxTopIndex) { continue; }
// Crop from the bottom
if (i > minBottomIndex) { continue; }
// Crop from the left
if (x <= cropLeft) { continue; }
// Crop from the right
if (x > maxX) { continue; }
// If we get here, keep the pixels
for (int c = 0; c < channels; c++) {
rgb_image[writeIndex++] = rgb_image[i+c];
}
}
// Set the new dimensions of the framebuffer for further use.
width = newWidth;
height = newHeight;
}
CImageBasis::CImageBasis(string _name, CImageBasis *_copyfrom) CImageBasis::CImageBasis(string _name, CImageBasis *_copyfrom)
{ {
name = _name; name = _name;
@@ -598,6 +636,20 @@ CImageBasis::CImageBasis(string _name, uint8_t* _rgb_image, int _channels, int _
} }
void CImageBasis::Negative(void)
{
RGBImageLock();
for (int i = 0; i < width * height * channels; i += channels) {
for (int c = 0; c < channels; c++) {
rgb_image[i+c] = 255 - rgb_image[i+c];
}
}
RGBImageRelease();
}
void CImageBasis::Contrast(float _contrast) //input range [-100..100] void CImageBasis::Contrast(float _contrast) //input range [-100..100]
{ {
stbi_uc* p_source; stbi_uc* p_source;

View File

@@ -56,6 +56,7 @@ class CImageBasis
void drawEllipse(int x1, int y1, int radx, int rady, int r, int g, int b, int thickness = 1); void drawEllipse(int x1, int y1, int radx, int rady, int r, int g, int b, int thickness = 1);
void setPixelColor(int x, int y, int r, int g, int b); void setPixelColor(int x, int y, int r, int g, int b);
void Negative(void);
void Contrast(float _contrast); void Contrast(float _contrast);
bool ImageOkay(); bool ImageOkay();
bool CopyFromMemory(uint8_t* _source, int _size); bool CopyFromMemory(uint8_t* _source, int _size);
@@ -74,6 +75,7 @@ class CImageBasis
void Resize(int _new_dx, int _new_dy); void Resize(int _new_dx, int _new_dy);
void Resize(int _new_dx, int _new_dy, CImageBasis *_target); void Resize(int _new_dx, int _new_dy, CImageBasis *_target);
void crop_image(unsigned short cropLeft, unsigned short cropRight, unsigned short cropTop, unsigned short cropBottom);
void LoadFromMemory(stbi_uc *_buffer, int len); void LoadFromMemory(stbi_uc *_buffer, int len);

View File

@@ -1,353 +1,309 @@
#include <string> #include <string>
#include "CRotateImage.h" #include "CRotateImage.h"
#include "psram.h" #include "psram.h"
static const char *TAG = "C ROTATE IMG"; static const char *TAG = "C ROTATE IMG";
CRotateImage::CRotateImage(std::string _name, CImageBasis *_org, CImageBasis *_temp, bool _flip) : CImageBasis(_name) CRotateImage::CRotateImage(std::string _name, CImageBasis *_org, CImageBasis *_temp, bool _flip) : CImageBasis(_name)
{ {
rgb_image = _org->rgb_image; rgb_image = _org->rgb_image;
channels = _org->channels; channels = _org->channels;
width = _org->width; width = _org->width;
height = _org->height; height = _org->height;
bpp = _org->bpp; bpp = _org->bpp;
externalImage = true; externalImage = true;
ImageTMP = _temp; ImageTMP = _temp;
ImageOrg = _org; ImageOrg = _org;
islocked = false; islocked = false;
doflip = _flip; doflip = _flip;
} }
void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
void CRotateImage::Mirror(){ {
int memsize = width * height * channels; int org_width, org_height;
uint8_t* odata; float m[2][3];
if (ImageTMP)
{ float x_center = _centerx;
odata = ImageTMP->RGBImageLock(); float y_center = _centery;
} _angle = _angle / 180 * M_PI;
else
{ if (doflip)
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM); {
} org_width = width;
org_height = height;
height = org_width;
int x_source, y_source; width = org_height;
stbi_uc* p_target; x_center = x_center - (org_width/2) + (org_height/2);
stbi_uc* p_source; y_center = y_center + (org_width/2) - (org_height/2);
if (ImageOrg)
RGBImageLock(); {
ImageOrg->height = height;
for (int x = 0; x < width; ++x) ImageOrg->width = width;
for (int y = 0; y < height; ++y) }
{ }
p_target = odata + (channels * (y * width + x)); else
{
x_source = width - x; org_width = width;
y_source = y; org_height = height;
}
p_source = rgb_image + (channels * (y_source * width + x_source));
for (int _channels = 0; _channels < channels; ++_channels) m[0][0] = cos(_angle);
p_target[_channels] = p_source[_channels]; m[0][1] = sin(_angle);
} m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
// memcpy(rgb_image, odata, memsize); m[1][0] = -m[0][1];
memCopy(odata, rgb_image, memsize); m[1][1] = m[0][0];
if (!ImageTMP) m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
free_psram_heap(std::string(TAG) + "->odata", odata);
if (doflip)
if (ImageTMP) {
ImageTMP->RGBImageRelease(); m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
RGBImageRelease(); }
}
int memsize = width * height * channels;
void CRotateImage::Rotate(float _angle, int _centerx, int _centery) uint8_t* odata;
{ if (ImageTMP)
int org_width, org_height; {
float m[2][3]; odata = ImageTMP->RGBImageLock();
}
float x_center = _centerx; else
float y_center = _centery; {
_angle = _angle / 180 * M_PI; odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
}
if (doflip)
{
org_width = width; int x_source, y_source;
org_height = height; stbi_uc* p_target;
height = org_width; stbi_uc* p_source;
width = org_height;
x_center = x_center - (org_width/2) + (org_height/2); RGBImageLock();
y_center = y_center + (org_width/2) - (org_height/2);
if (ImageOrg) for (int x = 0; x < width; ++x)
{ for (int y = 0; y < height; ++y)
ImageOrg->height = height; {
ImageOrg->width = width; p_target = odata + (channels * (y * width + x));
}
} x_source = int(m[0][0] * x + m[0][1] * y);
else y_source = int(m[1][0] * x + m[1][1] * y);
{
org_width = width; x_source += int(m[0][2]);
org_height = height; y_source += int(m[1][2]);
}
if ((x_source >= 0) && (x_source < org_width) && (y_source >= 0) && (y_source < org_height))
m[0][0] = cos(_angle); {
m[0][1] = sin(_angle); p_source = rgb_image + (channels * (y_source * org_width + x_source));
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center; for (int _channels = 0; _channels < channels; ++_channels)
p_target[_channels] = p_source[_channels];
m[1][0] = -m[0][1]; }
m[1][1] = m[0][0]; else
m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center; {
for (int _channels = 0; _channels < channels; ++_channels)
if (doflip) p_target[_channels] = 255;
{ }
m[0][2] = m[0][2] + (org_width/2) - (org_height/2); }
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
} // memcpy(rgb_image, odata, memsize);
memCopy(odata, rgb_image, memsize);
int memsize = width * height * channels;
uint8_t* odata; if (!ImageTMP)
if (ImageTMP) {
{ free_psram_heap(std::string(TAG) + "->odata", odata);
odata = ImageTMP->RGBImageLock(); }
} if (ImageTMP)
else ImageTMP->RGBImageRelease();
{
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM); RGBImageRelease();
} }
int x_source, y_source;
stbi_uc* p_target; void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery)
stbi_uc* p_source; {
int org_width, org_height;
RGBImageLock(); float m[2][3];
for (int x = 0; x < width; ++x) float x_center = _centerx;
for (int y = 0; y < height; ++y) float y_center = _centery;
{ _angle = _angle / 180 * M_PI;
p_target = odata + (channels * (y * width + x));
if (doflip)
x_source = int(m[0][0] * x + m[0][1] * y); {
y_source = int(m[1][0] * x + m[1][1] * y); org_width = width;
org_height = height;
x_source += int(m[0][2]); height = org_width;
y_source += int(m[1][2]); width = org_height;
x_center = x_center - (org_width/2) + (org_height/2);
if ((x_source >= 0) && (x_source < org_width) && (y_source >= 0) && (y_source < org_height)) y_center = y_center + (org_width/2) - (org_height/2);
{ if (ImageOrg)
p_source = rgb_image + (channels * (y_source * org_width + x_source)); {
for (int _channels = 0; _channels < channels; ++_channels) ImageOrg->height = height;
p_target[_channels] = p_source[_channels]; ImageOrg->width = width;
} }
else }
{ else
for (int _channels = 0; _channels < channels; ++_channels) {
p_target[_channels] = 255; org_width = width;
} org_height = height;
} }
// memcpy(rgb_image, odata, memsize); m[0][0] = cos(_angle);
memCopy(odata, rgb_image, memsize); m[0][1] = sin(_angle);
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
if (!ImageTMP)
{ m[1][0] = -m[0][1];
free_psram_heap(std::string(TAG) + "->odata", odata); m[1][1] = m[0][0];
} m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
if (ImageTMP)
ImageTMP->RGBImageRelease(); if (doflip)
{
RGBImageRelease(); m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
} m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
}
int memsize = width * height * channels;
void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery) uint8_t* odata;
{ if (ImageTMP)
int org_width, org_height; {
float m[2][3]; odata = ImageTMP->RGBImageLock();
}
float x_center = _centerx; else
float y_center = _centery; {
_angle = _angle / 180 * M_PI; odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
}
if (doflip)
{
org_width = width; int x_source_1, y_source_1, x_source_2, y_source_2;
org_height = height; float x_source, y_source;
height = org_width; float quad_ul, quad_ur, quad_ol, quad_or;
width = org_height; stbi_uc* p_target;
x_center = x_center - (org_width/2) + (org_height/2); stbi_uc *p_source_ul, *p_source_ur, *p_source_ol, *p_source_or;
y_center = y_center + (org_width/2) - (org_height/2);
if (ImageOrg) RGBImageLock();
{
ImageOrg->height = height; for (int x = 0; x < width; ++x)
ImageOrg->width = width; for (int y = 0; y < height; ++y)
} {
} p_target = odata + (channels * (y * width + x));
else
{ x_source = (m[0][0] * x + m[0][1] * y);
org_width = width; y_source = (m[1][0] * x + m[1][1] * y);
org_height = height;
} x_source += (m[0][2]);
y_source += (m[1][2]);
m[0][0] = cos(_angle);
m[0][1] = sin(_angle); x_source_1 = (int)x_source;
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center; x_source_2 = x_source_1 + 1;
y_source_1 = (int)y_source;
m[1][0] = -m[0][1]; y_source_2 = y_source_1 + 1;
m[1][1] = m[0][0];
m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center; quad_ul = (x_source_2 - x_source) * (y_source_2 - y_source);
quad_ur = (1- (x_source_2 - x_source)) * (y_source_2 - y_source);
if (doflip) quad_or = (x_source_2 - x_source) * (1-(y_source_2 - y_source));
{ quad_ol = (1- (x_source_2 - x_source)) * (1-(y_source_2 - y_source));
m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
} if ((x_source_1 >= 0) && (x_source_2 < org_width) && (y_source_1 >= 0) && (y_source_2 < org_height))
{
int memsize = width * height * channels; p_source_ul = rgb_image + (channels * (y_source_1 * org_width + x_source_1));
uint8_t* odata; p_source_ur = rgb_image + (channels * (y_source_1 * org_width + x_source_2));
if (ImageTMP) p_source_or = rgb_image + (channels * (y_source_2 * org_width + x_source_1));
{ p_source_ol = rgb_image + (channels * (y_source_2 * org_width + x_source_2));
odata = ImageTMP->RGBImageLock(); for (int _channels = 0; _channels < channels; ++_channels)
} {
else p_target[_channels] = (int)((float)p_source_ul[_channels] * quad_ul
{ + (float)p_source_ur[_channels] * quad_ur
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM); + (float)p_source_or[_channels] * quad_or
} + (float)p_source_ol[_channels] * quad_ol);
}
}
int x_source_1, y_source_1, x_source_2, y_source_2; else
float x_source, y_source; {
float quad_ul, quad_ur, quad_ol, quad_or; for (int _channels = 0; _channels < channels; ++_channels)
stbi_uc* p_target; p_target[_channels] = 255;
stbi_uc *p_source_ul, *p_source_ur, *p_source_ol, *p_source_or; }
}
RGBImageLock();
// memcpy(rgb_image, odata, memsize);
for (int x = 0; x < width; ++x) memCopy(odata, rgb_image, memsize);
for (int y = 0; y < height; ++y)
{ if (!ImageTMP)
p_target = odata + (channels * (y * width + x)); {
free_psram_heap(std::string(TAG) + "->odata", odata);
x_source = (m[0][0] * x + m[0][1] * y); }
y_source = (m[1][0] * x + m[1][1] * y); if (ImageTMP)
ImageTMP->RGBImageRelease();
x_source += (m[0][2]);
y_source += (m[1][2]); RGBImageRelease();
}
x_source_1 = (int)x_source;
x_source_2 = x_source_1 + 1;
y_source_1 = (int)y_source; void CRotateImage::Rotate(float _angle)
y_source_2 = y_source_1 + 1; {
// ESP_LOGD(TAG, "width %d, height %d", width, height);
quad_ul = (x_source_2 - x_source) * (y_source_2 - y_source); Rotate(_angle, width / 2, height / 2);
quad_ur = (1- (x_source_2 - x_source)) * (y_source_2 - y_source); }
quad_or = (x_source_2 - x_source) * (1-(y_source_2 - y_source));
quad_ol = (1- (x_source_2 - x_source)) * (1-(y_source_2 - y_source)); void CRotateImage::RotateAntiAliasing(float _angle)
{
// ESP_LOGD(TAG, "width %d, height %d", width, height);
if ((x_source_1 >= 0) && (x_source_2 < org_width) && (y_source_1 >= 0) && (y_source_2 < org_height)) RotateAntiAliasing(_angle, width / 2, height / 2);
{ }
p_source_ul = rgb_image + (channels * (y_source_1 * org_width + x_source_1));
p_source_ur = rgb_image + (channels * (y_source_1 * org_width + x_source_2)); void CRotateImage::Translate(int _dx, int _dy)
p_source_or = rgb_image + (channels * (y_source_2 * org_width + x_source_1)); {
p_source_ol = rgb_image + (channels * (y_source_2 * org_width + x_source_2)); int memsize = width * height * channels;
for (int _channels = 0; _channels < channels; ++_channels) uint8_t* odata;
{ if (ImageTMP)
p_target[_channels] = (int)((float)p_source_ul[_channels] * quad_ul {
+ (float)p_source_ur[_channels] * quad_ur odata = ImageTMP->RGBImageLock();
+ (float)p_source_or[_channels] * quad_or }
+ (float)p_source_ol[_channels] * quad_ol); else
} {
} odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
else }
{
for (int _channels = 0; _channels < channels; ++_channels)
p_target[_channels] = 255;
} int x_source, y_source;
} stbi_uc* p_target;
stbi_uc* p_source;
// memcpy(rgb_image, odata, memsize);
memCopy(odata, rgb_image, memsize); RGBImageLock();
if (!ImageTMP) for (int x = 0; x < width; ++x)
{ for (int y = 0; y < height; ++y)
free_psram_heap(std::string(TAG) + "->odata", odata); {
} p_target = odata + (channels * (y * width + x));
if (ImageTMP)
ImageTMP->RGBImageRelease(); x_source = x - _dx;
y_source = y - _dy;
RGBImageRelease();
} if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height))
{
p_source = rgb_image + (channels * (y_source * width + x_source));
void CRotateImage::Rotate(float _angle) for (int _channels = 0; _channels < channels; ++_channels)
{ p_target[_channels] = p_source[_channels];
// ESP_LOGD(TAG, "width %d, height %d", width, height); }
Rotate(_angle, width / 2, height / 2); else
} {
for (int _channels = 0; _channels < channels; ++_channels)
void CRotateImage::RotateAntiAliasing(float _angle) p_target[_channels] = 255;
{ }
// ESP_LOGD(TAG, "width %d, height %d", width, height); }
RotateAntiAliasing(_angle, width / 2, height / 2);
} // memcpy(rgb_image, odata, memsize);
memCopy(odata, rgb_image, memsize);
void CRotateImage::Translate(int _dx, int _dy) if (!ImageTMP)
{ {
int memsize = width * height * channels; free_psram_heap(std::string(TAG) + "->odata", odata);
uint8_t* odata; }
if (ImageTMP)
{ if (ImageTMP)
odata = ImageTMP->RGBImageLock(); {
} ImageTMP->RGBImageRelease();
else }
{ RGBImageRelease();
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
} }
int x_source, y_source;
stbi_uc* p_target;
stbi_uc* p_source;
RGBImageLock();
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
{
p_target = odata + (channels * (y * width + x));
x_source = x - _dx;
y_source = y - _dy;
if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height))
{
p_source = rgb_image + (channels * (y_source * width + x_source));
for (int _channels = 0; _channels < channels; ++_channels)
p_target[_channels] = p_source[_channels];
}
else
{
for (int _channels = 0; _channels < channels; ++_channels)
p_target[_channels] = 255;
}
}
// memcpy(rgb_image, odata, memsize);
memCopy(odata, rgb_image, memsize);
if (!ImageTMP)
{
free_psram_heap(std::string(TAG) + "->odata", odata);
}
if (ImageTMP)
{
ImageTMP->RGBImageRelease();
}
RGBImageRelease();
}

View File

@@ -1,29 +1,28 @@
#pragma once #pragma once
#ifndef CROTATEIMAGE_H #ifndef CROTATEIMAGE_H
#define CROTATEIMAGE_H #define CROTATEIMAGE_H
#include "CImageBasis.h" #include "CImageBasis.h"
class CRotateImage: public CImageBasis class CRotateImage: public CImageBasis
{ {
public: public:
CImageBasis *ImageTMP, *ImageOrg; CImageBasis *ImageTMP, *ImageOrg;
bool doflip; bool doflip;
CRotateImage(std::string name, std::string _image, bool _flip = false) : CImageBasis(name, _image) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;}; CRotateImage(std::string name, std::string _image, bool _flip = false) : CImageBasis(name, _image) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
CRotateImage(std::string name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp, bool _flip = false) : CImageBasis(name, _rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;}; CRotateImage(std::string name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp, bool _flip = false) : CImageBasis(name, _rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
CRotateImage(std::string name, CImageBasis *_org, CImageBasis *_temp, bool _flip = false); CRotateImage(std::string name, CImageBasis *_org, CImageBasis *_temp, bool _flip = false);
void Rotate(float _angle); void Rotate(float _angle);
void RotateAntiAliasing(float _angle); void RotateAntiAliasing(float _angle);
void Rotate(float _angle, int _centerx, int _centery); void Rotate(float _angle, int _centerx, int _centery);
void RotateAntiAliasing(float _angle, int _centerx, int _centery); void RotateAntiAliasing(float _angle, int _centerx, int _centery);
void Translate(int _dx, int _dy); void Translate(int _dx, int _dy);
void Mirror(); };
};
#endif //CROTATEIMAGE_H #endif //CROTATEIMAGE_H

View File

@@ -5,6 +5,7 @@
#include <time.h> #include <time.h>
#include "ClassLogFile.h" #include "ClassLogFile.h"
#include "esp_http_client.h" #include "esp_http_client.h"
#include "time_sntp.h"
#include "../../include/defines.h" #include "../../include/defines.h"
@@ -30,7 +31,7 @@ void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, s
_influxDB_V2_Token = _token; _influxDB_V2_Token = _token;
} }
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp) void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC)
{ {
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0}; char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t http_config = { esp_http_client_config_t http_config = {
@@ -41,28 +42,20 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
.user_data = response_buffer .user_data = response_buffer
}; };
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
std::string payload; std::string payload;
char nowTimestamp[21]; char nowTimestamp[21];
if (_timestamp.length() > 0) if (_timeUTC > 0)
{ {
struct tm tm; LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
time_t t;
time(&t);
localtime_r(&t, &tm); // Extract DST setting from actual time to consider it for timestamp evaluation
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
t = mktime(&tm);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp; payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
} }
else else
{ {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
payload = _measurement + " " + _key + "=" + _content; payload = _measurement + " " + _key + "=" + _content;
} }
@@ -137,7 +130,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
return ESP_OK; return ESP_OK;
} }
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp) { void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC) {
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0}; char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t http_config = { esp_http_client_config_t http_config = {
.user_agent = "ESP32 Meter reader", .user_agent = "ESP32 Meter reader",
@@ -156,25 +149,17 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
std::string payload; std::string payload;
char nowTimestamp[21]; char nowTimestamp[21];
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp); LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
if (_timestamp.length() > 0) if (_timeUTC > 0)
{ {
struct tm tm; LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
time_t t;
time(&t);
localtime_r(&t, &tm); // Extract DST setting from actual time to consider it for timestamp evaluation
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
t = mktime(&tm);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp; payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
} }
else else
{ {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
payload = _measurement + " " + _key + "=" + _content; payload = _measurement + " " + _key + "=" + _content;
} }

View File

@@ -10,11 +10,11 @@
// Interface to InfluxDB v1.x // Interface to InfluxDB v1.x
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password); void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp); void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
// Interface to InfluxDB v2.x // Interface to InfluxDB v2.x
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token); void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp); void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);

View File

@@ -21,6 +21,7 @@ static const char *TAG = "MQTT SERVER";
extern const char* libfive_git_version(void); extern const char* libfive_git_version(void);
extern const char* libfive_git_revision(void); extern const char* libfive_git_revision(void);
extern const char* libfive_git_branch(void); extern const char* libfive_git_branch(void);
extern std::string getFwVersion(void);
std::vector<NumberPost*>* NUMBERS; std::vector<NumberPost*>* NUMBERS;
bool HomeassistantDiscovery = false; bool HomeassistantDiscovery = false;
@@ -151,6 +152,7 @@ bool MQTThomeassistantDiscovery(int qos) {
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category // Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "clock-time-eight-outline", "s", "", "", "diagnostic", qos); allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "clock-time-eight-outline", "s", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "MAC", "MAC Address", "network-outline", "", "", "", "diagnostic", qos); allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "MAC", "MAC Address", "network-outline", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "fwVersion", "Firmware Version", "application-outline", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "hostname", "Hostname", "network-outline", "", "", "", "diagnostic", qos); allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "hostname", "Hostname", "network-outline", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "freeMem", "Free Memory", "memory", "B", "", "measurement", "diagnostic", qos); allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "freeMem", "Free Memory", "memory", "B", "", "measurement", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", "", "diagnostic", qos); allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", "", "diagnostic", qos);
@@ -244,6 +246,7 @@ bool publishStaticData(int qos) {
int aFreeInternalHeapSizeBefore = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); int aFreeInternalHeapSizeBefore = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "fwVersion", getFwVersion().c_str(), qos, retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "MAC", getMac(), qos, retainFlag); allSendsSuccessed |= MQTTPublish(maintopic + "/" + "MAC", getMac(), qos, retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), qos, retainFlag); allSendsSuccessed |= MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), qos, retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, qos, retainFlag); allSendsSuccessed |= MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, qos, retainFlag);

View File

@@ -332,4 +332,18 @@ CTfLiteClass::~CTfLiteClass()
delete this->interpreter; delete this->interpreter;
psram_free_shared_tensor_arena_and_model_memory(); psram_free_shared_tensor_arena_and_model_memory();
} }
#ifdef SUPRESS_TFLITE_ERRORS
namespace tflite
{
//tflite::ErrorReporter
// int OwnMicroErrorReporter::Report(const char* format, va_list args)
int OwnMicroErrorReporter::Report(const char* format, va_list args)
{
return 0;
}
}
#endif

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources} idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "." INCLUDE_DIRS "."
REQUIRES esp-tflite-micro jomjol_logfile jomjol_configfile) REQUIRES esp_netif esp-tflite-micro jomjol_logfile jomjol_configfile)

View File

@@ -10,7 +10,8 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_sleep.h" #include "esp_sleep.h"
#include "esp_sntp.h" #include "esp_netif_sntp.h"
#include "../../include/defines.h" #include "../../include/defines.h"
#include "ClassLogFile.h" #include "ClassLogFile.h"
@@ -31,6 +32,9 @@ std::string getNtpStatusText(sntp_sync_status_t status);
static void setTimeZone(std::string _tzstring); static void setTimeZone(std::string _tzstring);
static std::string getServerName(void); static std::string getServerName(void);
int LocalTimeToUTCOffsetSeconds;
std::string ConvertTimeToString(time_t _time, const char * frm) std::string ConvertTimeToString(time_t _time, const char * frm)
{ {
@@ -89,15 +93,51 @@ bool time_manual_reset_sync(void)
} }
int getUTCOffsetSeconds(std::string &zeitzone)
{
int offset = 0;
int vorzeichen = 1;
int minuten = 0;
int stunden = 0;
time_t now;
struct tm timeinfo;
time (&now);
localtime_r(&now, &timeinfo);
char buffer[80];
strftime(buffer, 80, "%z", &timeinfo);
zeitzone = std::string(buffer);
if (zeitzone.length() == 5)
{
if (zeitzone[0] == '-')
vorzeichen = -1;
stunden = stoi(zeitzone.substr(1, 2));
minuten = stoi(zeitzone.substr(3, 2));
offset = ((stunden * 60) + minuten) * 60;
}
return offset;
}
void setTimeZone(std::string _tzstring) void setTimeZone(std::string _tzstring)
{ {
setenv("TZ", _tzstring.c_str(), 1); setenv("TZ", _tzstring.c_str(), 1);
tzset(); tzset();
_tzstring = "Time zone set to " + _tzstring; _tzstring = "Time zone set to " + _tzstring;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring); LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
std::string zeitzone;
LocalTimeToUTCOffsetSeconds = getUTCOffsetSeconds(zeitzone);
// std::string zw = std::to_string(LocalTimeToUTCOffsetSeconds);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "time zone: " + zeitzone + " Delta to UTC: " + std::to_string(LocalTimeToUTCOffsetSeconds) + " seconds");
} }
std::string getNtpStatusText(sntp_sync_status_t status) { std::string getNtpStatusText(sntp_sync_status_t status) {
if (status == SNTP_SYNC_STATUS_COMPLETED) { if (status == SNTP_SYNC_STATUS_COMPLETED) {
return "Synchronized"; return "Synchronized";
@@ -235,21 +275,13 @@ bool setupTime() {
if (useNtp) { if (useNtp) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client..."); LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
sntp_setoperatingmode(SNTP_OPMODE_POLL); esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeServer.c_str());
sntp_setservername(0, timeServer.c_str()); config.sync_cb = time_sync_notification_cb;
sntp_set_time_sync_notification_cb(time_sync_notification_cb); esp_netif_sntp_init(&config);
setTimeZone(timeZone); setTimeZone(timeZone);
sntp_init();
/*
if (!wait_for_timesync())
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Timesync at startup failed.");
}
*/
} }
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset) /* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
* There should only be a minor correction through NTP */ * There should only be a minor correction through NTP */
@@ -258,6 +290,7 @@ bool setupTime() {
localtime_r(&now, &timeinfo); localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
if (getTimeIsSet()) { if (getTimeIsSet()) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf)); LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
} }

View File

@@ -28,5 +28,7 @@ bool setupTime();
bool time_manual_reset_sync(void); bool time_manual_reset_sync(void);
extern int LocalTimeToUTCOffsetSeconds;
#endif //TIMESNTP_H #endif //TIMESNTP_H

View File

@@ -378,7 +378,7 @@ void wifi_scan(void)
else { else {
if (esp_wifi_scan_get_ap_records(&max_number_of_ap_found, wifi_ap_records) != ESP_OK) { // Retrieve results (and free internal heap) if (esp_wifi_scan_get_ap_records(&max_number_of_ap_found, wifi_ap_records) != ESP_OK) { // Retrieve results (and free internal heap)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "wifi_scan: esp_wifi_scan_get_ap_records: Error retrieving datasets"); LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "wifi_scan: esp_wifi_scan_get_ap_records: Error retrieving datasets");
delete wifi_ap_records; delete[] wifi_ap_records;
return; return;
} }
} }
@@ -401,7 +401,7 @@ void wifi_scan(void)
APWithBetterRSSI = true; APWithBetterRSSI = true;
} }
} }
delete wifi_ap_records; delete[] wifi_ap_records;
} }

View File

@@ -1,3 +1,3 @@
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815 manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
target: esp32 target: esp32
version: 1.0.0 version: 1.0.0

View File

@@ -66,6 +66,7 @@
#define FLASH_GPIO GPIO_NUM_4 // PIN for flashlight LED #define FLASH_GPIO GPIO_NUM_4 // PIN for flashlight LED
#define USE_PWM_LEDFLASH // if __LEDGLOBAL is defined, a global variable is used for LED control, otherwise locally and each time a new #define USE_PWM_LEDFLASH // if __LEDGLOBAL is defined, a global variable is used for LED control, otherwise locally and each time a new
#define CAM_LIVESTREAM_REFRESHRATE 500 // Camera livestream feature: Waiting time in milliseconds to refresh image #define CAM_LIVESTREAM_REFRESHRATE 500 // Camera livestream feature: Waiting time in milliseconds to refresh image
// #define GRAYSCALE_AS_DEFAULT
//ClassControllCamera + ClassFlowTakeImage //ClassControllCamera + ClassFlowTakeImage
@@ -167,15 +168,6 @@
#define LWT_DISCONNECTED "connection lost" #define LWT_DISCONNECTED "connection lost"
//CTfLiteClass
#define TFLITE_MINIMAL_CHECK(x) \
if (!(x)) { \
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
exit(1); \
}
// #define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
// connect_wlan.cpp // connect_wlan.cpp
//****************************** //******************************
/* WIFI roaming functionalities 802.11k+v (uses ca. 6kB - 8kB internal RAM; if SCAN CACHE activated: + 1kB / beacon) /* WIFI roaming functionalities 802.11k+v (uses ca. 6kB - 8kB internal RAM; if SCAN CACHE activated: + 1kB / beacon)

View File

@@ -3,12 +3,6 @@
#include <vector> #include <vector>
#include <regex> #include <regex>
//#include "freertos/FreeRTOS.h"
//#include "freertos/task.h"
//#include "freertos/event_groups.h"
//#include "driver/gpio.h"
//#include "sdkconfig.h"
#include "esp_psram.h" #include "esp_psram.h"
#include "esp_pm.h" #include "esp_pm.h"
@@ -16,17 +10,13 @@
#include "esp_chip_info.h" #include "esp_chip_info.h"
// SD-Card //////////////////// // SD-Card ////////////////////
//#include "nvs_flash.h" #include "sdcard_init.h"
#include "esp_vfs_fat.h" #include "esp_vfs_fat.h"
//#include "sdmmc_cmd.h" #include "ffconf.h"
#include "driver/sdmmc_host.h" #include "driver/sdmmc_host.h"
//#include "driver/sdmmc_defs.h"
/////////////////////////////// ///////////////////////////////
#include "ClassLogFile.h" #include "ClassLogFile.h"
#include "connect_wlan.h" #include "connect_wlan.h"
@@ -38,7 +28,6 @@
#include "server_ota.h" #include "server_ota.h"
#include "time_sntp.h" #include "time_sntp.h"
#include "configFile.h" #include "configFile.h"
//#include "ClassControllCamera.h"
#include "server_main.h" #include "server_main.h"
#include "server_camera.h" #include "server_camera.h"
#ifdef ENABLE_MQTT #ifdef ENABLE_MQTT
@@ -49,7 +38,6 @@
#include "sdcard_check.h" #include "sdcard_check.h"
#include "../../include/defines.h" #include "../../include/defines.h"
//#include "server_GPIO.h"
#ifdef ENABLE_SOFTAP #ifdef ENABLE_SOFTAP
#include "softAP.h" #include "softAP.h"
@@ -101,6 +89,8 @@ bool setCpuFrequency(void);
static const char *TAG = "MAIN"; static const char *TAG = "MAIN";
#define MOUNT_POINT "/sdcard"
bool Init_NVS_SDCard() bool Init_NVS_SDCard()
{ {
@@ -112,26 +102,30 @@ bool Init_NVS_SDCard()
ESP_LOGD(TAG, "Using SDMMC peripheral"); ESP_LOGD(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT(); sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
// This initializes the slot without card detect (CD) and write protect (WP) signals. // This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// To use 1-line SD mode, uncomment the following line: // Set bus width to use:
#ifdef __SD_USE_ONE_LINE_MODE__ #ifdef __SD_USE_ONE_LINE_MODE__
slot_config.width = 1; slot_config.width = 1;
#endif #else
slot_config.width = 4;
#endif
// GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups. // Enable internal pullups on enabled pins. The internal pullups
// Internal pull-ups are not sufficient. However, enabling internal pull-ups // are insufficient however, please make sure 10k external pullups are
// does make a difference some boards, so we do that here. // connected on the bus. This is for debug / example purpose only.
gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
#ifndef __SD_USE_ONE_LINE_MODE__ // Der PullUp des GPIO13 wird durch slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only // nicht gesetzt, da er eigentlich nicht benötigt wird,
gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only // dies führt jedoch bei schlechten Kopien des AI_THINKER Boards
#endif // zu Problemen mit der SD Initialisierung und eventuell sogar zur reboot-loops.
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes // Um diese Probleme zu kompensieren, wird der PullUp manuel gesetzt.
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // HS2_D3
// Options for mounting the filesystem. // Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and // If format_if_mount_failed is set to true, SD card will be partitioned and
@@ -139,15 +133,18 @@ bool Init_NVS_SDCard()
esp_vfs_fat_sdmmc_mount_config_t mount_config = { esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false, .format_if_mount_failed = false,
.max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7 .max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
.allocation_unit_size = 16 * 1024 .allocation_unit_size = 0, // 0 = auto
.disk_status_check_enable = 0
}; };
sdmmc_card_t* card; sdmmc_card_t* card;
const char mount_point[] = MOUNT_POINT;
// Use settings defined above to initialize SD card and mount FAT filesystem. // Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function. // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
// Please check its source code and implement error recovery when developing // Please check its source code and implement error recovery when developing
// production applications. // production applications.
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card); ret = esp_vfs_fat_sdmmc_mount_mh(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) { if (ret != ESP_OK) {
if (ret == ESP_FAIL) { if (ret == ESP_FAIL) {

View File

@@ -17,6 +17,7 @@
#include "MainFlowControl.h" #include "MainFlowControl.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_chip_info.h"
#include <stdio.h> #include <stdio.h>
@@ -170,6 +171,27 @@ esp_err_t info_get_handler(httpd_req_t *req)
httpd_resp_sendstr(req, zw.c_str()); httpd_resp_sendstr(req, zw.c_str());
return ESP_OK; return ESP_OK;
} }
else if (_task.compare("ChipCores") == 0)
{
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
httpd_resp_sendstr(req, to_string(chipInfo.cores).c_str());
return ESP_OK;
}
else if (_task.compare("ChipRevision") == 0)
{
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
httpd_resp_sendstr(req, to_string(chipInfo.revision).c_str());
return ESP_OK;
}
else if (_task.compare("ChipFeatures") == 0)
{
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
httpd_resp_sendstr(req, to_string(chipInfo.features).c_str());
return ESP_OK;
}
else else
{ {
char formatted[256]; char formatted[256];

View File

@@ -19,7 +19,7 @@
[common:esp32-idf] [common:esp32-idf]
extends = common:idf extends = common:idf
platform = platformio/espressif32 @ 6.3.2 platform = platformio/espressif32 @ 6.5.0
framework = espidf framework = espidf
lib_deps = lib_deps =
${common:idf.lib_deps} ${common:idf.lib_deps}

View File

@@ -109,11 +109,6 @@ CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024 CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
CONFIG_HTTPD_PURGE_BUF_LEN=16 CONFIG_HTTPD_PURGE_BUF_LEN=16
<<<<<<< Updated upstream
=======
CONFIG_HTTPD_WS_SUPPORT=y
CONFIG_LWIP_MAX_SOCKETS=12
>>>>>>> Stashed changes
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16 CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16

View File

@@ -33,7 +33,17 @@ std::string process_doFlow(UnderTestPost* _underTestPost) {
return _underTestPost->getReadout(0); return _underTestPost->getReadout(0);
} }
/**
* @brief setup flow like it runs after recognition.
*
* @param analog the analog recognitions as array begins with the highest ROI
* @param digits the digital regocnitions as array begins with the highest ROI
* @param digType type of the model defaults do Digital100
* @param checkConsistency for Digital type only. Not relvant for newer models
* @param extendedResolution the lowest ROI will directly used (9.7 => 9.7) if false 9.7 => 9
* @param decimal_shift the decimal point offset. -3 corresponds to x.yyy
* @return std::string the value result
*/
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType, std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType,
bool checkConsistency, bool extendedResolution, int decimal_shift) { bool checkConsistency, bool extendedResolution, int decimal_shift) {
// setup the classundertest // setup the classundertest

View File

@@ -110,6 +110,8 @@ void testNegative_Issues() {
setPreValue(underTestPost, preValue_extended); setPreValue(underTestPost, preValue_extended);
std::string result = process_doFlow(underTestPost); std::string result = process_doFlow(underTestPost);
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.09 ", underTestPost->getReadoutError().c_str()); TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.09 ", underTestPost->getReadoutError().c_str());
// if negativ no result any more
TEST_ASSERT_EQUAL_STRING("", result.c_str()); TEST_ASSERT_EQUAL_STRING("", result.c_str());
delete underTestPost; delete underTestPost;

View File

@@ -138,10 +138,6 @@ void task_UnityTesting(void *pvParameter)
RUN_TEST(test_doFlowPP3); RUN_TEST(test_doFlowPP3);
printf("---------------------------------------------------------------------------\n"); printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP4); RUN_TEST(test_doFlowPP4);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP_rainman110);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP_rainman110_transition);
UNITY_END(); UNITY_END();
while(1); while(1);
@@ -153,11 +149,24 @@ void task_UnityTesting(void *pvParameter)
*/ */
extern "C" void app_main() extern "C" void app_main()
{ {
initGPIO(); initGPIO();
Init_NVS_SDCard(); Init_NVS_SDCard();
esp_log_level_set("*", ESP_LOG_DEBUG); // set all components to DEBUG level esp_log_level_set("*", ESP_LOG_ERROR); // set all components to ERROR level
// Create dedicated testing task (heap size can be configured - large enough to handle a lot of testing cases) UNITY_BEGIN();
// ******************************************** RUN_TEST(testNegative_Issues);
xTaskCreate(&task_UnityTesting, "task_UnityTesting", 12 * 1024, NULL, tskIDLE_PRIORITY+2, NULL); RUN_TEST(testNegative);
RUN_TEST(test_analogToDigit_Standard);
RUN_TEST(test_analogToDigit_Transition);
RUN_TEST(test_doFlowPP);
RUN_TEST(test_doFlowPP1);
RUN_TEST(test_doFlowPP2);
RUN_TEST(test_doFlowPP3);
RUN_TEST(test_doFlowPP4);
// getReadoutRawString test
RUN_TEST(test_getReadoutRawString);
UNITY_END();
} }

3
param-docs/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
param-docs/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
</project>

8
param-docs/.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/generate-param-docs.iml" filepath="$PROJECT_DIR$/.idea/generate-param-docs.iml" />
</modules>
</component>
</project>

6
param-docs/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

17
param-docs/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Parameter Documentation
Each parameter which is listed in the [configfile](https://github.com/jomjol/AI-on-the-edge-device/blob/rolling/sd-card/config/config.ini) has its own description page in the folder `parameter-pages` (grouped by the config sections).
Those pages can be edited as needed.
During a Github action build, those parameter pages will be used to generate the tooltips in the web interface. And they also are used to build the [Online Documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Parameters).
If you create or rename a parameter, make sure to also update its description page!
## Template Generator
The script `generate-template-param-doc-pages.py` should be run whenever a new parameter gets added to the config file.
It then checks if there is already a page for each of the parameters.
- If no page exists yet, a templated page gets generated.
- Existing pages do not get modified.
If the parameter is listed in `expert-params.txt`, an **Expert warning** will be shown.
If the parameter is listed in `hidden-in-ui.txt`, a **Note** will be shown.

View File

@@ -0,0 +1,46 @@
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

View File

@@ -0,0 +1,95 @@
"""
For each parameter which can be found in the config file,
create a markdown file with a templated content if it does not exist yet.
The files are grouped in sub folders representing the config sections.
"""
import os
import configparser
import urllib.request
configFileUrl = "https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/rolling/sd-card/config/config.ini"
parameterDocsFolder = "parameter-pages"
parameterTemplateFile = "./templates/parameter.md"
expertParameterListFile = "./expert-params.txt"
hiddenInUiParameterListFile = "./hidden-in-ui.txt"
# Fetch default config file from URL
print("Fetching %r..." % configFileUrl)
with urllib.request.urlopen(configFileUrl) as response:
content = response.read().decode("utf-8")
lines = str(content).split("\n")
for l in range(len(lines)):
lines[l] = lines[l].strip() + "\n"
if lines[l][0] == ";":
lines[l] = lines[l][1:] # Remove comment
content = "".join(lines)
# Fetch list of expert parameters
with open(expertParameterListFile) as f:
expertParameters = f.read().splitlines()
# Fetch list of parameters not available through the UI
with open(hiddenInUiParameterListFile) as f:
hiddenInUiParameters = f.read().splitlines()
config = configparser.ConfigParser(allow_no_value=True)
config.optionxform = str # Make it case-insensitive
config.read_string(content)
#shutil.rmtree(parameterDocsFolder)
if not os.path.exists(parameterDocsFolder):
os.mkdir(parameterDocsFolder)
with open(parameterTemplateFile, 'r') as parameterTemplateFileHandle:
parameterTemplate = parameterTemplateFileHandle.read()
print("For each section/parameter, check if there is already a documentation page in the folder %r..." % (os.getcwd() + "/" + parameterDocsFolder))
for section in config:
if section != "DEFAULT":
#print(section)
subFolder = parameterDocsFolder + "/" + section
if not os.path.exists(subFolder):
os.mkdir(subFolder)
for parameter in config[section]:
if not " " in parameter: # Ignore parameters with whitespaces in them (special format, not part of editable config)
value = config[section][parameter]
#print(" %s = %s" % (parameter, value))
if "main." in parameter:
parameter = parameter.replace("main.", "NUMBER.")
"""
For each config line, create a markdown file
"""
parameterDocFile = subFolder + '/' + parameter + ".md"
if not os.path.exists(parameterDocFile): # File does not exist yet, generate template
print("%r does not exit yet, generating a templated file for it" % (os.getcwd() + "/" + parameterDocFile))
with open(parameterDocFile, 'w') as paramFileHandle:
content = parameterTemplate
content = content.replace("$NAME", parameter)
content = content.replace("$DEFAULT", value)
if parameter in expertParameters:
content = content.replace("$EXPERT_PARAMETER", "!!! Warning\n This is an **Expert Parameter**! Only change it if you understand what it does!") # Note: Needs a 4 whitespace Intent!
else:
content = content.replace("$EXPERT_PARAMETER", "")
if parameter in hiddenInUiParameters:
content = content.replace("$HIDDEN_IN_UI", "!!! Note\n This parameter is not accessible through the Web Interface Configuration Page!") # Note: Needs a 4 whitespace Intent!
else:
content = content.replace("$HIDDEN_IN_UI", "")
paramFileHandle.write(content)

View File

@@ -0,0 +1,4 @@
InitialRotate
MainTopicMQTT
AutoAdjustSummertime
SetupMode

View File

@@ -0,0 +1,14 @@
# Parameter `AlignmentAlgo`
Default Value: `Default`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Algorithm used for the alignment step.
Available options:
- `Default`: Use only red color channel
- `HighAccuracy`: Use all 3 color channels (3x slower)
- `Fast`: First time use `HighAccuracy`, then only check if the image is shifted
- `Off`: Disable alignment algorithm

View File

@@ -0,0 +1,11 @@
# Parameter `FlipImageSize`
Default Value: `false`
!!! 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!
This parameter can be used to rotate the viewport together with the alignment rotation:
![](img/flipImageSize.png)

View File

@@ -0,0 +1,10 @@
# Parameter `InitialMirror`
Default Value: `false`
!!! 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!
Option for initially mirroring the image on the original x-axis.

View File

@@ -0,0 +1,12 @@
# Parameter `InitialRotate`
Default Value: `0`
Unit: Degrees
!!! 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!
Initial rotation of image before alignment in degree (`-360` .. `+360`)

View File

@@ -0,0 +1,14 @@
# Parameter `SearchFieldX`
Default Value: `20`
Unit: Pixels
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
X-size (width) in which the reference is searched.
!!! Note
Since the alignment is one of the steps using a lot of computation time,
the search field should be as small as possible.
The calculation time goes quadratic with the search field size.

View File

@@ -0,0 +1,14 @@
# Parameter `SearchFieldY`
Default Value: `20`
Unit: Pixels
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Y-size (height) in which the reference is searched.
!!! Note
Since the alignment is one of the steps using a lot of computation time,
the search field should be as small as possible.
The calculation time goes quadratic with the search field size.

View File

@@ -0,0 +1,10 @@
# Parameter `CNNGoodThreshold`
Default Value: `0.5`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
!!! Warning
This is only supported for the `ana-class100` models!

View File

@@ -0,0 +1,5 @@
# Parameter `ExtendedResolution`
!!! Warning
This parameter is unused!
Use [`NUMBER.ExtendedResolution`](../Parameters/#PostProcessing-NUMBER.ExtendedResolution) instead!

View File

@@ -0,0 +1,4 @@
# Parameter `Model`
Default Value: `/config/ana-cont_*.tflite` (See [/config/config.ini](https://github.com/jomjol/AI-on-the-edge-device/blob/master/sd-card/config/config.ini))
Path to CNN model file for image recognition. See [here](../Choosing-the-Model) for details.

View File

@@ -0,0 +1,7 @@
# Parameter `ROIImagesLocation`
Default Value: `/log/analog`
Location to store separated analog images on the SD-Card.
!!! Warning
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,6 @@
# Parameter `ROIImagesRetention`
Default Value: `3`
Unit: Days
Days to keep the separated analog images (`0` = forever).

View File

@@ -0,0 +1,12 @@
# Parameter `AutoStart`
Default Value: `true`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Automatically start the Flow (Digitization Rounds) immediately after power up.
!!! Note
Typically this is set to `true`.
The main reasons to set it to `false` is when you want to trigger it manually using the
[REST API](../REST-API) or [MQTT-API](../MQTT-API) or for debugging.

View File

@@ -0,0 +1,7 @@
# Parameter `Interval`
Default Value: `5`
Unit: Minutes
Interval in which the Flow (Digitization Round) is run.
If a round takes longer than this interval, the next round gets postponed until the current round completes.

View File

@@ -0,0 +1,6 @@
# Parameter `DataFilesRetention`
Default Value: `3`
Unit: Days
Number of days to keep the data files (`0` = forever).

View File

@@ -0,0 +1,8 @@
# Parameter `DataLogActive`
Default Value: `true`
Activate data logging to the SD-Card.
The files will be stored in `/log/data/data_YYYY-MM-DD.csv`. See [`Data Logging`](../data-logging) for details.
!!! Warning
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,16 @@
# Parameter `LogLevel`
Default Value: `1` (`ERROR`)
Define the log level for the logging to the SD-Card.
Available options:
- `1`: `ERROR`
- `2`: `WARNING`
- `3`: `INFO`
- `4`: `DEBUG`
As higher the level, as more log messages get written to the SD-Card.
!!! Warning
`DEBUG` or `INFO` might damage the SD-Card if enabled long term due to excessive writes to the SD-Card!
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,6 @@
# Parameter `LogfilesRetention`
Default Value: `3`
Unit: Days
Number of days to keep the log files (`0` = forever).

View File

@@ -0,0 +1,10 @@
# Parameter `CNNGoodThreshold`
Default Value: `0.5`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
!!! Warning
This is only supported for the `dig-class100` models!

View File

@@ -0,0 +1,4 @@
# Parameter `Model`
Default Value: `/config/dig-cont_*.tflite` (See [/config/config.ini](https://github.com/jomjol/AI-on-the-edge-device/blob/master/sd-card/config/config.ini))
Path to CNN model file for image recognition. See [here](../Choosing-the-Model) for details.

View File

@@ -0,0 +1,7 @@
# Parameter `ROIImagesLocation`
Default Value: `/log/digit`
Location to store separated digit images on the SD-Card.
!!! Warning
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,6 @@
# Parameter `ROIImagesRetention`
Default Value: `3`
Unit: Days
Days to keep the separated digit images (`0` = forever).

View File

@@ -0,0 +1,21 @@
# Parameter `IO0`
Default Value: `input disabled 10 false false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
This parameter can be used to configure the GPIO `IO0` pin.
!!! Warning
This pin is only usable with restrictions!
It must be disabled when the camera is used.
Additionally, it is used to activate Bootloader mode and must therefore be HIGH after a reset!
Parameters:
- `GPIO 0 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
- `GPIO 0 use interrupt`: Enable interrupt trigger
- `GPIO 0 PWM duty resolution`: LEDC PWM duty resolution in bit
- `GPIO 0 enable MQTT`: Enable MQTT publishing/subscribing
- `GPIO 0 enable HTTP`: Enable HTTP write/read
- `GPIO 0 name`: MQTT topic name (empty = `GPIO0`). Allowed characters: `a-z, A-Z, 0-9, _, -`.

View File

@@ -0,0 +1,19 @@
# Parameter `IO1`
Default Value: `input disabled 10 false false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
This parameter can be used to configure the GPIO `IO1` pin.
!!! Warning
This pin is by default used for the serial communication as TX pin (USB logging)!
Parameters:
- `GPIO 1 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
- `GPIO 1 use interrupt`: Enable interrupt trigger
- `GPIO 1 PWM duty resolution`: LEDC PWM duty resolution in bit
- `GPIO 1 enable MQTT`: Enable MQTT publishing/subscribing
- `GPIO 1 enable HTTP`: Enable HTTP write/read
- `GPIO 1 name`: MQTT topic name (empty = `GPIO1`). Allowed characters: `a-z, A-Z, 0-9, _, -`.

View File

@@ -0,0 +1,19 @@
# Parameter `IO12`
Default Value: `input-pullup disabled 10 false false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
This parameter can be used to configure the GPIO `IO12` pin.
!!! Note
This pin is usable without known restrictions!
Parameters:
- `GPIO 12 state`: One of `external-flash-ws281x`, `input`, `input pullup`, `input pulldown` or `output`.
- `GPIO 12 use interrupt`: Enable interrupt trigger
- `GPIO 12 PWM duty resolution`: LEDC PWM duty resolution in bit
- `GPIO 12 enable MQTT`: Enable MQTT publishing/subscribing
- `GPIO 12 enable HTTP`: Enable HTTP write/read
- `GPIO 12 name`: MQTT topic name (empty = `GPIO12`). Allowed characters: `a-z, A-Z, 0-9, _, -`.

View File

@@ -0,0 +1,19 @@
# Parameter `IO13`
Default Value: `input-pullup disabled 10 false false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
This parameter can be used to configure the GPIO `IO13` pin.
!!! Note
This pin is usable without known restrictions!
Parameters:
- `GPIO 13 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
- `GPIO 13 use interrupt`: Enable interrupt trigger
- `GPIO 13 PWM duty resolution`: LEDC PWM duty resolution in bit
- `GPIO 13 enable MQTT`: Enable MQTT publishing/subscribing
- `GPIO 13 enable HTTP`: Enable HTTP write/read
- `GPIO 13 name`: MQTT topic name (empty = `GPIO13`). Allowed characters: `a-z, A-Z, 0-9, _, -`.

View File

@@ -0,0 +1,19 @@
# Parameter `IO3`
Default Value: `input disabled 10 false false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
This parameter can be used to configure the GPIO `IO3` pin.
!!! Warning
This pin is by default used for the serial communication as RX pin (USB logging)!
Parameters:
- `GPIO 3 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
- `GPIO 3 use interrupt`: Enable interrupt trigger
- `GPIO 3 PWM duty resolution`: LEDC PWM duty resolution in bit
- `GPIO 3 enable MQTT`: Enable MQTT publishing/subscribing
- `GPIO 3 enable HTTP`: Enable HTTP write/read
- `GPIO 3 name`: MQTT topic name (empty = `GPIO3`). Allowed characters: `a-z, A-Z, 0-9, _, -`.

View File

@@ -0,0 +1,20 @@
# Parameter `IO4`
Default Value: `built-in-led disabled 10 false false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
This parameter can be used to configure the GPIO `IO4` pin.
!!! Warning
This pin is only usable with restrictions!
By default, it is used for build-in flash light (onboard LED).
Parameters:
- `GPIO 4 state`: One of `built-in-led`, `input`, `input pullup`, `input pulldown` or `output`.
- `GPIO 4 use interrupt`: Enable interrupt trigger
- `GPIO 4 PWM duty resolution`: LEDC PWM duty resolution in bit
- `GPIO 4 enable MQTT`: Enable MQTT publishing/subscribing
- `GPIO 4 enable HTTP`: Enable HTTP write/read
- `GPIO 4 name`: MQTT topic name (empty = `GPIO4`). Allowed characters: `a-z, A-Z, 0-9, _, -`.

View File

@@ -0,0 +1,5 @@
# Parameter `LEDColor`
Default Value: `150 150 150`
Color of the attached LEDs to GPIO12 in **R**ed, **G**reen **B**lue from `0` (full off) .. `255` (full on)
(See `IO12` parameter).

View File

@@ -0,0 +1,4 @@
# Parameter `LEDNumbers`
Default Value: `2`
Number of LEDs on the external LED-stripe attached to GPIO12 (See `IO12` parameter).

View File

@@ -0,0 +1,3 @@
# Parameter `LEDType`
Default Value: `WS2812`
Type of the `WS2812x` which is connected to GPIO12 (See `IO12` parameter).

View File

@@ -0,0 +1,8 @@
# Parameter `MainTopicMQTT`
Default Value: `wasserzaehler/GPIO`
!!! Note
This parameter is not accessible through the Web Interface Configuration Page!
The GPIO Interface is prepared to report it's status and status changes as a MQTT topic. With this parameter you configure the MQTT main topic, under which the status is published.
As this parameter is still experimental it can only be set manually in the `config.ini` itself and has not been tested in detail so far.

View File

@@ -0,0 +1,7 @@
# Parameter `Database`
Default Value: `''`
Name of the InfluxDB v1 Database into which to publish the values.
!!! Note
See section `InfluxDBv2` for InfluxDB v2 support!

View File

@@ -0,0 +1,4 @@
# Parameter `<NUMBER>.Field`
Default Value: `undefined`
Dedicated definition of the field for InfluxDB use for saving in the Influx database (e.g.: "watermeter/value").

View File

@@ -0,0 +1,7 @@
# Parameter `Measurement`
Default Value: `undefined`
Name of the InfluxDB v1 Measurement to use to publish the value.
!!! Note
See section `InfluxDBv2` for InfluxDB v2 support!

View File

@@ -0,0 +1,7 @@
# Parameter `Uri`
Default Value: `undefined`
URI of the HTTP interface to InfluxDB v1, without trailing slash, e.g. `http://192.168.1.1:8086`.
!!! Note
See section `InfluxDBv2` for InfluxDB v2 support!

Some files were not shown because too many files have changed in this diff Show More