From 879906abc7bb33a9053fc57f43f537390e051093 Mon Sep 17 00:00:00 2001 From: Leszek Klich Date: Thu, 7 May 2026 12:13:53 +0200 Subject: [PATCH] init --- .gitignore | 4 + .vscode/c_cpp_properties.json | 519 ++++++++++++++++++ .vscode/extensions.json | 10 + .vscode/launch.json | 44 ++ README.md | 29 +- docs/PCA9685.jpg | Bin 0 -> 71805 bytes docs/test.md | 46 ++ include/Logger.h | 15 + include/Pinout.h | 31 ++ include/Tool.h | 14 + include/Version.h | 7 + include/Watchdog.h | 38 ++ lib/ArduinoThread/.gitignore | 13 + lib/ArduinoThread/.piopm | 1 + lib/ArduinoThread/LICENSE.txt | 21 + lib/ArduinoThread/README.md | 205 +++++++ lib/ArduinoThread/StaticThreadController.h | 75 +++ lib/ArduinoThread/Thread.cpp | 52 ++ lib/ArduinoThread/Thread.h | 89 +++ lib/ArduinoThread/ThreadController.cpp | 115 ++++ lib/ArduinoThread/ThreadController.h | 53 ++ .../ControllerInController.ino | 78 +++ .../ControllerWithTimer.ino | 100 ++++ .../CustomTimedThread/CustomTimedThread.ino | 257 +++++++++ .../examples/SensorThread/SensorThread.ino | 105 ++++ .../examples/SimpleThread/SimpleThread.ino | 35 ++ .../SimpleThreadController.ino | 48 ++ .../StaticThreadController.ino | 56 ++ lib/ArduinoThread/keywords.txt | 32 ++ lib/ArduinoThread/library.json | 13 + lib/ArduinoThread/library.properties | 9 + lib/README | 4 + platformio.ini | 30 + src/Logger.cpp | 16 + src/Tool.cpp | 48 ++ src/Watchdog.cpp | 81 +++ src/main.cpp | 143 +++++ test/README | 11 + 38 files changed, 2445 insertions(+), 2 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 docs/PCA9685.jpg create mode 100644 docs/test.md create mode 100644 include/Logger.h create mode 100644 include/Pinout.h create mode 100644 include/Tool.h create mode 100644 include/Version.h create mode 100644 include/Watchdog.h create mode 100644 lib/ArduinoThread/.gitignore create mode 100644 lib/ArduinoThread/.piopm create mode 100644 lib/ArduinoThread/LICENSE.txt create mode 100644 lib/ArduinoThread/README.md create mode 100644 lib/ArduinoThread/StaticThreadController.h create mode 100644 lib/ArduinoThread/Thread.cpp create mode 100644 lib/ArduinoThread/Thread.h create mode 100644 lib/ArduinoThread/ThreadController.cpp create mode 100644 lib/ArduinoThread/ThreadController.h create mode 100644 lib/ArduinoThread/examples/ControllerInController/ControllerInController.ino create mode 100644 lib/ArduinoThread/examples/ControllerWithTimer/ControllerWithTimer.ino create mode 100644 lib/ArduinoThread/examples/CustomTimedThread/CustomTimedThread.ino create mode 100644 lib/ArduinoThread/examples/SensorThread/SensorThread.ino create mode 100644 lib/ArduinoThread/examples/SimpleThread/SimpleThread.ino create mode 100644 lib/ArduinoThread/examples/SimpleThreadController/SimpleThreadController.ino create mode 100644 lib/ArduinoThread/examples/StaticThreadController/StaticThreadController.ino create mode 100644 lib/ArduinoThread/keywords.txt create mode 100644 lib/ArduinoThread/library.json create mode 100644 lib/ArduinoThread/library.properties create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 src/Logger.cpp create mode 100644 src/Tool.cpp create mode 100644 src/Watchdog.cpp create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/.gitignore b/.gitignore index e257658..c926297 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ # Prerequisites *.d +.pio + +.DS_Store + # Compiled Object files *.slo *.lo diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..6f2b89c --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,519 @@ +// +// !!! WARNING !!! AUTO-GENERATED FILE! +// PLEASE DO NOT MODIFY IT AND USE "platformio.ini": +// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags +// +{ + "configurations": [ + { + "name": "PlatformIO", + "includePath": [ + "/Users/lklich/Programowanie/robotic_hand/include", + "/Users/lklich/Programowanie/robotic_hand/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/ESP32Servo/src", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/Adafruit PWM Servo Driver Library", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/Adafruit BusIO", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/ServoEasing/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/newlib/platform_include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/include/esp_additions/freertos", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/port/riscv/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/include/esp_additions", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/include/soc", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/include/soc/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/port/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/port/esp32c3/private_include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/heap/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/log/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/include/apps", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/include/apps/sntp", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/lwip/src/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/port/esp32/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/port/esp32/include/arch", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/soc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/soc/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/soc/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/hal/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/hal/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/hal/platform_port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rom/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rom/include/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rom/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/port/soc", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/port/include/riscv", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/port/public_compat", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/riscv/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/driver/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/driver/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_pm/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_ringbuf/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/efuse/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/efuse/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/vfs/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_wifi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_event/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_netif/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_eth/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/tcpip_adapter/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_phy/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_phy/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_ipc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/app_trace/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_timer/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mbedtls/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mbedtls/mbedtls/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mbedtls/esp_crt_bundle/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/app_update/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/spi_flash/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bootloader_support/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/nvs_flash/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/pthread/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_gdbstub/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_gdbstub/riscv", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_gdbstub/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espcoredump/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espcoredump/include/port/riscv", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wpa_supplicant/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wpa_supplicant/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wpa_supplicant/esp_supplicant/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/ieee802154/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/console", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/asio/asio/asio/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/asio/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/osi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/include/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/api/include/api", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/btc/profile/esp/blufi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/btc/profile/esp/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/host/bluedroid/api/include/api", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_core", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_core/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_core/storage", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/btc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_models/common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_models/client/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_models/server/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/api/core/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/api/models/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/api", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/cbor/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/unity/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/unity/unity/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/cmock/CMock/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/coap/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/coap/libcoap/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/nghttp/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/nghttp/nghttp2/lib/includes", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-tls", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-tls/esp-tls-crypto", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_adc_cal/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hid/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/tcp_transport/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_http_client/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_http_server/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_https_ota/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_https_server/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_lcd/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_lcd/interface", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protobuf-c/protobuf-c", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protocomm/include/common", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protocomm/include/security", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protocomm/include/transports", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mdns/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_local_ctrl/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/sdmmc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_serial_slave_link/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_websocket_client/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/expat/expat/expat/lib", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/expat/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wear_levelling/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fatfs/diskio", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fatfs/vfs", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fatfs/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freemodbus/freemodbus/common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/idf_test/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/idf_test/include/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/jsmn/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json/cJSON", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/libsodium/libsodium/src/libsodium/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/libsodium/port_include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mqtt/esp-mqtt/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/openssl/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/spiffs/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wifi_provisioning/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/rmaker_common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_diagnostics/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/rtc_store/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_insights/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json_parser/upstream/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json_parser/upstream", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json_generator/upstream", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_schedule/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp_secure_cert_mgr/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rainmaker/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/gpio_button/button/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/qrcode/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/ws2812_led", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_littlefs/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/tool", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/typedef", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/image", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/math", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/nn", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/layer", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/detect", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/model_zoo", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp32-camera/driver/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp32-camera/conversions/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/dotprod/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/support/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/support/mem/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/hann/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/blackman/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/blackman_harris/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/blackman_nuttall/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/nuttall/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/flat_top/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/iir/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/fir/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/add/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/sub/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/mul/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/addc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/mulc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/sqrt/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/mul/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/add/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/addc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/mulc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/sub/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/fft/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/dct/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/conv/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/mul/test/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/kalman/ekf/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/kalman/ekf_imu13states/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fb_gfx/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/qio_qspi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/cores/esp32", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/variants/esp32c3", + "/Users/lklich/Programowanie/robotic_hand/lib/ArduinoThread", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/FS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Insights/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/USB/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Update/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", + "" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "path": [ + "/Users/lklich/Programowanie/robotic_hand/include", + "/Users/lklich/Programowanie/robotic_hand/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/ESP32Servo/src", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/Adafruit PWM Servo Driver Library", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/Adafruit BusIO", + "/Users/lklich/Programowanie/robotic_hand/.pio/libdeps/esp32-c3-devkitm-1/ServoEasing/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/newlib/platform_include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/include/esp_additions/freertos", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/port/riscv/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freertos/include/esp_additions", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/include/soc", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/include/soc/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/port/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hw_support/port/esp32c3/private_include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/heap/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/log/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/include/apps", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/include/apps/sntp", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/lwip/src/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/port/esp32/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/lwip/port/esp32/include/arch", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/soc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/soc/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/soc/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/hal/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/hal/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/hal/platform_port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rom/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rom/include/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rom/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/port/soc", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/port/include/riscv", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_system/port/public_compat", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/riscv/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/driver/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/driver/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_pm/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_ringbuf/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/efuse/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/efuse/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/vfs/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_wifi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_event/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_netif/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_eth/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/tcpip_adapter/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_phy/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_phy/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_ipc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/app_trace/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_timer/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mbedtls/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mbedtls/mbedtls/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mbedtls/esp_crt_bundle/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/app_update/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/spi_flash/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bootloader_support/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/nvs_flash/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/pthread/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_gdbstub/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_gdbstub/riscv", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_gdbstub/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espcoredump/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espcoredump/include/port/riscv", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wpa_supplicant/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wpa_supplicant/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wpa_supplicant/esp_supplicant/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/ieee802154/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/console", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/asio/asio/asio/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/asio/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/osi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/include/esp32c3/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/api/include/api", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/btc/profile/esp/blufi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/common/btc/profile/esp/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/host/bluedroid/api/include/api", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_core", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_core/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_core/storage", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/btc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_models/common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_models/client/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/mesh_models/server/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/api/core/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/api/models/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/bt/esp_ble_mesh/api", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/cbor/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/unity/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/unity/unity/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/cmock/CMock/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/coap/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/coap/libcoap/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/nghttp/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/nghttp/nghttp2/lib/includes", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-tls", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-tls/esp-tls-crypto", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_adc_cal/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_hid/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/tcp_transport/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_http_client/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_http_server/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_https_ota/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_https_server/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_lcd/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_lcd/interface", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protobuf-c/protobuf-c", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protocomm/include/common", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protocomm/include/security", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/protocomm/include/transports", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mdns/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_local_ctrl/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/sdmmc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_serial_slave_link/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_websocket_client/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/expat/expat/expat/lib", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/expat/port/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wear_levelling/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fatfs/diskio", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fatfs/vfs", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fatfs/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/freemodbus/freemodbus/common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/idf_test/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/idf_test/include/esp32c3", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/jsmn/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json/cJSON", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/libsodium/libsodium/src/libsodium/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/libsodium/port_include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/mqtt/esp-mqtt/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/openssl/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/spiffs/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/wifi_provisioning/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/rmaker_common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_diagnostics/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/rtc_store/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_insights/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json_parser/upstream/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json_parser/upstream", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/json_generator/upstream", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_schedule/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp_secure_cert_mgr/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_rainmaker/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/gpio_button/button/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/qrcode/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/ws2812_led", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp_littlefs/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/tool", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/typedef", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/image", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/math", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/nn", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/layer", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/detect", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp-dl/include/model_zoo", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp32-camera/driver/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/esp32-camera/conversions/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/dotprod/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/support/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/support/mem/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/hann/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/blackman/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/blackman_harris/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/blackman_nuttall/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/nuttall/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/windows/flat_top/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/iir/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/fir/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/add/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/sub/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/mul/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/addc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/mulc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/math/sqrt/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/mul/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/add/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/addc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/mulc/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/sub/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/fft/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/dct/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/conv/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/common/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/matrix/mul/test/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/kalman/ekf/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/espressif__esp-dsp/modules/kalman/ekf_imu13states/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/include/fb_gfx/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32c3/qio_qspi/include", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/cores/esp32", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/variants/esp32c3", + "/Users/lklich/Programowanie/robotic_hand/lib/ArduinoThread", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/FS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Insights/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/USB/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/Update/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", + "/Users/lklich/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", + "" + ] + }, + "defines": [ + "PLATFORMIO=60119", + "ARDUINO_ESP32C3_DEV", + "ARDUINO_USB_MODE=1", + "ARDUINO_USB_CDC_ON_BOOT=1", + "CORE_DEBUG_LEVEL=3", + "LOG_LOCAL_LEVEL=ESP_LOG_INFO", + "HAVE_CONFIG_H", + "MBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"", + "UNITY_INCLUDE_CONFIG_H", + "WITH_POSIX", + "_GNU_SOURCE", + "IDF_VER=\"v4.4.7-dirty\"", + "ESP_PLATFORM", + "_POSIX_READER_WRITER_LOCKS", + "ARDUINO_ARCH_ESP32", + "ESP32", + "F_CPU=160000000L", + "ARDUINO=10812", + "ARDUINO_VARIANT=\"esp32c3\"", + "ARDUINO_BOARD=\"Espressif ESP32-C3-DevKitM-1\"", + "ARDUINO_PARTITION_default", + "" + ], + "cStandard": "gnu99", + "cppStandard": "gnu++11", + "compilerPath": "/Users/lklich/.platformio/packages/toolchain-riscv32-esp/bin/riscv32-esp-elf-gcc", + "compilerArgs": [ + "-march=rv32imc", + "" + ] + } + ], + "version": 4 +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..20bde60 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,44 @@ +// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY +// +// PlatformIO Debugging Solution +// +// Documentation: https://docs.platformio.org/en/latest/plus/debugging.html +// Configuration: https://docs.platformio.org/en/latest/projectconf/sections/env/options/debug/index.html + +{ + "version": "0.2.0", + "configurations": [ + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug", + "executable": "/Users/lklich/Programowanie/robotic_hand/.pio/build/esp32-c3-devkitm-1/firmware.elf", + "projectEnvName": "esp32-c3-devkitm-1", + "toolchainBinDir": "/Users/lklich/.platformio/packages/toolchain-riscv32-esp/bin", + "internalConsoleOptions": "openOnSessionStart", + "preLaunchTask": { + "type": "PlatformIO", + "task": "Pre-Debug" + } + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (skip Pre-Debug)", + "executable": "/Users/lklich/Programowanie/robotic_hand/.pio/build/esp32-c3-devkitm-1/firmware.elf", + "projectEnvName": "esp32-c3-devkitm-1", + "toolchainBinDir": "/Users/lklich/.platformio/packages/toolchain-riscv32-esp/bin", + "internalConsoleOptions": "openOnSessionStart" + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (without uploading)", + "executable": "/Users/lklich/Programowanie/robotic_hand/.pio/build/esp32-c3-devkitm-1/firmware.elf", + "projectEnvName": "esp32-c3-devkitm-1", + "toolchainBinDir": "/Users/lklich/.platformio/packages/toolchain-riscv32-esp/bin", + "internalConsoleOptions": "openOnSessionStart", + "loadMode": "manual" + } + ] +} diff --git a/README.md b/README.md index 37b4245..6baecf8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ -# robotic_hand +# Robotyczna dłoń + +Ręka robotyczna - oprogramowanie mikrokontrolera + +## Podłączenie sterownika PCA9685 do ESP32-S3 + + +| ![Opis](docs/PCA9685.jpg) | +|:--:| +| **Rysunek 1.** Moduł sterowania serwomechanizmami | + + +* PCA9685 Supermini Uwagi +* VCC 3.3V Zasilanie logiki układu PCA +* GND, GND, Wspólna masa +* SDA, GPIO 8, Linia danych I2C +* SCL, GPIO 9, Linia zegarowa I2C +* V+, Zewnętrzne 5V-6V, Zasilanie serwomechanizmów z zewnętrznej przetwornicy 5V + + +## Podłączenie kolejności palców +* Kanał (PCA9685),Palec +* 0, Kciuk +* 1, Wskazujący +* 2, Środkowy +* 3, Serdeczny +* 4, Mały -Ręka robotyczna - oprogramowanie mikrokontrolera \ No newline at end of file diff --git a/docs/PCA9685.jpg b/docs/PCA9685.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f04b3536a4189182fd8aed94caed8262df06c01a GIT binary patch literal 71805 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

-cx(85do#lW$q$XYQ}4QbW{ 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 K5V0YDPygBLNkz~A literal 0 HcmV?d00001 diff --git a/docs/test.md b/docs/test.md new file mode 100644 index 0000000..afbff85 --- /dev/null +++ b/docs/test.md @@ -0,0 +1,46 @@ +``` +#include +#include +#include +#include +#include +#include + +Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); + +uint licznik=1; + +void setup() { + Serial.begin(115200); + delay(2000); + Serial.println("--- TEST KANAŁÓW PCA9685 ---"); + + Wire.begin(PIN_SDA, PIN_SCL); + pwm.begin(); + pwm.setPWMFreq(50); + + Serial.println("Rozpoczynam sekwencję testową..."); +} + +void loop() { + // Sprawdzamy pierwsze 8 kanałów (większość rąk ma 5 lub 6) + for (int channel = 0; channel < 5; channel++) { + Serial.print("Testuję kanał nr: "); + Serial.println(channel); + + // Ruch w jedną stronę + pwm.setPWM(channel, 0, 150); + delay(800); + + // Ruch w drugą stronę + pwm.setPWM(channel, 0, 500); + delay(800); + + // Krótka pauza przed następnym palcem + delay(500); + } + + Serial.println("Koniec cyklu. Powtarzam..."); + delay(2000); +} +``` diff --git a/include/Logger.h b/include/Logger.h new file mode 100644 index 0000000..3b57368 --- /dev/null +++ b/include/Logger.h @@ -0,0 +1,15 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include "esp_log.h" + +// Wszystkie tagi logowania w jednym miejscu +extern const char *TAG_MAIN; +extern const char *TAG_DISP; +extern const char *TAG_ADXL; +extern const char *TAG_CONF; + +// Funkcja inicjalizacji poziomów logowania +void init_log_levels(); + +#endif diff --git a/include/Pinout.h b/include/Pinout.h new file mode 100644 index 0000000..cf61899 --- /dev/null +++ b/include/Pinout.h @@ -0,0 +1,31 @@ +#pragma once + +#if defined(ESP32) +// SPI3 (HSPI) - SD Card nie kolidują z PSRAM +// #define SD_SCK 16 // 36 //18 +// #define SD_MOSI 17 // 35 //17 +// #define SD_MISO 18 // 37 //16 +// #define SD_CS 15 // 34 //15 ?? 34 + +// SPI2 (VSPI) - ADXL345 +// #define MOSI_ADSX 11 // SDA +// #define CLK_ADSX 12 // SCL +// #define MISO_ADSX 13 // SDO + +//I2C C3 +#define PIN_SDA 8 +#define PIN_SCL 9 + + +// Przycisk +// #define BTN_UP 5 +// #define BTN_OK 6 +// #define BTN_DOWN 7 + +// Przekaźnik +// #define RELAY_OUT 4 + + +#endif + + diff --git a/include/Tool.h b/include/Tool.h new file mode 100644 index 0000000..97d39ee --- /dev/null +++ b/include/Tool.h @@ -0,0 +1,14 @@ +#ifndef TOOL_H +#define TOOL_H + +#include +#include +#include "esp_log.h" +#include "Watchdog.h" + +void scanI2C(); + +/* Funkcja przyjmuje adres jako argument i zwraca true gdy urządzenie odpowiada, w przeciwnym wypadku false */ +bool isI2CDevPresent(uint8_t address); + +#endif diff --git a/include/Version.h b/include/Version.h new file mode 100644 index 0000000..6b5da75 --- /dev/null +++ b/include/Version.h @@ -0,0 +1,7 @@ +#ifndef VERSION_H +#define VERSION_H + +#define VERSION "0.1" + + +#endif \ No newline at end of file diff --git a/include/Watchdog.h b/include/Watchdog.h new file mode 100644 index 0000000..992bdb4 --- /dev/null +++ b/include/Watchdog.h @@ -0,0 +1,38 @@ +#pragma once +/** + * Watchdog — prosty interfejs do inicjalizacji i karmienia WDT z dowolnego modułu. + * + * Obsługiwane środowiska: + * - ESP32 Arduino Core / ESP-IDF (esp_task_wdt) + * - Fallback: no-op na innych platformach + * + * Użycie: + * Watchdog::init(5, true); + * Watchdog::addThisTask(); + * ... + * Watchdog::feed(); + */ + +#include + +namespace Watchdog { + +/** Inicjalizacja Task Watchdog (idempotentna). */ +bool init(int timeout_seconds = 5, bool panic_on_trigger = true); + +/** Dodaje bieżący task (wątki FreeRTOS: wołaj w ciele tego taska). */ +bool addThisTask(); + +/** Usuwa bieżący task z nadzoru WDT. */ +bool removeThisTask(); + +/** Karmi watchdog (reset licznika). */ +void feed(); + +/** Zmienia timeout (wykonuje re-init wewnętrznie, jeśli trzeba). */ +bool setTimeout(int timeout_seconds); + +/** Czy watchdog jest aktywny (zainicjalizowany)? */ +bool isActive(); + +} // namespace Watchdog diff --git a/lib/ArduinoThread/.gitignore b/lib/ArduinoThread/.gitignore new file mode 100644 index 0000000..620d3dc --- /dev/null +++ b/lib/ArduinoThread/.gitignore @@ -0,0 +1,13 @@ +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so +*.dylib + +# Compiled Static libraries +*.lai +*.la +*.a diff --git a/lib/ArduinoThread/.piopm b/lib/ArduinoThread/.piopm new file mode 100644 index 0000000..31954f3 --- /dev/null +++ b/lib/ArduinoThread/.piopm @@ -0,0 +1 @@ +{"type": "library", "name": "ArduinoThread", "version": "2.1.1", "spec": {"owner": "ivanseidel", "id": 7097, "name": "ArduinoThread", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/lib/ArduinoThread/LICENSE.txt b/lib/ArduinoThread/LICENSE.txt new file mode 100644 index 0000000..5c02604 --- /dev/null +++ b/lib/ArduinoThread/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Ivan Seidel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/ArduinoThread/README.md b/lib/ArduinoThread/README.md new file mode 100644 index 0000000..bca7ee5 --- /dev/null +++ b/lib/ArduinoThread/README.md @@ -0,0 +1,205 @@ +![ArduinoThread Logo](https://raw.githubusercontent.com/ivanseidel/ArduinoThread/master/extras/ArduinoThread.png) + +Arduino does not support "REAL" parallel tasks (aka Threads), but we can make use of this Library to +improve our code, and easily schedule tasks with fixed (or variable) time between runs. + +This Library helps to maintain organized and to facilitate the use of multiple tasks. We can +use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks under the rug. + +For example, I personaly use it for all my projects, and put all sensor aquisition and +filtering inside it, leaving the main loop, just for logic and "cool" part. + +#### ArduinoThreads is a library for managing the periodic execution of multiple tasks. + +Blinking an LED is often the very first thing an Arduino user learns. And this demonstrates that periodically performing one single task, like toggling the LED state, is really easy. However, one may quickly discover that managing multiple periodic tasks is not so simple if the tasks have different execution periods. + +ArduinoThreads is designed to simplify programs that need to perform multiple periodic tasks. The user defines a Thread object for each of those tasks, then lets the library manage their scheduled execution. + +It should be noted that these are not “threads” in the real computer-science meaning of the term: tasks are implemented as functions that are periodically run to completion. On the one hand, this means that the only way a task can “yield” the CPU is by returning to the caller, and it is thus inadvisable to delay() or do long waits inside a task. On the other hand, this makes ArduinoThreads memory friendly, as no stack needs to be allocated per task. + +## Installation + +1. "Download":https://github.com/ivanseidel/ArduinoThread/archive/master.zip the Master branch from gitHub. +2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master') +3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software). +4. Restart Arduino IDE + +**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.** + + +## Getting Started + +There are many examples showing many ways to use it. Here, we will explain Class itself, +what it does and "how" it does. + +There are basicaly, three Classes included in this Library: +`Thread`, `ThreadController` and `StaticThreadController` (both controllers inherit from Thread). + +- `Thread class`: This is the basic class, witch contains methods to set and run callbacks, + check if the Thread should be runned, and also creates a unique ThreadID on the instantiation. + +- `ThreadController class`: Responsable for "holding" multiple Threads. Can also be called + as "a group of Threads", and is used to perform run in every Thread ONLY when needed. + +- `StaticThreadController class`: Slighly faster and smaller version of `ThreadController`. + It works similar to `ThreadController`, but once constructed it can't add or remove threads to run. + +* The instantiation of a Thread class is very simple: + +```c++ +Thread myThread = Thread(); +// or, if initializing a pointer +Thread* myThread = new Thread(); +``` + + +* Setting up a thread is essential. You can configure many things: + +```c++ +myThread.enabled = true; // Default enabled value is true +myThread.setInterval(10); // Setts the wanted interval to be 10ms +/* + This is useful for debugging + (Thread Name is disabled by default, to use less memory) + (Enable it by definint USE_THREAD_NAMES on 'Thread.h') +*/ +myThread.ThreadName = "myThread tag"; +// This will set the callback of the Thread: "What should I run"? +myThread.onRun(callback_function); // callback_function is the name of the function +``` + +Ok, creating Threads are not so hard. But what do we do with them now? + +* First, let's see how Threads should work, to understand what a `ThreadController` is and does + +```c++ +// First check if our Thread "should" be runned +if(myThread.shouldRun()){ + // Yes, the Thread should be runned, let's run it + myThread.run(); +} +``` + +Now that you got the idea, let's think a little bit: What if i have 3, 5, 100 Threads. Do I need to check EACH one?!? + +* The answer is: NO. Create a `ThreadController` or `StaticThreadController`, +and put all your boring-complex Threads inside it! + +```c++ +// Instantiate a new ThreadController +ThreadController controller = ThreadController(); +// Now, put a bunch of Threads inside it, FEED it! +controller.add(&myThread); // Notice the & before the thread, IF it's not instantied as a pointer. +controller.add(&hisThread); +controller.add(&sensorReadings); +... +``` +or +```c++ +// Instantiate a new StaticThreadController with the number of threads to be supplied as template parameter +StaticThreadController<3> controller (&myThread, &hisThread, &sensorReadings); +// You don't need to do anything else, controller now contains all the threads. +... +``` + +* You have created, configured, grouped it. What is missing? Yes, whe should RUN it! + +```c++ +// call run on a Thread, a ThreadController or a StaticThreadController to run it +controller.run(); +``` + +This will run all the Threads that NEED to be runned. + +Congratulations, you have learned the basics of `ArduinoThread`. If you want some TIPS, see bellow. + + +### TIPs and Warnings + +* ThreadController is not a `LinkedList`. It's "MAXIMUM" size (the maximum Threads that it can + store) is defined on ThreadController.h (default is 15) + +* !!!! VERY IMPORTANT !!!! When extending `Thread` class and implementing the function + `run()`, always remember to put `runned();` after all, otherwhise the `Thread` will ALWAYS run. + +* It's a good idea, to create a Timer interrupt and call a ThreadController.run() there. +That way, you don't need to worry about reading sensors and doing time-sensitive stuff +on your main code (loop). Check `ControllerWithTimer` example. + +* Inheriting from `Thread` or even `ThreadController` is always a good idea. +For example, I always create base classes of sensors that extends `Thread`, +so that I can "register" the sensors inside a ThreadController, and forget +about really reading sensors, just getting theirs values within my main code. +Checkout `SensorThread` example. + +* Remember that `ThreadController` is in fact, a Thread. If you want to enable +or disable a GROUP of Threads, think about putting all of them inside a ThreadController, +and adding this ThreadController to another ThreadController (YES! One ThreadController +inside another). Check `ControllerInController` example. + +* There is a `StaticThreadController` which is better to use when you know exact number of +threads to run. You cannot add or remove threads in runtime, but `StaticThreadController` +doesn't have additional memory overhead to keep all the treads together, doesn't have any +limitations how many threads to store (except of available memory) and also the code may be slighly +more optimized because all the threads always exist and no need to do any runtime checks. + +* Check the full example `CustomTimedThread` for a cool application of Threads that runs +for a period, after a button is pressed. + +* Running tasks on the Timer interrupts must be tought REALLY carefully + + You cannot use "sleep()" inside a interrupt, because it will get into a infinite loop. + + Things must do stuff quickly. Waiting too loooong on a interrupt, means waiting too + loooong on the main code (loop) + + Things might get "scrambled". Since Timers interrupts actualy "BREAK" your code in half + and start running the interrupt, you might want to call `noInterrupts` and `interrupts` + on places where cannot be interrupted: + +```c++ +noInterrupts(); +// Put the code that CANNOT be interrupted... +interrupts(); // This will enable the interrupts egain. DO NOT FORGET! +``` + + +## Library Reference + +### You should know: + +- `bool Thread::enabled` - Enables or disables the Thread. (do not stop it from running, but will + return false when shouldRun() is called) +- `void Thread::setInterval()` - Setts the desired interval for the Thread (in Ms). +- `bool Thread::shouldRun()` - Returns true, if the Thread should be runned. + (Basicaly,the logic is: (reached time AND is enabled?). +- `void Thread::onRun()` - The target callback function to be called. +- `void Thread::run()` - This will run the Thread (call the callback function). +- `int Thread::ThreadID` - Theoretically, it's the address of memory. It's unique, and can + be used to compare if two threads are identical. +- `int Thread::ThreadName` - A human-redable thread name. Default is "Thread ThreadID" + eg.: "Thread 141515"; Note that to enable this attribute, you must uncomment the line that disables it on 'Thread.h'; +- protected: `void Thread::runned()` - Used to reset internal timer of the Thread. + This is automaticaly called AFTER a call to `run()`. + + +- `void ThreadController::run()` - This will run the all `Threads` within the `ThreadController`, + only if needed (if shouldRun returns true); +- `bool ThreadController::add(Thread* _thread)` - This will add a the thread to the ThreadController, + and return `true` if suceeded (it the array is full, returns false). +- `void ThreadController::remove(Thread* _thread)` - This will remove the Thread from the ThreadController. +- `void ThreadController::remove(int index)` - This will remove the thread on the position `index`. +- `void ThreadController::clear()` - This will remove ALL threads from the ThreadController array. +- `int ThreadController::size(bool cached = true)` - Returns how many Threads are allocated + inside the ThreadController. If cached is `false`, will force the calculation of threads. +- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index`. + + +- `void StaticThreadController::run()` - This will run the all `Threads` within the `StaicThreadController`, + only if needed (if shouldRun returns true); +- `int StaticThreadController::size()` - Returns how many Threads are allocated inside the StaticThreadController. +- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index` and `nullptr` if `index` + is out of bounds. + +### You don't need to know: +- Nothing, yet ;) diff --git a/lib/ArduinoThread/StaticThreadController.h b/lib/ArduinoThread/StaticThreadController.h new file mode 100644 index 0000000..6e316ea --- /dev/null +++ b/lib/ArduinoThread/StaticThreadController.h @@ -0,0 +1,75 @@ +/* + StaticThreadController.h - Controlls a list of Threads with different timings + + Basicaly, what it does is to keep track of current Threads and run when + necessary. + + StaticThreadController is an extended class of Thread, because of that, + it allows you to add a StaticThreadController inside another kind of ThreadController... + + It works exact as ThreadController except you can't add or remove treads dynamically. + + Created by Alex Eremin, September, 2016. + Released into the public domain. +*/ + +#ifndef StaticThreadController_h +#define StaticThreadController_h + +#include "Thread.h" + +template +class StaticThreadController: public Thread{ +protected: + //since this is a static controller, the pointers themselves can be const + //it should be distinguished from 'const Thread* thread[N]' + Thread * const thread[N]; +public: + template + StaticThreadController(T... params) : + Thread(), + thread{params...} + { + #ifdef USE_THREAD_NAMES + // Overrides name + ThreadName = "StaticThreadController "; + ThreadName = ThreadName + ThreadID; + #endif + }; + + // run() Method is overrided + void run() override + { + // Run this thread before + if(_onRun != nullptr && shouldRun()) + _onRun(); + + for(int i = 0; i < N; i++){ + // Is enabled? Timeout exceeded? + if(thread[i]->shouldRun()){ + thread[i]->run(); + } + } + + // StaticThreadController extends Thread, so we should flag as runned thread + runned(); + } + + // Return the quantity of Threads + static constexpr int size() { return N; }; + + // Return the I Thread on the array + // Returns nullptr if index is out of bounds + Thread* get(int index) { + return (index >= 0 && index < N) ? thread[index] : nullptr; + }; + + // Return the I Thread on the array + // Doesn't perform any bounds checks and behaviour is + // unpredictable in case of index > N + Thread& operator[](int index) { + return *thread[index]; + }; +}; + +#endif diff --git a/lib/ArduinoThread/Thread.cpp b/lib/ArduinoThread/Thread.cpp new file mode 100644 index 0000000..cd29d98 --- /dev/null +++ b/lib/ArduinoThread/Thread.cpp @@ -0,0 +1,52 @@ +#include "Thread.h" + +Thread::Thread(void (*callback)(void), unsigned long _interval){ + enabled = true; + onRun(callback); + _cached_next_run = 0; + last_run = millis(); + + ThreadID = (int)this; + #ifdef USE_THREAD_NAMES + ThreadName = "Thread "; + ThreadName = ThreadName + ThreadID; + #endif + + setInterval(_interval); +}; + +void Thread::runned(unsigned long time){ + // Saves last_run + last_run = time; + + // Cache next run + _cached_next_run = last_run + interval; +} + +void Thread::setInterval(unsigned long _interval){ + // Save interval + interval = _interval; + + // Cache the next run based on the last_run + _cached_next_run = last_run + interval; +} + +bool Thread::shouldRun(unsigned long time){ + // If the "sign" bit is set the signed difference would be negative + bool time_remaining = (time - _cached_next_run) & 0x80000000; + + // Exceeded the time limit, AND is enabled? Then should run... + return !time_remaining && enabled; +} + +void Thread::onRun(void (*callback)(void)){ + _onRun = callback; +} + +void Thread::run(){ + if(_onRun != NULL) + _onRun(); + + // Update last_run and _cached_next_run + runned(); +} diff --git a/lib/ArduinoThread/Thread.h b/lib/ArduinoThread/Thread.h new file mode 100644 index 0000000..0e580a9 --- /dev/null +++ b/lib/ArduinoThread/Thread.h @@ -0,0 +1,89 @@ +/* + Thread.h - An runnable object + + Thread is responsable for holding the "action" for something, + also, it responds if it "should" or "should not" run, based on + the current time; + + For instructions, go to https://github.com/ivanseidel/ArduinoThread + + Created by Ivan Seidel Gomes, March, 2013. + Released into the public domain. +*/ + +#ifndef Thread_h +#define Thread_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include +#else + #include +#endif + +#include + +/* + Uncomment this line to enable ThreadName Strings. + + It might be usefull if you are loging thread with Serial, + or displaying a list of threads... +*/ +// #define USE_THREAD_NAMES 1 + +class Thread{ +protected: + // Desired interval between runs + unsigned long interval; + + // Last runned time in Ms + unsigned long last_run; + + // Scheduled run in Ms (MUST BE CACHED) + unsigned long _cached_next_run; + + /* + IMPORTANT! Run after all calls to run() + Updates last_run and cache next run. + NOTE: This MUST be called if extending + this class and implementing run() method + */ + void runned(unsigned long time); + + // Default is to mark it runned "now" + void runned() { runned(millis()); } + + // Callback for run() if not implemented + void (*_onRun)(void); + +public: + + // If the current Thread is enabled or not + bool enabled; + + // ID of the Thread (initialized from memory adr.) + int ThreadID; + + #ifdef USE_THREAD_NAMES + // Thread Name (used for better UI). + String ThreadName; + #endif + + Thread(void (*callback)(void) = NULL, unsigned long _interval = 0); + + // Set the desired interval for calls, and update _cached_next_run + virtual void setInterval(unsigned long _interval); + + // Return if the Thread should be runned or not + virtual bool shouldRun(unsigned long time); + + // Default is to check whether it should run "now" + bool shouldRun() { return shouldRun(millis()); } + + // Callback set + void onRun(void (*callback)(void)); + + // Runs Thread + virtual void run(); +}; + +#endif diff --git a/lib/ArduinoThread/ThreadController.cpp b/lib/ArduinoThread/ThreadController.cpp new file mode 100644 index 0000000..af5f1d9 --- /dev/null +++ b/lib/ArduinoThread/ThreadController.cpp @@ -0,0 +1,115 @@ +#include "Thread.h" +#include "ThreadController.h" + +ThreadController::ThreadController(unsigned long _interval): Thread(){ + cached_size = 0; + + clear(); + setInterval(_interval); + + #ifdef USE_THREAD_NAMES + // Overrides name + ThreadName = "ThreadController "; + ThreadName = ThreadName + ThreadID; + #endif +} + +/* + ThreadController run() (cool stuf) +*/ +void ThreadController::run(){ + // Run this thread before + if(_onRun != NULL) + _onRun(); + + unsigned long time = millis(); + int checks = 0; + for(int i = 0; i < MAX_THREADS && checks <= cached_size; i++){ + // Object exists? Is enabled? Timeout exceeded? + if(thread[i]){ + checks++; + if(thread[i]->shouldRun(time)){ + thread[i]->run(); + } + } + } + + // ThreadController extends Thread, so we should flag as runned thread + runned(); +} + + +/* + List controller (boring part) +*/ +bool ThreadController::add(Thread* _thread){ + // Check if the Thread already exists on the array + for(int i = 0; i < MAX_THREADS; i++){ + if(thread[i] != NULL && thread[i]->ThreadID == _thread->ThreadID) + return true; + } + + // Find an empty slot + for(int i = 0; i < MAX_THREADS; i++){ + if(!thread[i]){ + // Found a empty slot, now add Thread + thread[i] = _thread; + cached_size++; + return true; + } + } + + // Array is full + return false; +} + +void ThreadController::remove(int id){ + // Find Threads with the id, and removes + bool found = false; + for(int i = 0; i < MAX_THREADS; i++){ + if(thread[i]->ThreadID == id){ + thread[i] = NULL; + cached_size--; + return; + } + } +} + +void ThreadController::remove(Thread* _thread){ + remove(_thread->ThreadID); +} + +void ThreadController::clear(){ + for(int i = 0; i < MAX_THREADS; i++){ + thread[i] = NULL; + } + cached_size = 0; +} + +int ThreadController::size(bool cached){ + if(cached) + return cached_size; + + int size = 0; + for(int i = 0; i < MAX_THREADS; i++){ + if(thread[i]) + size++; + } + cached_size = size; + + return cached_size; +} + +Thread* ThreadController::get(int index){ + int pos = -1; + for(int i = 0; i < MAX_THREADS; i++){ + if(thread[i] != NULL){ + pos++; + + if(pos == index) + return thread[i]; + } + } + + return NULL; +} diff --git a/lib/ArduinoThread/ThreadController.h b/lib/ArduinoThread/ThreadController.h new file mode 100644 index 0000000..8e2888c --- /dev/null +++ b/lib/ArduinoThread/ThreadController.h @@ -0,0 +1,53 @@ +/* + ThreadController.h - Controlls a list of Threads with different timings + + Basicaly, what it does is to keep track of current Threads and run when + necessary. + + ThreadController is an extended class of Thread, because of that, + it allows you to add a ThreadController inside another ThreadController... + + For instructions, go to https://github.com/ivanseidel/ArduinoThread + + Created by Ivan Seidel Gomes, March, 2013. + Released into the public domain. +*/ + +#ifndef ThreadController_h +#define ThreadController_h + +#include "Thread.h" +#include "inttypes.h" + +#define MAX_THREADS 15 + +class ThreadController: public Thread{ +protected: + Thread* thread[MAX_THREADS]; + int cached_size; +public: + ThreadController(unsigned long _interval = 0); + + // run() Method is overrided + void run(); + + // Adds a thread in the first available slot (remove first) + // Returns if the Thread could be added or not + bool add(Thread* _thread); + + // remove the thread (given the Thread* or ThreadID) + void remove(int _id); + void remove(Thread* _thread); + + // Removes all threads + void clear(); + + // Return the quantity of Threads + int size(bool cached = true); + + // Return the I Thread on the array + // Returns NULL if none found + Thread* get(int index); +}; + +#endif diff --git a/lib/ArduinoThread/examples/ControllerInController/ControllerInController.ino b/lib/ArduinoThread/examples/ControllerInController/ControllerInController.ino new file mode 100644 index 0000000..feb8a0a --- /dev/null +++ b/lib/ArduinoThread/examples/ControllerInController/ControllerInController.ino @@ -0,0 +1,78 @@ +#include +#include + +int ledPin = 13; + +// ThreadController that will controll all threads +ThreadController controll = ThreadController(); + +//My Thread +Thread myThread = Thread(); +//His Thread +Thread hisThread = Thread(); +//Blink Led Thread +Thread blinkLedThread = Thread(); +//ThreadController, that will be added to controll +ThreadController groupOfThreads = ThreadController(); + +// callback for myThread +void niceCallback(){ + Serial.print("COOL! I'm running on: "); + Serial.println(millis()); +} + +// callback for hisThread +void boringCallback(){ + Serial.println("BORING..."); +} + +// callback for blinkLedThread +void blinkLed(){ + static bool ledStatus = false; + ledStatus = !ledStatus; + + digitalWrite(ledPin, ledStatus); + + Serial.print("blinking: "); + Serial.println(ledStatus); +} + +void setup(){ + Serial.begin(9600); + + pinMode(ledPin, OUTPUT); + + // Configure myThread + myThread.onRun(niceCallback); + myThread.setInterval(500); + + // Configure hisThread + hisThread.onRun(boringCallback); + hisThread.setInterval(250); + + // Configure blinkLedThread + blinkLedThread.onRun(blinkLed); + blinkLedThread.setInterval(100); + + // Adds myThread to the controll + controll.add(&myThread); + + // Adds hisThread and blinkLedThread to groupOfThreads + groupOfThreads.add(&hisThread); + groupOfThreads.add(&blinkLedThread); + + // Add groupOfThreads to controll + controll.add(&groupOfThreads); + +} + +void loop(){ + // run ThreadController + // this will check every thread inside ThreadController, + // if it should run. If yes, he will run it; + controll.run(); + + // Rest of code + float h = 3.1415; + h/=2; +} \ No newline at end of file diff --git a/lib/ArduinoThread/examples/ControllerWithTimer/ControllerWithTimer.ino b/lib/ArduinoThread/examples/ControllerWithTimer/ControllerWithTimer.ino new file mode 100644 index 0000000..029507f --- /dev/null +++ b/lib/ArduinoThread/examples/ControllerWithTimer/ControllerWithTimer.ino @@ -0,0 +1,100 @@ +#include +#include + +/* + This example, requires a Timer Interrupt Library. + If you are using Arduino NANO, UNO... (with ATmega168/328) + Please go to: http://playground.arduino.cc/code/timer1 + If you are using Arduino DUE, + Please go to: https://github.com/ivanseidel/DueTimer + + Include the library corresponding to your Arduino. +*/ +// #include +// #include + +// ThreadController that will controll all threads +ThreadController controll = ThreadController(); + +//My Thread +Thread myThread = Thread(); +//His Thread +Thread hisThread = Thread(); + +// callback for myThread +void myThreadCallback(){ + Serial.println("myThread\t\tcallback"); +} + +// callback for hisThread +void hisThreadCallback(){ + Serial.println("\thisThread\tcallback"); +} + +// This is the callback for the Timer +void timerCallback(){ + controll.run(); +} + +void setup(){ + Serial.begin(9600); + + // Configure myThread + myThread.onRun(myThreadCallback); + myThread.setInterval(500); + + // Configure myThread + hisThread.onRun(hisThreadCallback); + hisThread.setInterval(200); + + // Adds both threads to the controller + controll.add(&myThread); // & to pass the pointer to it + controll.add(&hisThread); + + /* + If using DueTimer... + */ + // Timer1.attachInterrupt(timerCallback).start(20000); + + /* + If using TimerOne... + */ + // Timer1.initialize(20000); + // Timer1.attachInterrupt(timerCallback); + // Timer1.start(); +} + +void waitSerial(){ + while (!Serial.available()); + delay(10); + while (Serial.available() && Serial.read()); +} + +void loop(){ + while(1){ + noInterrupts(); // Call to disable interrupts + Serial.println("Type anyting to stop myThread!"); + interrupts(); // Call to enable interrupts + waitSerial(); + myThread.enabled = false; + + noInterrupts(); + Serial.println("Type anyting to stop hisThread!"); + interrupts(); + waitSerial(); + hisThread.enabled = false; + + noInterrupts(); + Serial.println("Type anyting to enable myThread!"); + interrupts(); + waitSerial(); + myThread.enabled = true; + + noInterrupts(); + Serial.println("Type anyting to enable hisThread!"); + interrupts(); + waitSerial(); + hisThread.enabled = true; + + } +} \ No newline at end of file diff --git a/lib/ArduinoThread/examples/CustomTimedThread/CustomTimedThread.ino b/lib/ArduinoThread/examples/CustomTimedThread/CustomTimedThread.ino new file mode 100644 index 0000000..9d2d7d8 --- /dev/null +++ b/lib/ArduinoThread/examples/CustomTimedThread/CustomTimedThread.ino @@ -0,0 +1,257 @@ +/* + This is an example from ArduinoThread. You can find more information + in https://github.com/ivanseidel/ArduinoThread. + + Coded by Ivan Seidel, Jun/2014 - ivanseidel@gmail.com + + Dont be afraid. 90% is commented lines. READ them, they will teach you. +*/ + +#include +#include + +/* + This example provides an object-oriented approach to + develop a custom Thread that overrides the 'shouldRun' + method, to only run the thread after a button was pushed. + + After the push, it should 'keep' running for a desired time. + + It should also provide us, a way to easily implement this + controll multiple times, without trouble. + + We are giving this Custom Thread the name 'ButtonThread'. + + Exemplifying what it does: + + ButtonThread added to our mainController ThreadList + => Instantiated with a custom Pin #, + => and a time duration (in miliseconds) + + + ButtonThread is not running. + + + When the button is pressed: + + Thread will start and keep running. + + If the thread runned for our defined period, + we stop it. + + ================ HOW TO SETUP HARDWARE ================== + In order to make this example work with any arduino, hook up + the pins on the board to 3 buttons. You can change the inputs + if you need below here. + + The Buttons are being SOFTWARE pulled UP (to VCC), and when + pushed, should go LOW. Connect like this: + (Arduino Input) <----> (Btn) <----> GND (-) + + We are using digital pins 9, 10 and 11 as input. + It also uses a LED, but we are using the default one in the board. + + =============== WHAT YO LEARN WITH THIS ================= + 1) Threads are actually running in 'parallel'. + + Synce each thread process time is very tiny, they appear + as being runned in parallel. + + Because of that, clicking multiple buttons at any time, + will looks like there is a program for each one of them. + + 2) If you keep the button 'pressed', it will continue to run. + + Since we are 'enabling' the thread, and reseting the timer + flag (_lastButtonPushed) every time the button is pressed, + we should notice that in btn1Callback, where we print this + flag, it will never go beyond 0 if we keep pressing it. + + 3) The LED turns off, only because the Thread runs a last time + with the flag 'enabled' as false. This way, we can turn the + LED off and remain OFF until we press it egain. + + I hope you enjoy, and learn some advanced-cool stuf with this tutorial. + Any feedback is apreciated! +*/ +#define BTN1 9 +#define BTN2 10 +#define BTN3 11 + +#define LED 13 + +// ThreadController that will controll all button threads +ThreadController controll = ThreadController(); + +// Here we implement our custom ButtonThread, that Inherits from Thread +class ButtonThread: public Thread{ +public: + // Our custom thread attributes + int pin; + long duration; + long _lastButtonPushed; + + /* + Our Constructor. This will initialize the thread + with it's corresponding pin and duration after clicked. + */ + ButtonThread(int _pin, long _duration): Thread(){ + // Set our attributes on construct + pin = _pin; + duration = _duration; + _lastButtonPushed = 0; + + // Thread will start disabled + enabled = false; + + // Configure the pin as INPUT and enable pull-up + pinMode(pin, INPUT); + digitalWrite(pin, HIGH); + } + + /* + Override the method responsible for + checking if the thread should run. + + It will first check if the button is pressed. + If so, we enable the thread, and then let the + "Old" default Thread method 'shouldRun' return if + it should run. + */ + bool shouldRun(long time){ + // Override enabled on thread when pin goes LOW. + if(digitalRead(pin) == LOW){ + enabled = true; + /* + Here, we save the current time in this object, + to compare it later. + + the 'time' parameter in this method, is an override for the + 'millis()' method. It allows who is checking the thread, to + pass a custom time. + + This is sintax for writing an 'inline' if is very usefull, + it's the same as: + if(time > 0){ + _lastButtonPushed = time; + }else{ + _lastButtonPushed = millis(); + } + */ + _lastButtonPushed = (time ? time : millis()); + } + + // Let default method check for it. + return Thread::shouldRun(time); + } + + /* + We 'disable' the thread after the duration on the + 'run' method. + + What we should do here, is check if the time saved + in the _lastButtonPushed variable plus the duration, + is greater than our current time. If that's true, it + means we exceeded the thread time, and that we must + disable it and prevent from running. + */ + void run(){ + // Check if time elapsed since last button push + if(millis() > _lastButtonPushed + duration){ + // It exceeded time. We should disable it. + enabled = false; + } + + /* + Run the thread. + + Note that this method will only get called + from the ThreadList, IF the 'shouldRun' returns true. + + If the thread is not enabled anymore, it will run a 'last' + time with the flag 'enabled' as false, meaning it's the last + run in the period. You can use it for doing something only + before it stops running. + */ + Thread::run(); + } +}; + +/* + ButtonThreads objects instantiation + (we are instantiating 2 as a member, and one + as pointer in the setup, just to show you + different ways of doing it) +*/ + +// Thread 1 will be reading BTN1 pin, and will run for 3 secs +ButtonThread btn1Thread(BTN1, 3000); + +// Thread 2 will be reading BTN1 pin, and will run for 5 secs +ButtonThread btn2Thread = ButtonThread(BTN2, 5000); + +// Thread 3 will be instantiated in the setup() +ButtonThread *btn3Thread; + + +/* + Callback for ButtonThreads +*/ +void btn1Callback(){ + // When it's running, this thread will write to the serial. + /* + This math will print 'how long' the thread has been running, + since the button was/is pressed. + + After pressing it, it should print as 0, and goes up untill + the thread duration (in this case, +-5000ms). + */ + Serial.print("BTN 1 Thread: "); + Serial.println(millis() - btn1Thread._lastButtonPushed); +} + +void btn2Callback(){ + /* + This thread will remain with the LED on pin 13 turned on + while it is running. + + We detect that this method is called for the LAST time, if + the flag 'enabled' is FALSE on the btn2Thread object. + + So, basically: If it's TRUE, we should turn ON the led, if not + we should turn OFF. We can simplify that into one line. + (Same 'inline' sintax as above) + */ + digitalWrite(LED, btn2Thread.enabled ? HIGH : LOW); +} + +void btn3Callback(){ + // When it's running, this thread will also write to the serial + Serial.println("BTN 3 Thread"); +} + +void setup(){ + // Configure serial and output pins + Serial.begin(9600); + pinMode(LED, OUTPUT); + + // Configure btn1Thread callback + // (During the 'enabled' time, it will run every 100ms, aka Interval) + btn1Thread.onRun(btn1Callback); + btn1Thread.setInterval(100); + + // Configure btn2Thread callback and interval + btn2Thread.onRun(btn2Callback); + btn2Thread.setInterval(200); + + // Instantiate btn3Thread + btn3Thread = new ButtonThread(BTN3, 4000); + // Configure btn3Thread callback and interval + btn3Thread->onRun(btn3Callback); + btn3Thread->setInterval(100); + + // Adds all threads to the controller + controll.add(&btn1Thread); // & to pass the pointer to it + controll.add(&btn2Thread); + controll.add(btn3Thread); // Its already a pointer, no need for & +} + +void loop(){ + // Here we just run the main thread controller + controll.run(); +} \ No newline at end of file diff --git a/lib/ArduinoThread/examples/SensorThread/SensorThread.ino b/lib/ArduinoThread/examples/SensorThread/SensorThread.ino new file mode 100644 index 0000000..9c5c91f --- /dev/null +++ b/lib/ArduinoThread/examples/SensorThread/SensorThread.ino @@ -0,0 +1,105 @@ +#include "Thread.h" +#include "ThreadController.h" +/* + This is a more "complex" for of using Threads. + You can also inherit from Thread, and do your entire code on the class. + + This allows you, to create for example: + Sensor Readings (aquire, filter, and save localy values) + Custom Blinks, Beeps... + Anything you can imagine. + + Threads are more "usefull" when used within Timer interrupts + + This way of coding is more "reusable", and "correct" (Object Oriented) +*/ + + +/* + This example, requires a Timer Interrupt Library. + If you are using Arduino NANO, UNO... (with ATmega168/328) + Please go to: http://playground.arduino.cc/code/timer1 + If you are using Arduino DUE, + Please go to: https://github.com/ivanseidel/DueTimer + + Include the library corresponding to your Arduino. +*/ +#include +// #include + +// Create a new Class, called SensorThread, that inherits from Thread +class SensorThread: public Thread +{ +public: + int value; + int pin; + + // No, "run" cannot be anything... + // Because Thread uses the method "run" to run threads, + // we MUST overload this method here. using anything other + // than "run" will not work properly... + void run(){ + // Reads the analog pin, and saves it localy + value = map(analogRead(pin), 0,1023,0,255); + runned(); + } +}; + +// Now, let's use our new class of Thread +SensorThread analog1 = SensorThread(); +SensorThread analog2 = SensorThread(); + +// Instantiate a new ThreadController +ThreadController controller = ThreadController(); + +// This is the callback for the Timer +void timerCallback(){ + controller.run(); +} + +void setup(){ + + Serial.begin(9600); + + // Configures Thread analog1 + analog1.pin = A1; + analog1.setInterval(100); + + // Configures Thread analog2 + analog2.pin = A2; + analog2.setInterval(100); + + // Add the Threads to our ThreadController + controller.add(&analog1); + controller.add(&analog2); + + /* + If using DueTimer... + */ + Timer1.attachInterrupt(timerCallback).start(10000); + + /* + If using TimerOne... + */ + // Timer1.initialize(20000); + // Timer1.attachInterrupt(timerCallback); + // Timer1.start(); + +} + +void loop(){ + // Do complex-crazy-timeconsuming-tasks here + delay(1000); + + // Get the fresh readings + Serial.print("Analog1 Thread: "); + Serial.println(analog1.value); + + Serial.print("Analog2 Thread: "); + Serial.println(analog2.value); + + // Do more complex-crazy-timeconsuming-tasks here + delay(1000); + +} + diff --git a/lib/ArduinoThread/examples/SimpleThread/SimpleThread.ino b/lib/ArduinoThread/examples/SimpleThread/SimpleThread.ino new file mode 100644 index 0000000..e45362a --- /dev/null +++ b/lib/ArduinoThread/examples/SimpleThread/SimpleThread.ino @@ -0,0 +1,35 @@ +#include +int ledPin = 13; + +//My simple Thread +Thread myThread = Thread(); + +// callback for myThread +void niceCallback(){ + static bool ledStatus = false; + ledStatus = !ledStatus; + + digitalWrite(ledPin, ledStatus); + + Serial.print("COOL! I'm running on: "); + Serial.println(millis()); +} + +void setup(){ + Serial.begin(9600); + + pinMode(ledPin, OUTPUT); + + myThread.onRun(niceCallback); + myThread.setInterval(500); +} + +void loop(){ + // checks if thread should run + if(myThread.shouldRun()) + myThread.run(); + + // Other code... + int x = 0; + x = 1 + 2; +} \ No newline at end of file diff --git a/lib/ArduinoThread/examples/SimpleThreadController/SimpleThreadController.ino b/lib/ArduinoThread/examples/SimpleThreadController/SimpleThreadController.ino new file mode 100644 index 0000000..949290b --- /dev/null +++ b/lib/ArduinoThread/examples/SimpleThreadController/SimpleThreadController.ino @@ -0,0 +1,48 @@ +#include +#include + +// ThreadController that will controll all threads +ThreadController controll = ThreadController(); + +//My Thread (as a pointer) +Thread* myThread = new Thread(); +//His Thread (not pointer) +Thread hisThread = Thread(); + +// callback for myThread +void niceCallback(){ + Serial.print("COOL! I'm running on: "); + Serial.println(millis()); +} + +// callback for hisThread +void boringCallback(){ + Serial.println("BORING..."); +} + +void setup(){ + Serial.begin(9600); + + // Configure myThread + myThread->onRun(niceCallback); + myThread->setInterval(500); + + // Configure myThread + hisThread.onRun(boringCallback); + hisThread.setInterval(250); + + // Adds both threads to the controller + controll.add(myThread); + controll.add(&hisThread); // & to pass the pointer to it +} + +void loop(){ + // run ThreadController + // this will check every thread inside ThreadController, + // if it should run. If yes, he will run it; + controll.run(); + + // Rest of code + float h = 3.1415; + h/=2; +} \ No newline at end of file diff --git a/lib/ArduinoThread/examples/StaticThreadController/StaticThreadController.ino b/lib/ArduinoThread/examples/StaticThreadController/StaticThreadController.ino new file mode 100644 index 0000000..bb4155a --- /dev/null +++ b/lib/ArduinoThread/examples/StaticThreadController/StaticThreadController.ino @@ -0,0 +1,56 @@ +#include +#include + +//My Thread (as a pointer) +Thread* myThread = new Thread(); +//His Thread (not pointer) +Thread hisThread = Thread(); + +// callback for myThread +void niceCallback(){ + Serial.print("COOL! I'm running on: "); + Serial.println(millis()); +} + +// callback for hisThread +void boringCallback(){ + Serial.println("BORING..."); +} + +// callback for theThread +void justCallback(){ + Serial.println("executing..."); +} + +//The Thread (as a pointer) with justCallback initialized +Thread* theThread = new Thread(justCallback); + +// StaticThreadController that will controll all threads +// All non-pointers go with '&', but pointers go without '&', +StaticThreadController<3> controll (myThread, &hisThread, theThread); + +void setup(){ + Serial.begin(9600); + + // Configure myThread + myThread->onRun(niceCallback); + myThread->setInterval(500); + + // Configure hisThread + hisThread.onRun(boringCallback); + hisThread.setInterval(250); + + // Set interval for theThread using StaticThreadController interface + controll[3].setInterval(375); +} + +void loop(){ + // run StaticThreadController + // this will check every thread inside ThreadController, + // if it should run. If yes, he will run it; + controll.run(); + + // Rest of code + float h = 3.1415; + h/=2; +} diff --git a/lib/ArduinoThread/keywords.txt b/lib/ArduinoThread/keywords.txt new file mode 100644 index 0000000..09b104d --- /dev/null +++ b/lib/ArduinoThread/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Thread KEYWORD1 +ThreadController KEYWORD1 +StaticThreadController KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +runned KEYWORD2 +setInterval KEYWORD2 +shouldRun KEYWORD2 +onRun KEYWORD2 +run KEYWORD2 + +# Specific of ThreadController or StaticThreadController +add KEYWORD2 +remove KEYWORD2 +clear KEYWORD2 +size KEYWORD2 +get KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/ArduinoThread/library.json b/lib/ArduinoThread/library.json new file mode 100644 index 0000000..5870787 --- /dev/null +++ b/lib/ArduinoThread/library.json @@ -0,0 +1,13 @@ +{ + "name": "ArduinoThread", + "keywords": "thread, task", + "description": "A library for managing the periodic execution of multiple tasks", + "repository": { + "type": "git", + "url": "https://github.com/ivanseidel/ArduinoThread.git" + }, + "frameworks": "arduino", + //"platforms": "atmelavr", LK 2025 + "platforms": "*" + "version": "2.1.1" +} \ No newline at end of file diff --git a/lib/ArduinoThread/library.properties b/lib/ArduinoThread/library.properties new file mode 100644 index 0000000..59eed7a --- /dev/null +++ b/lib/ArduinoThread/library.properties @@ -0,0 +1,9 @@ +name=ArduinoThread +version=2.1.1 +author=Ivan Seidel +maintainer=Ivan Seidel +sentence=A simple way to run Threads on Arduino +paragraph=This Library helps to maintain organized and to facilitate the use of multiple tasks. We can use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks on the rug. +category=Timing +url=https://github.com/ivanseidel/ArduinoThread +architectures=* diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..d7637ec --- /dev/null +++ b/lib/README @@ -0,0 +1,4 @@ + +# Biblioteki + +Ten folder zawiera biblioteki wykorzystane w projekcie. diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..e41fe43 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,30 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32-c3-devkitm-1] +platform = espressif32 +board = esp32-c3-devkitm-1 +framework = arduino +monitor_speed = 115200 +build_flags = + -DARDUINO_USB_MODE=1 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DCORE_DEBUG_LEVEL=3 + -DLOG_LOCAL_LEVEL=ESP_LOG_INFO + +; Wymuszenie poprawnego sprawdzania zależności +lib_ldf_mode = deep+ + +lib_deps = + SPI + Wire + arminjo/ServoEasing@^3.6.0 + adafruit/Adafruit PWM Servo Driver Library@^3.0.3 + madhephaestus/ESP32Servo@^3.2.0 diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..07b994b --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,16 @@ +#include + +const char *TAG_MAIN = "MAIN"; +const char *TAG_DISPLAY = "DISPLAY"; +const char *TAG_WIFI = "WiFi"; +const char *TAG_ADXL = "ADXL345"; +const char *TAG_CONF = "CONFIG"; + + +void init_log_levels() { + esp_log_level_set(TAG_MAIN, ESP_LOG_INFO); + esp_log_level_set(TAG_DISPLAY, ESP_LOG_INFO); + esp_log_level_set(TAG_WIFI, ESP_LOG_INFO); + esp_log_level_set(TAG_ADXL, ESP_LOG_INFO); + esp_log_level_set(TAG_CONF, ESP_LOG_INFO); +} diff --git a/src/Tool.cpp b/src/Tool.cpp new file mode 100644 index 0000000..54c90cc --- /dev/null +++ b/src/Tool.cpp @@ -0,0 +1,48 @@ +#include + +static const char *TOOL = "tool"; + +bool isI2CDevPresent(uint8_t address) { + Wire.beginTransmission(address); + uint8_t error = Wire.endTransmission(); + + if (error == 0) { + ESP_LOGI(TOOL, "I2C response from 0x%02X", address); + return true; + } else { + if (error == 4) { + //ESP_LOGW(TOOL, "I2C unknown error at 0x%02X", address); + } else { + ESP_LOGI(TOOL, "No I2C device at 0x%02X", address); + } + return false; + } +} + +void scanI2C() { + byte error, address; + int nDevices = 0; + ESP_LOGI(TOOL, "I2C start scan"); + for (address = 1; address < 127; address++) { + Wire.beginTransmission(address); + error = Wire.endTransmission(); + + if (error == 0) { + char buf[32]; + snprintf(buf, sizeof(buf), "I2C device: 0x%02X", address); + ESP_LOGI(TOOL, "%s", buf); + nDevices++; + Watchdog::feed(); + } + else if (error == 4) { + ESP_LOGW(TOOL, "I2C error at address: 0x%02X", address); + } + } + + if (nDevices == 0) { + ESP_LOGE(TOOL, "I2C no devices found"); + } else { + ESP_LOGI(TOOL, "I2C scan finished. Found %d device(s)", nDevices); + } + Watchdog::feed(); +} diff --git a/src/Watchdog.cpp b/src/Watchdog.cpp new file mode 100644 index 0000000..5b7c5c6 --- /dev/null +++ b/src/Watchdog.cpp @@ -0,0 +1,81 @@ +#include "Watchdog.h" + +// Wykrywanie środowiska +#if defined(ESP_PLATFORM) || defined(ESP32) + #include + #define WDOG_HAS_ESP 1 +#else + #define WDOG_HAS_ESP 0 +#endif + +namespace Watchdog { + +static bool s_initialized = false; + +bool init(int timeout_seconds, bool panic_on_trigger) { +#if WDOG_HAS_ESP + if (s_initialized) return true; + esp_err_t err = esp_task_wdt_init(timeout_seconds, panic_on_trigger); + if (err == ESP_OK || err == ESP_ERR_INVALID_STATE) { + // ESP_ERR_INVALID_STATE: już zainicjalizowany — traktujemy jako OK + s_initialized = true; + return true; + } + return false; +#else + (void)timeout_seconds; (void)panic_on_trigger; + s_initialized = true; // no-op, aby nie blokować wywołań w kodzie + return true; +#endif +} + +bool addThisTask() { +#if WDOG_HAS_ESP + if (!s_initialized) return false; + esp_err_t err = esp_task_wdt_add(nullptr); // nullptr = bieżący task + return (err == ESP_OK || err == ESP_ERR_INVALID_STATE); +#else + return true; // no-op +#endif +} + +bool removeThisTask() { +#if WDOG_HAS_ESP + if (!s_initialized) return false; + esp_err_t err = esp_task_wdt_delete(nullptr); // bieżący task + return (err == ESP_OK || err == ESP_ERR_INVALID_STATE); +#else + return true; // no-op +#endif +} + +void feed() { +#if WDOG_HAS_ESP + esp_task_wdt_reset(); +#else + // no-op +#endif +} + +bool setTimeout(int timeout_seconds) { +#if WDOG_HAS_ESP + if (!s_initialized) { + // jeśli ktoś nie zainicjalizował — zrób to teraz + return init(timeout_seconds, true); + } + // W ESP-IDF/Arduino brak prostego API na „live update” — re-init: + esp_err_t err = esp_task_wdt_deinit(); + (void)err; // nie każdy port raportuje OK/INVALID_STATE spójnie + s_initialized = false; + return init(timeout_seconds, true); +#else + (void)timeout_seconds; + return true; // no-op +#endif +} + +bool isActive() { + return s_initialized; +} + +} // namespace Watchdog diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..10d7575 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,143 @@ +#include +#include "Watchdog.h" +#include +#include +#include +#include +#include +#include +#include + +#define WDT_TIMEOUT 60 // Czas watchdoga do restartu +// Konfiguracja serw (to trzeba skalibrować) +#define SERVOMIN 150 // Minimalna długość impulsu (0 stopni) +#define SERVOMAX 550 // Maksymalna długość impulsu (180 stopni) +#define NUM_FINGERS 5 + +// Aktualne pozycje serw (do płynnych przejść) +int currentPositions[NUM_FINGERS] = {0, 0, 0, 0, 0}; + +Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); + +// Struktura gestu +struct Gesture { + const char *name; + int angles[NUM_FINGERS]; // Kąty 0-180 +}; + +// --- DEFINICJA GESTÓW --- +// Kolejność: Kciuk, Wskazujący, Środkowy, Serdeczny, Mały +Gesture gestureList[] = { + {"OTWARTA", {0, 0, 0, 0, 0}}, // Wszystkie wyprostowane + {"PIESC", {170, 170, 170, 170, 170}},// Wszystkie zgięte + {"V-SIGN", {170, 0, 0, 170, 170}}, // Pokój / Zwycięstwo + {"OK", {150, 150, 0, 0, 0}}, // Kciuk i wskazujący złączone + {"PALEC", {170, 0, 170, 170, 170}}, // Wskazywanie palcem + + // --- NOWE GESTY --- + {"KCIUK_GORA", {0, 170, 170, 170, 170}}, // Lajk (Kciuk wyprostowany, reszta pięść) + {"ROCK_ON", {0, 0, 170, 170, 0}}, // "Rogi" (Kciuk, wskazujący i mały wyprostowane) + {"SPIDERMAN", {0, 0, 170, 170, 0}}, // Podobnie jak rock, ale kciuk szeroko + {"SHAKA", {0, 170, 170, 170, 0}}, // Gest surferów (Kciuk i mały wyprostowane) + {"PUNKT", {170, 0, 0, 170, 170}}, // Wskazujący i środkowy (jak pistolet) + + // --- LICZBY --- + {"LICZBA_1", {170, 0, 170, 170, 170}}, // Tylko wskazujący + {"LICZBA_2", {170, 0, 0, 170, 170}}, // Wskazujący i środkowy + {"LICZBA_3", {170, 0, 0, 0, 170}}, // Trzy środkowe palce + {"LICZBA_4", {170, 0, 0, 0, 0}}, // Bez kciuka + + // --- INNE --- + {"CZEŚĆ", {40, 40, 40, 40, 40}}, // Lekko ugięte (naturalna dłoń) + {"CHWYT_PRECYZ", {120, 120, 170, 170, 170}} // Pęseta (Kciuk i wskazujący do połowy) +}; +int totalGestures = sizeof(gestureList) / sizeof(Gesture); + +//////// PROTOTYPY ///////////////// +void setup(); +void loop(); +//void playGesture(Gesture g); +void moveToGesture(Gesture g, int speed); +int angleToPWM(int angle); + + +void setup() { + Serial.begin(115200); + delay(500); + unsigned long t0 = millis(); + while (!Serial && millis()-t0 < 2000) { delay(10); } + esp_log_level_set("*", ESP_LOG_INFO); // _ERROR, _WARN, _INFO, _DEBUG, _VERBOSE + delay(500); + + ESP_LOGI(TAG_MAIN, "----------------------"); + ESP_LOGI(TAG_MAIN, "WMT Stalowa Wola L.Klich"); + ESP_LOGI(TAG_MAIN, "Robotyczna reka"); + ESP_LOGI(TAG_MAIN, "Firmware: %s", VERSION); + ESP_LOGI(TAG_MAIN, "----------------------"); + ESP_LOGI(TAG_MAIN, "ESP32 model: %s Rev %d", ESP.getChipModel(), ESP.getChipRevision()); + ESP_LOGI(TAG_MAIN, "Chip cores: %d", ESP.getChipCores()); + + // Inicjalizacja Watchdoga panic_on_trigger = true + if (Watchdog::init(25, true)) { + ESP_LOGI(TAG_MAIN, "Watchdog init ok."); + } else { + ESP_LOGE(TAG_MAIN, "Watchdog init error."); + } + + Wire.begin(PIN_SDA, PIN_SCL); + scanI2C(); // Skanowanie magistrali I2C + pwm.begin(); + pwm.setPWMFreq(50); + + // Dodanie taska loop do WDT + if (Watchdog::addThisTask()) { + ESP_LOGI(TAG_MAIN, "Added main task to Watchdog"); + } + + // Ustawienie pozycji startowej (otwarta dłoń) + for(int i=0; i g.angles[i]) { + currentPositions[i]--; + allReached = false; + } + pwm.setPWM(i, 0, angleToPWM(currentPositions[i])); + } + delay(speed); // Kontrola prędkości (im mniejsza wartość, tym szybciej) + } +} + +void loop() { + Watchdog::feed(); + + for (int i = 0; i < totalGestures; i++) { + moveToGesture(gestureList[i], 10); // Prędkość 10ms na stopień + delay(1000); // 1 sekunda przed kolejnym gestem + Watchdog::feed(); + } + +} + diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html