diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..a1b16285 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 099e1f7c..15d2ae94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ .project .cproject .settings/ -/esp32-snippets/.vs + +# IDEs +.vs/ +.idea/ + +# CMake +cmake-build-debug/ diff --git a/Documentation/ideas/FastFlash/README.md b/Documentation/ideas/FastFlash/README.md new file mode 100644 index 00000000..d599b4aa --- /dev/null +++ b/Documentation/ideas/FastFlash/README.md @@ -0,0 +1,8 @@ +# FastFlash +As we build ESP32 applications, we typically perform a compile, flash, test loop cycle. We compile an app, we flash the ESP32 with that app and then we test whether it works. We perform these actions over and over again. When we look at the time taken in each step, we see there is compile time on our PC and then the time taken to flash the PC. This story talks about the time taken to flash the PC. + +The ESP32 is typically configured to flash at 115200 kbps. This is 115200 bits per second. If we think that a typical ESP32 application is 800KBytes then this requires a transmission of: + +800000 * 9 = 7.2 million bits = 62.5 seconds + +we can increase our baud rate up to 921600 = 7.8 seconds \ No newline at end of file diff --git a/README.md b/README.md index c785b3c6..fbea27ae 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,2 @@ # ESP32 Snippets -This repository hosts a set of ESP32 snippets that are in different -stages of completeness. They are made available in the hope that there -may be something of value to you and under the notion that something -is better than nothing. The samples are being categorized. - -* vfs - Virtual File System -* wifi - WiFi access -* curl - Examples of curl usage +This repository is no longer being actively maintained. It was previously archived to make it read-only but, by request, has been un-archived so that others may continue to post comments and issues. However, please understand that issues raised are unlikely to be resolved against this repository. diff --git a/VisualStudioCode/README.md b/VisualStudioCode/README.md new file mode 100644 index 00000000..ff5ab2f2 --- /dev/null +++ b/VisualStudioCode/README.md @@ -0,0 +1,4 @@ +These are file for Microsoft Visual Studio Code and can be copied into your `.vscode` project folder. For more information on this area, see: + +* [VSCode JTAG Debugging of ESP32 - Part 2](https://gojimmypi.blogspot.com/2017/05/vscode-remote-jtag-debugging-of-esp32.html) +* [Deous/VSC-Guide-for-esp32](https://github.com/Deous/VSC-Guide-for-esp32) \ No newline at end of file diff --git a/VisualStudioCode/c_cpp_properties.json b/VisualStudioCode/c_cpp_properties.json new file mode 100644 index 00000000..9ef83b14 --- /dev/null +++ b/VisualStudioCode/c_cpp_properties.json @@ -0,0 +1,266 @@ +{ + "configurations": [ + { + "name": "ESP32-Linux", + "includePath": [ + "${workspaceRoot}", + "${workspaceRoot}/components", + "${workspaceRoot}/build", + "${workspaceRoot}/build/include", + "${env:IDF_PATH}/components/bt/bluedroid/utils/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/smp/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/sdp/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/rfcomm/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/l2cap/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/gatt/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/gap/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/avrc/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/avdt/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/avct/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/a2dp/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/include", + "${env:IDF_PATH}/components/bt/bluedroid/osi/include", + "${env:IDF_PATH}/components/bt/bluedroid/hci/include", + "${env:IDF_PATH}/components/bt/bluedroid/gki/include", + "${env:IDF_PATH}/components/bt/bluedroid/external/sbc/encoder/include", + "${env:IDF_PATH}/components/bt/bluedroid/external/sbc/decoder/include", + "${env:IDF_PATH}/components/bt/bluedroid/device/include", + "${env:IDF_PATH}/components/bt/bluedroid/btcore/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/smp/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/hid/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/dis/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/battery/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/a2dp/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/esp/blufi/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/esp/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/include", + "${env:IDF_PATH}/components/bt/bluedroid/bta/sys/include", + "${env:IDF_PATH}/components/bt/bluedroid/bta/include", + "${env:IDF_PATH}/components/bt/bluedroid/api/include", + "${env:IDF_PATH}/components/bt/bluedroid/include", + "${env:IDF_PATH}/components/aws_iot/include", + "${env:IDF_PATH}/components/aws_iot/aws-iot-device-sdk-embedded-C/include", + "${env:IDF_PATH}/components/app_trace/include", + "${env:IDF_PATH}/components/app_update/include", + "${env:IDF_PATH}/components/xtensa-debug-module/include", + "${env:IDF_PATH}/components/bootloader_support/include", + "${env:IDF_PATH}/components/bootloader_support/include_priv", + "${env:IDF_PATH}/components/bt/include", + "${env:IDF_PATH}/components/coap/port/include", + "${env:IDF_PATH}/components/coap/port/include/coap", + "${env:IDF_PATH}/components/coap/libcoap/include", + "${env:IDF_PATH}/components/coap/libcoap/include/coap", + "${env:IDF_PATH}/components/cxx/include", + "${env:IDF_PATH}/components/driver/include", + "${env:IDF_PATH}/components/driver/include/driver", + "${env:IDF_PATH}/components/esp32/include", + "${env:IDF_PATH}/components/ethernet/include", + "${env:IDF_PATH}/components/expat/include/expat", + "${env:IDF_PATH}/components/expat/port/include", + "${env:IDF_PATH}/components/fatfs/src", + "${env:IDF_PATH}/components/freertos/include", + "${env:IDF_PATH}/components/heap/include", + "${env:IDF_PATH}/components/jsmn/include", + "${env:IDF_PATH}/components/json/include", + "${env:IDF_PATH}/components/json/port/include", + "${env:IDF_PATH}/components/json/cJSON", + "${env:IDF_PATH}/components/libsodium/libsodium/src/libsodium/include", + "${env:IDF_PATH}/components/libsodium/libsodium/src/libsodium/include/sodium", + "${env:IDF_PATH}/components/log/include", + "${env:IDF_PATH}/components/lwip/include/lwip", + "${env:IDF_PATH}/components/lwip/include/lwip/port", + "${env:IDF_PATH}/components/lwip/include/lwip/posix", + "${env:IDF_PATH}/components/lwip/apps/ping", + "${env:IDF_PATH}/components/lwip/include/lwip/apps", + "${env:IDF_PATH}/components/lwip/include/lwip/apps/sntp", + "${env:IDF_PATH}/components/lwip/include/lwip/lwip", + "${env:IDF_PATH}/components/lwip/include/lwip/lwip/priv", + "${env:IDF_PATH}/components/lwip/include/lwip/netif", + "${env:IDF_PATH}/components/lwip/include/lwip/netif/ppp", + "${env:IDF_PATH}/components/lwip/include/lwip/netif/ppp/polarssl", + "${env:IDF_PATH}/components/lwip/include/lwip/port", + "${env:IDF_PATH}/components/lwip/include/lwip/port/arch", + "${env:IDF_PATH}/components/lwip/include/lwip/port/arpa", + "${env:IDF_PATH}/components/lwip/include/lwip/port/netif", + "${env:IDF_PATH}/components/lwip/include/lwip/port/netinet", + "${env:IDF_PATH}/components/lwip/include/lwip/posix", + "${env:IDF_PATH}/components/lwip/include/lwip/posix/sys", + "${env:IDF_PATH}/components/mbedtls/port/include", + "${env:IDF_PATH}/components/mbedtls/mbedtls/include", + "${env:IDF_PATH}/components/mbedtls/port/include/mbedtls", + "${env:IDF_PATH}/components/mdns/include", + "${env:IDF_PATH}/components/micro-ecc/micro-ecc", + "${env:IDF_PATH}/components/newlib/include", + "${env:IDF_PATH}/components/newlib/include/sys", + "${env:IDF_PATH}/components/newlib/platform_include", + "${env:IDF_PATH}/components/nghttp/include", + "${env:IDF_PATH}/components/nghttp/port/include", + "${env:IDF_PATH}/components/nvs_flash/include", + "${env:IDF_PATH}/components/openssl/include", + "${env:IDF_PATH}/components/openssl/include/internal", + "${env:IDF_PATH}/components/openssl/include/platform", + "${env:IDF_PATH}/components/openssl/include/openssl", + "${env:IDF_PATH}/components/pthread/include", + "${env:IDF_PATH}/components/sdmmc/include", + "${env:IDF_PATH}/components/spi_flash/include", + "${env:IDF_PATH}/components/tcpip_adapter/include", + "${env:IDF_PATH}/components/soc/esp32/include", + "${env:IDF_PATH}/components/soc/include", + "${env:IDF_PATH}/components/soc/esp32/include/soc", + "${env:IDF_PATH}/components/spi_flash", + "${env:IDF_PATH}/components/spiffs/include", + "${env:IDF_PATH}/components/tcpip_adapter/include", + "${env:IDF_PATH}/components/heap/include", + "${env:IDF_PATH}/components/ulp/include", + "${env:IDF_PATH}/components/ulp/include/esp32", + "${env:IDF_PATH}/components/vfs/include", + "${env:IDF_PATH}/components/vfs/include/sys", + "${env:IDF_PATH}/components/wear_levelling/include", + "${env:IDF_PATH}/components/wpa_supplicant/include", + "${env:IDF_PATH}/components/wpa_supplicant/port/include", + "${env:IDF_PATH}/components/wpa_supplicant/include/crypto", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa2/eap_peer", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa2/tls", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa2/utils", + "${env:IDF_PATH}/components/xtensa-debug-module/include", + "C:/Program Files/Espressif/ESP-IDF Tools/toolchain/lib/gcc/xtensa-esp32-elf/5.2.0/include" + ], + "intelliSenseMode": "clang-x64", + "browse": { + "path": [ + "${workspaceRoot}", + "${workspaceRoot}/components", + "${workspaceRoot}/build", + "${workspaceRoot}/build/include", + "${env:IDF_PATH}/components/bt/bluedroid/utils/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/smp/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/sdp/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/rfcomm/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/l2cap/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/gatt/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/gap/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/avrc/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/avdt/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/avct/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/a2dp/include", + "${env:IDF_PATH}/components/bt/bluedroid/stack/include", + "${env:IDF_PATH}/components/bt/bluedroid/osi/include", + "${env:IDF_PATH}/components/bt/bluedroid/hci/include", + "${env:IDF_PATH}/components/bt/bluedroid/gki/include", + "${env:IDF_PATH}/components/bt/bluedroid/external/sbc/encoder/include", + "${env:IDF_PATH}/components/bt/bluedroid/external/sbc/decoder/include", + "${env:IDF_PATH}/components/bt/bluedroid/device/include", + "${env:IDF_PATH}/components/bt/bluedroid/btcore/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/smp/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/hid/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/dis/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/battery/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/a2dp/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/std/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/esp/blufi/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/profile/esp/include", + "${env:IDF_PATH}/components/bt/bluedroid/btc/include", + "${env:IDF_PATH}/components/bt/bluedroid/bta/sys/include", + "${env:IDF_PATH}/components/bt/bluedroid/bta/include", + "${env:IDF_PATH}/components/bt/bluedroid/api/include", + "${env:IDF_PATH}/components/bt/bluedroid/include", + "${env:IDF_PATH}/components/aws_iot/include", + "${env:IDF_PATH}/components/aws_iot/aws-iot-device-sdk-embedded-C/include", + "${env:IDF_PATH}/components/app_trace/include", + "${env:IDF_PATH}/components/app_update/include", + "${env:IDF_PATH}/components/xtensa-debug-module/include", + "${env:IDF_PATH}/components/bootloader_support/include", + "${env:IDF_PATH}/components/bootloader_support/include_priv", + "${env:IDF_PATH}/components/bt/include", + "${env:IDF_PATH}/components/coap/port/include", + "${env:IDF_PATH}/components/coap/port/include/coap", + "${env:IDF_PATH}/components/coap/libcoap/include", + "${env:IDF_PATH}/components/coap/libcoap/include/coap", + "${env:IDF_PATH}/components/cxx/include", + "${env:IDF_PATH}/components/driver/include", + "${env:IDF_PATH}/components/driver/include/driver", + "${env:IDF_PATH}/components/esp32/include", + "${env:IDF_PATH}/components/ethernet/include", + "${env:IDF_PATH}/components/expat/include/expat", + "${env:IDF_PATH}/components/expat/port/include", + "${env:IDF_PATH}/components/fatfs/src", + "${env:IDF_PATH}/components/freertos/include", + "${env:IDF_PATH}/components/heap/include", + "${env:IDF_PATH}/components/jsmn/include", + "${env:IDF_PATH}/components/json/include", + "${env:IDF_PATH}/components/json/port/include", + "${env:IDF_PATH}/components/json/cJSON", + "${env:IDF_PATH}/components/libsodium/libsodium/src/libsodium/include", + "${env:IDF_PATH}/components/libsodium/libsodium/src/libsodium/include/sodium", + "${env:IDF_PATH}/components/log/include", + "${env:IDF_PATH}/components/lwip/include/lwip", + "${env:IDF_PATH}/components/lwip/include/lwip/port", + "${env:IDF_PATH}/components/lwip/include/lwip/posix", + "${env:IDF_PATH}/components/lwip/apps/ping", + "${env:IDF_PATH}/components/lwip/include/lwip/apps", + "${env:IDF_PATH}/components/lwip/include/lwip/apps/sntp", + "${env:IDF_PATH}/components/lwip/include/lwip/lwip", + "${env:IDF_PATH}/components/lwip/include/lwip/lwip/priv", + "${env:IDF_PATH}/components/lwip/include/lwip/netif", + "${env:IDF_PATH}/components/lwip/include/lwip/netif/ppp", + "${env:IDF_PATH}/components/lwip/include/lwip/netif/ppp/polarssl", + "${env:IDF_PATH}/components/lwip/include/lwip/port", + "${env:IDF_PATH}/components/lwip/include/lwip/port/arch", + "${env:IDF_PATH}/components/lwip/include/lwip/port/arpa", + "${env:IDF_PATH}/components/lwip/include/lwip/port/netif", + "${env:IDF_PATH}/components/lwip/include/lwip/port/netinet", + "${env:IDF_PATH}/components/lwip/include/lwip/posix", + "${env:IDF_PATH}/components/lwip/include/lwip/posix/sys", + "${env:IDF_PATH}/components/mbedtls/port/include", + "${env:IDF_PATH}/components/mbedtls/include", + "${env:IDF_PATH}/components/mbedtls/port/include/mbedtls", + "${env:IDF_PATH}/components/mdns/include", + "${env:IDF_PATH}/components/micro-ecc/micro-ecc", + "${env:IDF_PATH}/components/newlib/include", + "${env:IDF_PATH}/components/newlib/include/sys", + "${env:IDF_PATH}/components/newlib/platform_include", + "${env:IDF_PATH}/components/nghttp/include", + "${env:IDF_PATH}/components/nghttp/port/include", + "${env:IDF_PATH}/components/nvs_flash/include", + "${env:IDF_PATH}/components/openssl/include", + "${env:IDF_PATH}/components/openssl/include/internal", + "${env:IDF_PATH}/components/openssl/include/platform", + "${env:IDF_PATH}/components/openssl/include/openssl", + "${env:IDF_PATH}/components/pthread/include", + "${env:IDF_PATH}/components/sdmmc/include", + "${env:IDF_PATH}/components/spi_flash/include", + "${env:IDF_PATH}/components/tcpip_adapter/include", + "${env:IDF_PATH}/components/soc/esp32/include", + "${env:IDF_PATH}/components/soc/include", + "${env:IDF_PATH}/components/soc/esp32/include/soc", + "${env:IDF_PATH}/components/spi_flash", + "${env:IDF_PATH}/components/spiffs/include", + "${env:IDF_PATH}/components/tcpip_adapter/include", + "${env:IDF_PATH}/components/heap/include", + "${env:IDF_PATH}/components/ulp/include", + "${env:IDF_PATH}/components/ulp/include/esp32", + "${env:IDF_PATH}/components/vfs/include", + "${env:IDF_PATH}/components/vfs/include/sys", + "${env:IDF_PATH}/components/wear_levelling/include", + "${env:IDF_PATH}/components/wpa_supplicant/include", + "${env:IDF_PATH}/components/wpa_supplicant/port/include", + "${env:IDF_PATH}/components/wpa_supplicant/include/crypto", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa2/eap_peer", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa2/tls", + "${env:IDF_PATH}/components/wpa_supplicant/include/wpa2/utils", + "${env:IDF_PATH}/components/xtensa-debug-module/include", + "C:/Program Files/Espressif/ESP-IDF Tools/toolchain/lib/gcc/xtensa-esp32-elf/5.2.0/include" + + ], + "limitSymbolsToIncludedHeaders": true, + "databaseFilename": "${workspaceRoot}/.vscode/browse.vc.db" + }, + "cStandard": "c11", + "cppStandard": "c++17" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/VisualStudioCode/launch.json b/VisualStudioCode/launch.json new file mode 100644 index 00000000..257de4a0 --- /dev/null +++ b/VisualStudioCode/launch.json @@ -0,0 +1,43 @@ +{ + "version": "0.2.0", + "configurations": [ + + { + "name": "ESP32 OpenOCD launch", + "type": "cppdbg", + "request": "launch", + "program": "./build/app-template.elf", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "/opt/xtensa-esp32-elf/bin/xtensa-esp32-elf-gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "text": "target remote localhost:3333" + }, + { + "text": "monitor reset halt" + }, + { + "text": "flushregs" + }, + { + "text": "thb app_main" + } + ], + "logging": { + "trace": true, + "traceResponse": true, + "engineLogging": true + } + } + ] +} \ No newline at end of file diff --git a/VisualStudioCode/settings.json b/VisualStudioCode/settings.json new file mode 100644 index 00000000..7a73a41b --- /dev/null +++ b/VisualStudioCode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/VisualStudioCode/tasks.json b/VisualStudioCode/tasks.json new file mode 100644 index 00000000..d989b0f2 --- /dev/null +++ b/VisualStudioCode/tasks.json @@ -0,0 +1,41 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "menuconfig", + "type": "shell", + "command": "make menuconfig", + "problemMatcher": [] + }, + { + "label": "make", + "type": "shell", + "command": "make -j5", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [] + }, + { + "label": "flash", + "type": "shell", + "command": "make flash monitor", + "problemMatcher": [] + }, + { + "label": "monitor", + "type": "shell", + "command": "make monitor", + "problemMatcher": [] + }, + { + "label": "clean", + "type": "shell", + "command": "make clean", + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/cloud/GCP/JWT/base64url.cpp b/cloud/GCP/JWT/base64url.cpp new file mode 100644 index 00000000..94221181 --- /dev/null +++ b/cloud/GCP/JWT/base64url.cpp @@ -0,0 +1,136 @@ +// https://raw.githubusercontent.com/zhicheng/base64/master/base64.c +/* This is a public domain base64 implementation written by WEI Zhicheng. */ + +#include + +#include "base64url.h" + +/* BASE 64 encode table */ +static const char base64en[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '-', '_', +}; + +#define BASE64_PAD '=' + + +#define BASE64DE_FIRST '+' +#define BASE64DE_LAST 'z' +/* ASCII order for BASE 64 decode, -1 in unused character */ +static const signed char base64de[] = { + /* '+', ',', '-', '.', '/', '0', '1', '2', */ + 62, -1, -1, -1, 63, 52, 53, 54, + + /* '3', '4', '5', '6', '7', '8', '9', ':', */ + 55, 56, 57, 58, 59, 60, 61, -1, + + /* ';', '<', '=', '>', '?', '@', 'A', 'B', */ + -1, -1, -1, -1, -1, -1, 0, 1, + + /* 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', */ + 2, 3, 4, 5, 6, 7, 8, 9, + + /* 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', */ + 10, 11, 12, 13, 14, 15, 16, 17, + + /* 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */ + 18, 19, 20, 21, 22, 23, 24, 25, + + /* '[', '\', ']', '^', '_', '`', 'a', 'b', */ + -1, -1, -1, -1, -1, -1, 26, 27, + + /* 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', */ + 28, 29, 30, 31, 32, 33, 34, 35, + + /* 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', */ + 36, 37, 38, 39, 40, 41, 42, 43, + + /* 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */ + 44, 45, 46, 47, 48, 49, 50, 51, +}; + +int base64url_encode(const unsigned char *in, unsigned int inlen, char *out) +{ + unsigned int i, j; + + for (i = j = 0; i < inlen; i++) { + int s = i % 3; /* from 6/gcd(6, 8) */ + + switch (s) { + case 0: + out[j++] = base64en[(in[i] >> 2) & 0x3F]; + continue; + case 1: + out[j++] = base64en[((in[i-1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)]; + continue; + case 2: + out[j++] = base64en[((in[i-1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)]; + out[j++] = base64en[in[i] & 0x3F]; + } + } + + /* move back */ + i -= 1; + + /* check the last and add padding */ + + if ((i % 3) == 0) { + out[j++] = base64en[(in[i] & 0x3) << 4]; + //out[j++] = BASE64_PAD; + //out[j++] = BASE64_PAD; + } else if ((i % 3) == 1) { + out[j++] = base64en[(in[i] & 0xF) << 2]; + //out[j++] = BASE64_PAD; + } + + out[j++] = 0; + + return BASE64_OK; +} + +int base64url_decode(const char *in, unsigned int inlen, unsigned char *out) +{ + unsigned int i, j; + + for (i = j = 0; i < inlen; i++) { + int c; + int s = i % 4; /* from 8/gcd(6, 8) */ + + if (in[i] == '=') + return BASE64_OK; + + if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST || + (c = base64de[in[i] - BASE64DE_FIRST]) == -1) + return BASE64_INVALID; + + switch (s) { + case 0: + out[j] = ((unsigned int)c << 2) & 0xFF; + continue; + case 1: + out[j++] += ((unsigned int)c >> 4) & 0x3; + + /* if not last char with padding */ + if (i < (inlen - 3) || in[inlen - 2] != '=') + out[j] = ((unsigned int)c & 0xF) << 4; + continue; + case 2: + out[j++] += ((unsigned int)c >> 2) & 0xF; + + /* if not last char with padding */ + if (i < (inlen - 2) || in[inlen - 1] != '=') + out[j] = ((unsigned int)c & 0x3) << 6; + continue; + case 3: + out[j++] += (unsigned char)c; + } + } + + return BASE64_OK; +} diff --git a/cloud/GCP/JWT/base64url.h b/cloud/GCP/JWT/base64url.h new file mode 100644 index 00000000..7a8c80ca --- /dev/null +++ b/cloud/GCP/JWT/base64url.h @@ -0,0 +1,15 @@ +// https://raw.githubusercontent.com/zhicheng/base64/master/base64.h +#ifndef __BASE64URL_H__ +#define __BASE64URL_H__ + +enum {BASE64_OK = 0, BASE64_INVALID}; + +#define BASE64_ENCODE_OUT_SIZE(s) (((s) + 2) / 3 * 4) +#define BASE64_DECODE_OUT_SIZE(s) (((s)) / 4 * 3) + +int base64url_encode(const unsigned char *in, unsigned int inlen, char *out); + +int base64url_decode(const char *in, unsigned int inlen, unsigned char *out); + + +#endif /* __BASE64URL_H__ */ diff --git a/cloud/GCP/JWT/main.cpp b/cloud/GCP/JWT/main.cpp new file mode 100644 index 00000000..fcf8ec8b --- /dev/null +++ b/cloud/GCP/JWT/main.cpp @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "passwords.h" +#include "base64url.h" + +// This is an "xxd" file of the PEM of the private key. +#include "device1_private_pem.h" + + +extern "C" { + void app_main(); +} + +/** + * Return a string representation of an mbedtls error code + */ +static char* mbedtlsError(int errnum) { + static char buffer[200]; + mbedtls_strerror(errnum, buffer, sizeof(buffer)); + return buffer; +} // mbedtlsError + + +/** + * Create a JWT token for GCP. + * For full details, perform a Google search on JWT. However, in summary, we build two strings. One that represents the + * header and one that represents the payload. Both are JSON and are as described in the GCP and JWT documentation. Next + * we base64url encode both strings. Note that is distinct from normal/simple base64 encoding. Once we have a string for + * the base64url encoding of both header and payload, we concatenate both strings together separated by a ".". This resulting + * string is then signed using RSASSA which basically produces an SHA256 message digest that is then signed. The resulting + * binary is then itself converted into base64url and concatenated with the previously built base64url combined header and + * payload and that is our resulting JWT token. + * @param projectId The GCP project. + * @param privateKey The PEM or DER of the private key. + * @param privateKeySize The size in bytes of the private key. + * @returns A JWT token for transmission to GCP. + */ +char* createGCPJWT(const char* projectId, uint8_t* privateKey, size_t privateKeySize) { + char base64Header[100]; + const char header[] = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; + base64url_encode( + (unsigned char *)header, // Data to encode. + strlen(header), // Length of data to encode. + base64Header); // Base64 encoded data. + + time_t now; + time(&now); + uint32_t iat = now; // Set the time now. + uint32_t exp = iat + 60*60; // Set the expiry time. + + char payload[100]; + sprintf(payload, "{\"iat\":%d,\"exp\":%d,\"aud\":\"%s\"}", iat, exp, projectId); + + char base64Payload[100]; + base64url_encode( + (unsigned char *)payload, // Data to encode. + strlen(payload), // Length of data to encode. + base64Payload); // Base64 encoded data. + + uint8_t headerAndPayload[800]; + sprintf((char*)headerAndPayload, "%s.%s", base64Header, base64Payload); + + // At this point we have created the header and payload parts, converted both to base64 and concatenated them + // together as a single string. Now we need to sign them using RSASSA + + mbedtls_pk_context pk_context; + mbedtls_pk_init(&pk_context); + int rc = mbedtls_pk_parse_key(&pk_context, privateKey, privateKeySize, NULL, 0); + if (rc != 0) { + printf("Failed to mbedtls_pk_parse_key: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc)); + return nullptr; + } + + uint8_t oBuf[5000]; + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + + const char* pers="MyEntropy"; + + mbedtls_ctr_drbg_seed( + &ctr_drbg, + mbedtls_entropy_func, + &entropy, + (const unsigned char*)pers, + strlen(pers)); + + + uint8_t digest[32]; + rc = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), headerAndPayload, strlen((char*)headerAndPayload), digest); + if (rc != 0) { + printf("Failed to mbedtls_md: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc)); + return nullptr; + } + + size_t retSize; + rc = mbedtls_pk_sign(&pk_context, MBEDTLS_MD_SHA256, digest, sizeof(digest), oBuf, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg); + if (rc != 0) { + printf("Failed to mbedtls_pk_sign: %d (-0x%x): %s\n", rc, -rc, mbedtlsError(rc)); + return nullptr; + } + + + char base64Signature[600]; + base64url_encode((unsigned char *)oBuf, retSize, base64Signature); + + char* retData = (char*)malloc(strlen((char*)headerAndPayload) + 1 + strlen((char*)base64Signature) + 1); + + sprintf(retData, "%s.%s", headerAndPayload, base64Signature); + + mbedtls_pk_free(&pk_context); + return retData; +} + +void run(void *) { + printf("Task starting!\n"); + const char* projectId = "test-214415"; + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, "time-a-g.nist.gov"); + sntp_init(); + // https://www.epochconverter.com/ + time_t now = 0; + time(&now); + while(now < 5000) { + vTaskDelay(1000 * portTICK_RATE_MS); + time(&now); + } + + char* jwt = createGCPJWT(projectId, device1_private_pem, device1_private_pem_len); + if (jwt != nullptr) { + printf("JWT: %s\n", jwt); + free(jwt); + } + vTaskDelete(nullptr); +} + +esp_err_t event_handler(void *ctx, system_event_t *event) +{ + if (event->event_id == SYSTEM_EVENT_STA_GOT_IP) { + printf("Our IP address is " IPSTR "\n", + IP2STR(&event->event_info.got_ip.ip_info.ip)); + printf("We have now connected to a station and can do things...\n"); + xTaskCreate(run, "run", 16000, nullptr, 0, nullptr); + + } + + if (event->event_id == SYSTEM_EVENT_STA_START) { + ESP_ERROR_CHECK(esp_wifi_connect()); + } + return ESP_OK; +} + +void app_main(void) +{ + printf("Starting\n"); + nvs_flash_init(); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + wifi_config_t sta_config; + memset(&sta_config, 0, sizeof(sta_config)); + strcpy((char*)sta_config.sta.ssid, SSID); + strcpy((char*)sta_config.sta.password, SSID_PASSWORD); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + ESP_ERROR_CHECK(esp_wifi_start()); +} + diff --git a/cpp_utils/AWS.cpp b/cpp_utils/AWS.cpp index 561162c3..7687be21 100644 --- a/cpp_utils/AWS.cpp +++ b/cpp_utils/AWS.cpp @@ -19,6 +19,129 @@ AWS::AWS() { AWS::~AWS() { } +/** + * Convert an AWS IoT error code to a string representation. + * @param err The error code to be mapped. + * @return A string representation of the error code. + */ +/* static */ std::string AWS::errorToString(IoT_Error_t err) { + switch(err) { + case NETWORK_PHYSICAL_LAYER_CONNECTED : + return "NETWORK_PHYSICAL_LAYER_CONNECTED"; + case NETWORK_MANUALLY_DISCONNECTED : + return "NETWORK_MANUALLY_DISCONNECTED"; + case NETWORK_ATTEMPTING_RECONNECT: + return "NETWORK_ATTEMPTING_RECONNECT"; + case NETWORK_RECONNECTED: + return "NETWORK_RECONNECTED"; + case MQTT_NOTHING_TO_READ : + return "MQTT_NOTHING_TO_READ"; + case MQTT_CONNACK_CONNECTION_ACCEPTED: + return "MQTT_CONNACK_CONNECTION_ACCEPTED"; + case SUCCESS : + return "SUCCESS"; + case FAILURE: + return "FAILURE"; + case NULL_VALUE_ERROR : + return "NULL_VALUE_ERROR"; + case TCP_CONNECTION_ERROR : + return "TCP_CONNECTION_ERROR"; + case SSL_CONNECTION_ERROR: + return "SSL_CONNECTION_ERROR"; + case TCP_SETUP_ERROR : + return "TCP_SETUP_ERROR"; + case NETWORK_SSL_CONNECT_TIMEOUT_ERROR : + return "NETWORK_SSL_CONNECT_TIMEOUT_ERROR"; + case NETWORK_SSL_WRITE_ERROR : + return "NETWORK_SSL_WRITE_ERROR"; + case NETWORK_SSL_INIT_ERROR : + return "NETWORK_SSL_INIT_ERROR"; + case NETWORK_SSL_CERT_ERROR : + return "NETWORK_SSL_CERT_ERROR"; + case NETWORK_SSL_WRITE_TIMEOUT_ERROR : + return "NETWORK_SSL_WRITE_TIMEOUT_ERROR"; + case NETWORK_SSL_READ_TIMEOUT_ERROR : + return "NETWORK_SSL_READ_TIMEOUT_ERROR"; + case NETWORK_SSL_READ_ERROR : + return "NETWORK_SSL_READ_ERROR"; + case NETWORK_DISCONNECTED_ERROR : + return "NETWORK_DISCONNECTED_ERROR"; + case NETWORK_RECONNECT_TIMED_OUT_ERROR: + return "NETWORK_RECONNECT_TIMED_OUT_ERROR"; + case NETWORK_ALREADY_CONNECTED_ERROR : + return "NETWORK_ALREADY_CONNECTED_ERROR"; + case NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED : + return "NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED"; + case NETWORK_SSL_UNKNOWN_ERROR : + return "NETWORK_SSL_UNKNOWN_ERROR"; + case NETWORK_PHYSICAL_LAYER_DISCONNECTED : + return "NETWORK_PHYSICAL_LAYER_DISCONNECTED"; + case NETWORK_X509_ROOT_CRT_PARSE_ERROR : + return "NETWORK_X509_ROOT_CRT_PARSE_ERROR"; + case NETWORK_X509_DEVICE_CRT_PARSE_ERROR : + return "NETWORK_X509_DEVICE_CRT_PARSE_ERROR"; + case NETWORK_PK_PRIVATE_KEY_PARSE_ERROR : + return "NETWORK_PK_PRIVATE_KEY_PARSE_ERROR"; + case NETWORK_ERR_NET_SOCKET_FAILED : + return "NETWORK_ERR_NET_SOCKET_FAILED"; + case NETWORK_ERR_NET_UNKNOWN_HOST : + return "NETWORK_ERR_NET_UNKNOWN_HOST"; + case NETWORK_ERR_NET_CONNECT_FAILED : + return "NETWORK_ERR_NET_CONNECT_FAILED"; + case NETWORK_SSL_NOTHING_TO_READ : + return "NETWORK_SSL_NOTHING_TO_READ"; + case MQTT_CONNECTION_ERROR : + return "MQTT_CONNECTION_ERROR"; + case MQTT_CONNECT_TIMEOUT_ERROR : + return "MQTT_CONNECT_TIMEOUT_ERROR"; + case MQTT_REQUEST_TIMEOUT_ERROR: + return "MQTT_REQUEST_TIMEOUT_ERROR"; + case MQTT_UNEXPECTED_CLIENT_STATE_ERROR : + return "MQTT_UNEXPECTED_CLIENT_STATE_ERROR"; + case MQTT_CLIENT_NOT_IDLE_ERROR : + return "MQTT_CLIENT_NOT_IDLE_ERROR"; + case MQTT_RX_MESSAGE_PACKET_TYPE_INVALID_ERROR : + return "MQTT_RX_MESSAGE_PACKET_TYPE_INVALID_ERROR"; + case MQTT_RX_BUFFER_TOO_SHORT_ERROR : + return "MQTT_RX_BUFFER_TOO_SHORT_ERROR"; + case MQTT_TX_BUFFER_TOO_SHORT_ERROR : + return "MQTT_TX_BUFFER_TOO_SHORT_ERROR"; + case MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR : + return "MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR"; + case MQTT_DECODE_REMAINING_LENGTH_ERROR : + return "MQTT_DECODE_REMAINING_LENGTH_ERROR"; + case MQTT_CONNACK_UNKNOWN_ERROR : + return "MQTT_CONNACK_UNKNOWN_ERROR"; + case MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR : + return "MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR"; + case MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR: + return "MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR"; + case MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR : + return "MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR"; + case MQTT_CONNACK_BAD_USERDATA_ERROR: + return "MQTT_CONNACK_BAD_USERDATA_ERROR"; + case MQTT_CONNACK_NOT_AUTHORIZED_ERROR : + return "MQTT_CONNACK_NOT_AUTHORIZED_ERROR"; + case JSON_PARSE_ERROR : + return "JSON_PARSE_ERROR"; + case SHADOW_WAIT_FOR_PUBLISH : + return "SHADOW_WAIT_FOR_PUBLISH"; + case SHADOW_JSON_BUFFER_TRUNCATED : + return "SHADOW_JSON_BUFFER_TRUNCATED"; + case SHADOW_JSON_ERROR : + return "SHADOW_JSON_ERROR"; + case MUTEX_INIT_ERROR : + return "MUTEX_INIT_ERROR"; + case MUTEX_LOCK_ERROR: + return "MUTEX_LOCK_ERROR"; + case MUTEX_UNLOCK_ERROR : + return "MUTEX_UNLOCK_ERROR"; + case MUTEX_DESTROY_ERROR : + return "MUTEX_DESTROY_ERROR"; + default: + return "Unknown error!"; + } +} // AWS#errorToString /** * @brief Connect to the AWS IoT service. diff --git a/cpp_utils/AWS.h b/cpp_utils/AWS.h index 5d2c891c..abbd0613 100644 --- a/cpp_utils/AWS.h +++ b/cpp_utils/AWS.h @@ -24,6 +24,7 @@ class AWS { void connect(std::string clientId); void disconnect(); + static std::string errorToString(IoT_Error_t err); // Convert an AWS IoT error code to a string representation. void init(std::string host=CONFIG_AWS_IOT_MQTT_HOST, uint16_t port=CONFIG_AWS_IOT_MQTT_PORT); void publish(std::string topic, std::string payload, QoS qos = QOS0); void subscribe(std::string topic); diff --git a/cpp_utils/Apa102.cpp b/cpp_utils/Apa102.cpp index 274ec83f..c35c9150 100644 --- a/cpp_utils/Apa102.cpp +++ b/cpp_utils/Apa102.cpp @@ -37,7 +37,7 @@ void Apa102::show() { double brigthnessScale = getBrightness() / 100.0; // Loop over all the pixels in the pixels array to set the colors. - for (int i=0; i #include #include "BLEAdvertisedDevice.h" #include "BLEUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" -#endif +#define LOG_TAG "" +#else +#include "esp_log.h" static const char* LOG_TAG="BLEAdvertisedDevice"; +#endif BLEAdvertisedDevice::BLEAdvertisedDevice() { m_adFlag = 0; @@ -137,9 +139,8 @@ BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is * @return Return true if service is advertised */ bool BLEAdvertisedDevice::isAdvertisingService(BLEUUID uuid){ - for (int i = 0; i < m_serviceUUIDs.size(); ++i) { - if(m_serviceUUIDs[i].equals(uuid)) - return true; + for (int i = 0; i < m_serviceUUIDs.size(); i++) { + if (m_serviceUUIDs[i].equals(uuid)) return true; } return false; } @@ -229,12 +230,13 @@ bool BLEAdvertisedDevice::haveTXPower() { * * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile */ -void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { +void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len) { uint8_t length; uint8_t ad_type; uint8_t sizeConsumed = 0; bool finished = false; - setPayload(payload); + m_payload = payload; + m_payloadLength = total_len; while(!finished) { length = *payload; // Retrieve the length of the record. @@ -275,7 +277,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { case ESP_BLE_AD_TYPE_16SRV_CMPL: case ESP_BLE_AD_TYPE_16SRV_PART: { // Adv Data Type: 0x02 for (int var = 0; var < length/2; ++var) { - setServiceUUID(BLEUUID(*reinterpret_cast(payload+var*2))); + setServiceUUID(BLEUUID(*reinterpret_cast(payload + var * 2))); } break; } // ESP_BLE_AD_TYPE_16SRV_PART @@ -283,7 +285,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { case ESP_BLE_AD_TYPE_32SRV_CMPL: case ESP_BLE_AD_TYPE_32SRV_PART: { // Adv Data Type: 0x04 for (int var = 0; var < length/4; ++var) { - setServiceUUID(BLEUUID(*reinterpret_cast(payload+var*4))); + setServiceUUID(BLEUUID(*reinterpret_cast(payload + var * 4))); } break; } // ESP_BLE_AD_TYPE_32SRV_PART @@ -309,10 +311,10 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA"); break; } - uint16_t uuid = *(uint16_t *)payload; + uint16_t uuid = *(uint16_t*)payload; setServiceDataUUID(BLEUUID(uuid)); if (length > 2) { - setServiceData(std::string(reinterpret_cast(payload+2), length-2)); + setServiceData(std::string(reinterpret_cast(payload + 2), length - 2)); } break; } //ESP_BLE_AD_TYPE_SERVICE_DATA @@ -322,10 +324,10 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA"); break; } - uint32_t uuid = *(uint32_t *)payload; + uint32_t uuid = *(uint32_t*) payload; setServiceDataUUID(BLEUUID(uuid)); if (length > 4) { - setServiceData(std::string(reinterpret_cast(payload+4), length-4)); + setServiceData(std::string(reinterpret_cast(payload + 4), length - 4)); } break; } //ESP_BLE_AD_TYPE_32SERVICE_DATA @@ -338,7 +340,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { setServiceDataUUID(BLEUUID(payload, (size_t)16, false)); if (length > 16) { - setServiceData(std::string(reinterpret_cast(payload+16), length-16)); + setServiceData(std::string(reinterpret_cast(payload + 16), length - 16)); } break; } //ESP_BLE_AD_TYPE_32SERVICE_DATA @@ -352,9 +354,9 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { } // Length <> 0 - if (sizeConsumed >=31 || length == 0) { + if (sizeConsumed >= total_len) finished = true; - } + } // !finished } // parseAdvertisement @@ -395,7 +397,7 @@ void BLEAdvertisedDevice::setAppearance(uint16_t appearance) { void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) { m_manufacturerData = manufacturerData; m_haveManufacturerData = true; - char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)m_manufacturerData.data(), (uint8_t)m_manufacturerData.length()); + char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*) m_manufacturerData.data(), (uint8_t) m_manufacturerData.length()); ESP_LOGD(LOG_TAG, "- manufacturer data: %s", pHex); free(pHex); } // setManufacturerData @@ -511,10 +513,20 @@ uint8_t* BLEAdvertisedDevice::getPayload() { return m_payload; } -void BLEAdvertisedDevice::setPayload(uint8_t* payload) { - m_payload = payload; +esp_ble_addr_type_t BLEAdvertisedDevice::getAddressType() { + return m_addressType; +} + +void BLEAdvertisedDevice::setAddressType(esp_ble_addr_type_t type) { + m_addressType = type; +} + +size_t BLEAdvertisedDevice::getPayloadLength() { + return m_payloadLength; } +void BLEAdvertisedDeviceCallbacks::onResult(BLEAdvertisedDevice dev) {} +void BLEAdvertisedDeviceCallbacks::onResult(BLEAdvertisedDevice* dev) {} #endif /* CONFIG_BT_ENABLED */ diff --git a/cpp_utils/BLEAdvertisedDevice.h b/cpp_utils/BLEAdvertisedDevice.h index a3b1e6e2..cd206d4a 100644 --- a/cpp_utils/BLEAdvertisedDevice.h +++ b/cpp_utils/BLEAdvertisedDevice.h @@ -40,6 +40,9 @@ class BLEAdvertisedDevice { BLEUUID getServiceUUID(); int8_t getTXPower(); uint8_t* getPayload(); + size_t getPayloadLength(); + esp_ble_addr_type_t getAddressType(); + void setAddressType(esp_ble_addr_type_t type); bool isAdvertisingService(BLEUUID uuid); @@ -56,7 +59,7 @@ class BLEAdvertisedDevice { private: friend class BLEScan; - void parseAdvertisement(uint8_t* payload); + void parseAdvertisement(uint8_t* payload, size_t total_len=62); void setAddress(BLEAddress address); void setAdFlag(uint8_t adFlag); void setAdvertizementResult(uint8_t* payload); @@ -70,8 +73,6 @@ class BLEAdvertisedDevice { void setServiceUUID(const char* serviceUUID); void setServiceUUID(BLEUUID serviceUUID); void setTXPower(int8_t txPower); - void setPayload(uint8_t* payload); - bool m_haveAppearance; bool m_haveManufacturerData; @@ -94,7 +95,9 @@ class BLEAdvertisedDevice { int8_t m_txPower; std::string m_serviceData; BLEUUID m_serviceDataUUID; - uint8_t* m_payload; + uint8_t* m_payload = nullptr; + size_t m_payloadLength = 0; + esp_ble_addr_type_t m_addressType; }; /** @@ -113,7 +116,8 @@ class BLEAdvertisedDeviceCallbacks { * As we are scanning, we will find new devices. When found, this call back is invoked with a reference to the * device that was found. During any individual scan, a device will only be detected one time. */ - virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0; + virtual void onResult(BLEAdvertisedDevice advertisedDevice); + virtual void onResult(BLEAdvertisedDevice* advertisedDevice); }; #endif /* CONFIG_BT_ENABLED */ diff --git a/cpp_utils/BLEAdvertising.cpp b/cpp_utils/BLEAdvertising.cpp index 4b3cb8d6..230d77cb 100644 --- a/cpp_utils/BLEAdvertising.cpp +++ b/cpp_utils/BLEAdvertising.cpp @@ -19,16 +19,18 @@ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) #include "BLEAdvertising.h" -#include #include #include "BLEUtils.h" #include "GeneralUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEAdvertising"; #endif -static const char* LOG_TAG = "BLEAdvertising"; /** @@ -56,6 +58,7 @@ BLEAdvertising::BLEAdvertising() { m_advParams.own_addr_type = BLE_ADDR_TYPE_PUBLIC; m_advParams.channel_map = ADV_CHNL_ALL; m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; + m_advParams.peer_addr_type = BLE_ADDR_TYPE_PUBLIC; m_customAdvData = false; // No custom advertising data m_customScanResponseData = false; // No custom scan response data @@ -92,22 +95,31 @@ void BLEAdvertising::setAppearance(uint16_t appearance) { } // setAppearance void BLEAdvertising::setMinInterval(uint16_t mininterval) { - m_advData.min_interval = mininterval; m_advParams.adv_int_min = mininterval; } // setMinInterval void BLEAdvertising::setMaxInterval(uint16_t maxinterval) { - m_advData.max_interval = maxinterval; m_advParams.adv_int_max = maxinterval; } // setMaxInterval +void BLEAdvertising::setMinPreferred(uint16_t mininterval) { + m_advData.min_interval = mininterval; +} // + +void BLEAdvertising::setMaxPreferred(uint16_t maxinterval) { + m_advData.max_interval = maxinterval; +} // + +void BLEAdvertising::setScanResponse(bool set) { + m_scanResp = set; +} /** * @brief Set the filtering for the scan filter. * @param [in] scanRequestWhitelistOnly If true, only allow scan requests from those on the white list. * @param [in] connectWhitelistOnly If true, only allow connections from those on the white list. */ -void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) { +void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) { ESP_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly); if (!scanRequestWhitelistOnly && !connectWhitelistOnly) { m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; @@ -173,21 +185,20 @@ void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData void BLEAdvertising::start() { ESP_LOGD(LOG_TAG, ">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData); - // We have a vector of service UUIDs that we wish to advertise. In order to use the // ESP-IDF framework, these must be supplied in a contiguous array of their 128bit (16 byte) // representations. If we have 1 or more services to advertise then we allocate enough // storage to host them and then copy them in one at a time into the contiguous storage. int numServices = m_serviceUUIDs.size(); if (numServices > 0) { - m_advData.service_uuid_len = 16*numServices; - m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len]; + m_advData.service_uuid_len = 16 * numServices; + m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len]; uint8_t* p = m_advData.p_service_uuid; - for (int i=0; iuuid.uuid128, 16); - p+=16; + p += 16; } } else { m_advData.service_uuid_len = 0; @@ -196,9 +207,11 @@ void BLEAdvertising::start() { esp_err_t errRc; - if (m_customAdvData == false) { - // Set the configuration for advertising. + if (!m_customAdvData) { + // Set the configuration for advertising. m_advData.set_scan_rsp = false; + m_advData.include_name = !m_scanResp; + m_advData.include_txpower = !m_scanResp; errRc = ::esp_ble_gap_config_adv_data(&m_advData); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -206,8 +219,10 @@ void BLEAdvertising::start() { } } - if (m_customScanResponseData == false) { + if (!m_customScanResponseData && m_scanResp) { m_advData.set_scan_rsp = true; + m_advData.include_name = m_scanResp; + m_advData.include_txpower = m_scanResp; errRc = ::esp_ble_gap_config_adv_data(&m_advData); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -270,7 +285,7 @@ void BLEAdvertisementData::setAppearance(uint16_t appearance) { char cdata[2]; cdata[0] = 3; cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE; // 0x19 - addData(std::string(cdata, 2) + std::string((char *)&appearance,2)); + addData(std::string(cdata, 2) + std::string((char*) &appearance, 2)); } // setAppearance @@ -280,12 +295,12 @@ void BLEAdvertisementData::setAppearance(uint16_t appearance) { */ void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { char cdata[2]; - switch(uuid.bitSize()) { + switch (uuid.bitSize()) { case 16: { // [Len] [0x02] [LL] [HH] cdata[0] = 3; cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03 - addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2)); + addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2)); break; } @@ -293,7 +308,7 @@ void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { // [Len] [0x04] [LL] [LL] [HH] [HH] cdata[0] = 5; cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05 - addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4)); + addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4)); break; } @@ -301,7 +316,7 @@ void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { // [Len] [0x04] [0] [1] ... [15] cdata[0] = 17; cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07 - addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16)); + addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->uuid.uuid128, 16)); break; } @@ -341,7 +356,7 @@ void BLEAdvertisementData::setManufacturerData(std::string data) { char cdata[2]; cdata[0] = data.length() + 1; cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff - addData(std::string(cdata, 2) + data); + addData(std::string(cdata, 2) + data); ESP_LOGD("BLEAdvertisementData", "<< setManufacturerData"); } // setManufacturerData @@ -355,7 +370,7 @@ void BLEAdvertisementData::setName(std::string name) { char cdata[2]; cdata[0] = name.length() + 1; cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09 - addData(std::string(cdata, 2) + name); + addData(std::string(cdata, 2) + name); ESP_LOGD("BLEAdvertisementData", "<< setName"); } // setName @@ -366,12 +381,12 @@ void BLEAdvertisementData::setName(std::string name) { */ void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { char cdata[2]; - switch(uuid.bitSize()) { + switch (uuid.bitSize()) { case 16: { // [Len] [0x02] [LL] [HH] cdata[0] = 3; cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART; // 0x02 - addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2)); + addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid16, 2)); break; } @@ -379,7 +394,7 @@ void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { // [Len] [0x04] [LL] [LL] [HH] [HH] cdata[0] = 5; cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART; // 0x04 - addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4)); + addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid32, 4)); break; } @@ -387,7 +402,7 @@ void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { // [Len] [0x04] [0] [1] ... [15] cdata[0] = 17; cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06 - addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16)); + addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->uuid.uuid128, 16)); break; } @@ -404,12 +419,12 @@ void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { */ void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) { char cdata[2]; - switch(uuid.bitSize()) { + switch (uuid.bitSize()) { case 16: { // [Len] [0x16] [UUID16] data cdata[0] = data.length() + 3; cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA; // 0x16 - addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid16,2) + data); + addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid16, 2) + data); break; } @@ -417,7 +432,7 @@ void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) { // [Len] [0x20] [UUID32] data cdata[0] = data.length() + 5; cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA; // 0x20 - addData(std::string(cdata, 2) + std::string((char *)&uuid.getNative()->uuid.uuid32,4) + data); + addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid32, 4) + data); break; } @@ -425,7 +440,7 @@ void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) { // [Len] [0x21] [UUID128] data cdata[0] = data.length() + 17; cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA; // 0x21 - addData(std::string(cdata, 2) + std::string((char *)uuid.getNative()->uuid.uuid128,16) + data); + addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->uuid.uuid128, 16) + data); break; } @@ -444,12 +459,11 @@ void BLEAdvertisementData::setShortName(std::string name) { char cdata[2]; cdata[0] = name.length() + 1; cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08 - addData(std::string(cdata, 2) + name); + addData(std::string(cdata, 2) + name); ESP_LOGD("BLEAdvertisementData", "<< setShortName"); } // setShortName - /** * @brief Retrieve the payload that is to be advertised. * @return The payload that is to be advertised. @@ -458,5 +472,34 @@ std::string BLEAdvertisementData::getPayload() { return m_payload; } // getPayload +void BLEAdvertising::handleGAPEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param) { + + ESP_LOGD(LOG_TAG, "handleGAPEvent [event no: %d]", (int)event); + + switch(event) { + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { + // m_semaphoreSetAdv.give(); + break; + } + case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: { + // m_semaphoreSetAdv.give(); + break; + } + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { + // m_semaphoreSetAdv.give(); + break; + } + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { + ESP_LOGI(LOG_TAG, "STOP advertising"); + start(); + break; + } + default: + break; + } +} + #endif /* CONFIG_BT_ENABLED */ diff --git a/cpp_utils/BLEAdvertising.h b/cpp_utils/BLEAdvertising.h index e3165298..3128b50f 100644 --- a/cpp_utils/BLEAdvertising.h +++ b/cpp_utils/BLEAdvertising.h @@ -12,6 +12,7 @@ #include #include "BLEUUID.h" #include +#include "FreeRTOS.h" /** * @brief Advertisement data set by the programmer to be published by the %BLE server. @@ -56,13 +57,22 @@ class BLEAdvertising { void setAdvertisementData(BLEAdvertisementData& advertisementData); void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly); void setScanResponseData(BLEAdvertisementData& advertisementData); + void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM); + + void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); + void setMinPreferred(uint16_t); + void setMaxPreferred(uint16_t); + void setScanResponse(bool); private: esp_ble_adv_data_t m_advData; esp_ble_adv_params_t m_advParams; std::vector m_serviceUUIDs; - bool m_customAdvData; // Are we using custom advertising data? - bool m_customScanResponseData; // Are we using custom scan response data? + bool m_customAdvData = false; // Are we using custom advertising data? + bool m_customScanResponseData = false; // Are we using custom scan response data? + FreeRTOS::Semaphore m_semaphoreSetAdv = FreeRTOS::Semaphore("startAdvert"); + bool m_scanResp = true; + }; #endif /* CONFIG_BT_ENABLED */ -#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ +#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ \ No newline at end of file diff --git a/cpp_utils/BLEBeacon.cpp b/cpp_utils/BLEBeacon.cpp index a63197ca..68f8d8ed 100644 --- a/cpp_utils/BLEBeacon.cpp +++ b/cpp_utils/BLEBeacon.cpp @@ -7,12 +7,17 @@ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) #include -#include #include "BLEBeacon.h" +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) +#include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEBeacon"; +#endif #define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) -static const char LOG_TAG[] = "BLEBeacon"; BLEBeacon::BLEBeacon() { m_beaconData.manufacturerId = 0x4c00; @@ -25,7 +30,7 @@ BLEBeacon::BLEBeacon() { } // BLEBeacon std::string BLEBeacon::getData() { - return std::string((char*)&m_beaconData, sizeof(m_beaconData)); + return std::string((char*) &m_beaconData, sizeof(m_beaconData)); } // getData uint16_t BLEBeacon::getMajor() { diff --git a/cpp_utils/BLEBeacon.h b/cpp_utils/BLEBeacon.h index 0b02e2bd..277bd670 100644 --- a/cpp_utils/BLEBeacon.h +++ b/cpp_utils/BLEBeacon.h @@ -23,7 +23,7 @@ class BLEBeacon { uint16_t major; uint16_t minor; int8_t signalPower; - } __attribute__((packed))m_beaconData; + } __attribute__((packed)) m_beaconData; public: BLEBeacon(); std::string getData(); diff --git a/cpp_utils/BLECharacteristic.cpp b/cpp_utils/BLECharacteristic.cpp index 931c753d..2868ee26 100644 --- a/cpp_utils/BLECharacteristic.cpp +++ b/cpp_utils/BLECharacteristic.cpp @@ -11,7 +11,6 @@ #include #include #include "sdkconfig.h" -#include #include #include "BLECharacteristic.h" #include "BLEService.h" @@ -19,11 +18,13 @@ #include "BLEUtils.h" #include "BLE2902.h" #include "GeneralUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" -#endif - +#define LOG_TAG "" +#else +#include "esp_log.h" static const char* LOG_TAG = "BLECharacteristic"; +#endif #define NULL_HANDLE (0xffff) @@ -47,12 +48,12 @@ BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) { m_properties = (esp_gatt_char_prop_t)0; m_pCallbacks = nullptr; - setBroadcastProperty((properties & PROPERTY_BROADCAST) !=0); - setReadProperty((properties & PROPERTY_READ) !=0); - setWriteProperty((properties & PROPERTY_WRITE) !=0); - setNotifyProperty((properties & PROPERTY_NOTIFY) !=0); - setIndicateProperty((properties & PROPERTY_INDICATE) !=0); - setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) !=0); + setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0); + setReadProperty((properties & PROPERTY_READ) != 0); + setWriteProperty((properties & PROPERTY_WRITE) != 0); + setNotifyProperty((properties & PROPERTY_NOTIFY) != 0); + setIndicateProperty((properties & PROPERTY_INDICATE) != 0); + setWriteNoResponseProperty((properties & PROPERTY_WRITE_NR) != 0); } // BLECharacteristic /** @@ -87,7 +88,7 @@ void BLECharacteristic::executeCreate(BLEService* pService) { return; } - m_pService = pService; // Save the service for to which this characteristic belongs. + m_pService = pService; // Save the service to which this characteristic belongs. ESP_LOGD(LOG_TAG, "Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s", getUUID().toString().c_str(), @@ -97,20 +98,11 @@ void BLECharacteristic::executeCreate(BLEService* pService) { control.auto_rsp = ESP_GATT_RSP_BY_APP; m_semaphoreCreateEvt.take("executeCreate"); - - /* - esp_attr_value_t value; - value.attr_len = m_value.getLength(); - value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; - value.attr_value = m_value.getData(); - */ - esp_err_t errRc = ::esp_ble_gatts_add_char( m_pService->getHandle(), getUUID().getNative(), static_cast(m_permissions), getProperties(), - //&value, nullptr, &control); // Whether to auto respond or not. @@ -118,15 +110,9 @@ void BLECharacteristic::executeCreate(BLEService* pService) { ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; } - m_semaphoreCreateEvt.wait("executeCreate"); - // Now that we have registered the characteristic, we must also register all the descriptors associated with this - // characteristic. We iterate through each of those and invoke the registration call to register them with the - // ESP environment. - BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); - while (pDescriptor != nullptr) { pDescriptor->executeCreate(this); pDescriptor = m_descriptorMap.getNext(); @@ -198,6 +184,14 @@ std::string BLECharacteristic::getValue() { return m_value.getValue(); } // getValue +/** + * @brief Retrieve the current raw data of the characteristic. + * @return A pointer to storage containing the current characteristic data. + */ +uint8_t* BLECharacteristic::getData() { + return m_value.getData(); +} // getData + /** * Handle a GATT server event. @@ -230,21 +224,24 @@ void BLECharacteristic::handleGATTServerEvent( // - uint8_t exec_write_flag - Either ESP_GATT_PREP_WRITE_EXEC or ESP_GATT_PREP_WRITE_CANCEL // case ESP_GATTS_EXEC_WRITE_EVT: { - if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { - m_value.commit(); - if (m_pCallbacks != nullptr) { - m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. + if(m_writeEvt){ + m_writeEvt = false; + if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { + m_value.commit(); + if (m_pCallbacks != nullptr) { + m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. + } + } else { + m_value.cancel(); + } + // ??? + esp_err_t errRc = ::esp_ble_gatts_send_response( + gatts_if, + param->write.conn_id, + param->write.trans_id, ESP_GATT_OK, nullptr); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } - } else { - m_value.cancel(); - } - - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, - param->write.conn_id, - param->write.trans_id, ESP_GATT_OK, nullptr); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } break; } // ESP_GATTS_EXEC_WRITE_EVT @@ -257,9 +254,13 @@ void BLECharacteristic::handleGATTServerEvent( // - uint16_t service_handle // - esp_bt_uuid_t char_uuid case ESP_GATTS_ADD_CHAR_EVT: { - if (getUUID().equals(BLEUUID(param->add_char.char_uuid)) && - getHandle() == param->add_char.attr_handle && - getService()->getHandle()==param->add_char.service_handle) { + if (getHandle() == param->add_char.attr_handle) { + // we have created characteristic, now we can create descriptors + // BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); + // while (pDescriptor != nullptr) { + // pDescriptor->executeCreate(this); + // pDescriptor = m_descriptorMap.getNext(); + // } // End while m_semaphoreCreateEvt.give(); } break; @@ -286,8 +287,12 @@ void BLECharacteristic::handleGATTServerEvent( if (param->write.handle == m_handle) { if (param->write.is_prep) { m_value.addPart(param->write.value, param->write.len); + m_writeEvt = true; } else { setValue(param->write.value, param->write.len); + if (m_pCallbacks != nullptr && param->write.is_prep != true) { + m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. + } } ESP_LOGD(LOG_TAG, " - Response to write event: New value: handle: %.2x, uuid: %s", @@ -315,9 +320,6 @@ void BLECharacteristic::handleGATTServerEvent( } } // Response needed - if (m_pCallbacks != nullptr && param->write.is_prep != true) { - m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler. - } } // Match on handles. break; } // ESP_GATTS_WRITE_EVT @@ -360,11 +362,10 @@ void BLECharacteristic::handleGATTServerEvent( // The following code has deliberately not been factored to make it fewer statements because this would cloud the // the logic flow comprehension. // - // TODO requires some more research to confirm that 512 is max PDU like in bluetooth specs - uint16_t maxOffset = BLEDevice::getMTU() - 1; - if (BLEDevice::getMTU() > 512) { - maxOffset = 512; - } + + // get mtu for peer device that we are sending read request to + uint16_t maxOffset = getService()->getServer()->getPeerMTU(param->read.conn_id) - 1; + ESP_LOGD(LOG_TAG, "mtu value: %d", maxOffset); if (param->read.need_rsp) { ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); esp_gatt_rsp_t rsp; @@ -390,10 +391,9 @@ void BLECharacteristic::handleGATTServerEvent( if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback m_pCallbacks->onRead(this); // Invoke the read callback. } - std::string value = m_value.getValue(); - if (value.length()+1 > maxOffset) { + if (value.length() + 1 > maxOffset) { // Too big for a single shot entry. m_value.setReadOffset(maxOffset); rsp.attr_value.len = maxOffset; @@ -405,6 +405,10 @@ void BLECharacteristic::handleGATTServerEvent( rsp.attr_value.offset = 0; memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); } + + // if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback + // m_pCallbacks->onRead(this); // Invoke the read callback. + // } } rsp.attr_value.handle = param->read.handle; rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; @@ -434,12 +438,13 @@ void BLECharacteristic::handleGATTServerEvent( // - uint16_t conn_id – The connection used. // case ESP_GATTS_CONF_EVT: { - m_semaphoreConfEvt.give(); + // ESP_LOGD(LOG_TAG, "m_handle = %d, conf->handle = %d", m_handle, param->conf.handle); + if(param->conf.conn_id == getService()->getServer()->getConnId()) // && param->conf.handle == m_handle) // bug in esp-idf and not implemented in arduino yet + m_semaphoreConfEvt.give(param->conf.status); break; } case ESP_GATTS_CONNECT_EVT: { - m_semaphoreConfEvt.give(); break; } @@ -471,45 +476,7 @@ void BLECharacteristic::handleGATTServerEvent( void BLECharacteristic::indicate() { ESP_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length()); - - assert(getService() != nullptr); - assert(getService()->getServer() != nullptr); - - GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); - - if (getService()->getServer()->getConnectedCount() == 0) { - ESP_LOGD(LOG_TAG, "<< indicate: No connected clients."); - return; - } - - // Test to see if we have a 0x2902 descriptor. If we do, then check to see if indications are enabled - // and, if not, prevent the indication. - - BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); - if (p2902 != nullptr && !p2902->getIndications()) { - ESP_LOGD(LOG_TAG, "<< indications disabled; ignoring"); - return; - } - - if (m_value.getValue().length() > (BLEDevice::getMTU() - 3)) { - ESP_LOGI(LOG_TAG, "- Truncating to %d bytes (maximum indicate size)", BLEDevice::getMTU() - 3); - } - - size_t length = m_value.getValue().length(); - - m_semaphoreConfEvt.take("indicate"); - - esp_err_t errRc = ::esp_ble_gatts_send_indicate( - getService()->getServer()->getGattsIf(), - getService()->getServer()->getConnId(), - getHandle(), length, (uint8_t*)m_value.getValue().data(), true); // The need_confirm = true makes this an indication. - - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; - } - - m_semaphoreConfEvt.wait("indicate"); + notify(false); ESP_LOGD(LOG_TAG, "<< indicate"); } // indicate @@ -520,14 +487,12 @@ void BLECharacteristic::indicate() { * will not block; it is a fire and forget. * @return N/A. */ -void BLECharacteristic::notify() { +void BLECharacteristic::notify(bool is_notification) { ESP_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length()); - assert(getService() != nullptr); assert(getService()->getServer() != nullptr); - GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length()); if (getService()->getServer()->getConnectedCount() == 0) { @@ -538,31 +503,44 @@ void BLECharacteristic::notify() { // Test to see if we have a 0x2902 descriptor. If we do, then check to see if notification is enabled // and, if not, prevent the notification. - BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); - if (p2902 != nullptr && !p2902->getNotifications()) { - ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring"); + BLE2902* p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902); + if(p2902 == nullptr){ + ESP_LOGE(LOG_TAG, "Characteristic without 0x2902 descriptor"); return; } - - if (m_value.getValue().length() > (BLEDevice::getMTU() - 3)) { - ESP_LOGI(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", BLEDevice::getMTU() - 3); + if(is_notification) { + if (p2902 != nullptr && !p2902->getNotifications()) { + ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring"); + return; + } } - - size_t length = m_value.getValue().length(); - - m_semaphoreConfEvt.take("notify"); - - esp_err_t errRc = ::esp_ble_gatts_send_indicate( - getService()->getServer()->getGattsIf(), - getService()->getServer()->getConnId(), - getHandle(), length, (uint8_t*)m_value.getValue().data(), false); // The need_confirm = false makes this a notify. - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_indicate: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + else{ + if (p2902 != nullptr && !p2902->getIndications()) { + ESP_LOGD(LOG_TAG, "<< indications disabled; ignoring"); + return; + } } + for (auto &myPair : getService()->getServer()->getPeerDevices(false)) { + uint16_t _mtu = (myPair.second.mtu); + if (m_value.getValue().length() > _mtu - 3) { + ESP_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3); + } - m_semaphoreConfEvt.wait("notify"); - + size_t length = m_value.getValue().length(); + if(!is_notification) + m_semaphoreConfEvt.take("indicate"); + esp_err_t errRc = ::esp_ble_gatts_send_indicate( + getService()->getServer()->getGattsIf(), + myPair.first, + getHandle(), length, (uint8_t*)m_value.getValue().data(), !is_notification); // The need_confirm = false makes this a notify. + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc)); + m_semaphoreConfEvt.give(); + return; + } + if(!is_notification) + m_semaphoreConfEvt.wait("indicate"); + } ESP_LOGD(LOG_TAG, "<< notify"); } // Notify @@ -660,7 +638,7 @@ void BLECharacteristic::setReadProperty(bool value) { * @param [in] length The length of the data in bytes. */ void BLECharacteristic::setValue(uint8_t* data, size_t length) { - char *pHex = BLEUtils::buildHexData(nullptr, data, length); + char* pHex = BLEUtils::buildHexData(nullptr, data, length); ESP_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); free(pHex); if (length > ESP_GATT_MAX_ATTR_LEN) { @@ -685,38 +663,38 @@ void BLECharacteristic::setValue(std::string value) { void BLECharacteristic::setValue(uint16_t& data16) { uint8_t temp[2]; - temp[0]=data16; - temp[1]=data16>>8; + temp[0] = data16; + temp[1] = data16 >> 8; setValue(temp, 2); } // setValue void BLECharacteristic::setValue(uint32_t& data32) { uint8_t temp[4]; - temp[0]=data32; - temp[1]=data32>>8; - temp[2]=data32>>16; - temp[3]=data32>>24; + temp[0] = data32; + temp[1] = data32 >> 8; + temp[2] = data32 >> 16; + temp[3] = data32 >> 24; setValue(temp, 4); } // setValue void BLECharacteristic::setValue(int& data32) { uint8_t temp[4]; - temp[0]=data32; - temp[1]=data32>>8; - temp[2]=data32>>16; - temp[3]=data32>>24; + temp[0] = data32; + temp[1] = data32 >> 8; + temp[2] = data32 >> 16; + temp[3] = data32 >> 24; setValue(temp, 4); } // setValue void BLECharacteristic::setValue(float& data32) { uint8_t temp[4]; - *((float *)temp) = data32; + *((float*)temp) = data32; setValue(temp, 4); } // setValue void BLECharacteristic::setValue(double& data64) { uint8_t temp[8]; - *((double *)temp) = data64; + *((double*)temp) = data64; setValue(temp, 8); } // setValue @@ -758,12 +736,12 @@ std::string BLECharacteristic::toString() { stringstream << std::hex << std::setfill('0'); stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle; stringstream << " " << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_READ)?"Read ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE)?"Write ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)?"WriteNoResponse ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST)?"Broadcast ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)?"Notify ":"") << - ((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE)?"Indicate ":""); + ((m_properties & ESP_GATT_CHAR_PROP_BIT_READ) ? "Read " : "") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE) ? "Write " : "") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) ? "WriteNoResponse " : "") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST) ? "Broadcast " : "") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) ? "Notify " : "") << + ((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE) ? "Indicate " : ""); return stringstream.str(); } // toString @@ -775,7 +753,7 @@ BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {} * @brief Callback function to support a read request. * @param [in] pCharacteristic The characteristic that is the source of the event. */ -void BLECharacteristicCallbacks::onRead(BLECharacteristic *pCharacteristic) { +void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic) { ESP_LOGD("BLECharacteristicCallbacks", ">> onRead: default"); ESP_LOGD("BLECharacteristicCallbacks", "<< onRead"); } // onRead @@ -785,7 +763,7 @@ void BLECharacteristicCallbacks::onRead(BLECharacteristic *pCharacteristic) { * @brief Callback function to support a write request. * @param [in] pCharacteristic The characteristic that is the source of the event. */ -void BLECharacteristicCallbacks::onWrite(BLECharacteristic *pCharacteristic) { +void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) { ESP_LOGD("BLECharacteristicCallbacks", ">> onWrite: default"); ESP_LOGD("BLECharacteristicCallbacks", "<< onWrite"); } // onWrite diff --git a/cpp_utils/BLECharacteristic.h b/cpp_utils/BLECharacteristic.h index b3f8d2e9..82a8d7d0 100644 --- a/cpp_utils/BLECharacteristic.h +++ b/cpp_utils/BLECharacteristic.h @@ -27,30 +27,27 @@ class BLECharacteristicCallbacks; */ class BLEDescriptorMap { public: - void setByUUID(const char* uuid, BLEDescriptor *pDescriptor); - void setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor); - void setByHandle(uint16_t handle, BLEDescriptor *pDescriptor); + void setByUUID(const char* uuid, BLEDescriptor* pDescriptor); + void setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor); + void setByHandle(uint16_t handle, BLEDescriptor* pDescriptor); BLEDescriptor* getByUUID(const char* uuid); BLEDescriptor* getByUUID(BLEUUID uuid); BLEDescriptor* getByHandle(uint16_t handle); - std::string toString(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); + std::string toString(); + void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); BLEDescriptor* getFirst(); BLEDescriptor* getNext(); private: - std::map m_uuidMap; - std::map m_handleMap; - std::map::iterator m_iterator; + std::map m_uuidMap; + std::map m_handleMap; + std::map::iterator m_iterator; }; /** * @brief The model of a %BLE Characteristic. * - * A %BLE Characteristic is an identified value container that manages a value. It is exposed by a %BLE server and + * A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE server and * can be read and written to by a %BLE client. */ class BLECharacteristic { @@ -62,12 +59,12 @@ class BLECharacteristic { void addDescriptor(BLEDescriptor* pDescriptor); BLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID); - //size_t getLength(); BLEUUID getUUID(); std::string getValue(); + uint8_t* getData(); void indicate(); - void notify(); + void notify(bool is_notification = true); void setBroadcastProperty(bool value); void setCallbacks(BLECharacteristicCallbacks* pCallbacks); void setIndicateProperty(bool value); @@ -108,6 +105,7 @@ class BLECharacteristic { BLEService* m_pService; BLEValue m_value; esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; + bool m_writeEvt = false; void handleGATTServerEvent( esp_gatts_cb_event_t event, @@ -127,7 +125,7 @@ class BLECharacteristic { * @brief Callbacks that can be associated with a %BLE characteristic to inform of events. * * When a server application creates a %BLE characteristic, we may wish to be informed when there is either - * a read or write request to the characteristic's value. An application can register a + * a read or write request to the characteristic's value. An application can register a * sub-classed instance of this class and will be notified when such an event happens. */ class BLECharacteristicCallbacks { diff --git a/cpp_utils/BLECharacteristicMap.cpp b/cpp_utils/BLECharacteristicMap.cpp index 86a97441..d73aae99 100644 --- a/cpp_utils/BLECharacteristicMap.cpp +++ b/cpp_utils/BLECharacteristicMap.cpp @@ -56,9 +56,7 @@ BLECharacteristic* BLECharacteristicMap::getByUUID(BLEUUID uuid) { */ BLECharacteristic* BLECharacteristicMap::getFirst() { m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } + if (m_iterator == m_uuidMap.end()) return nullptr; BLECharacteristic* pRet = m_iterator->first; m_iterator++; return pRet; @@ -70,9 +68,7 @@ BLECharacteristic* BLECharacteristicMap::getFirst() { * @return The next characteristic in the map. */ BLECharacteristic* BLECharacteristicMap::getNext() { - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } + if (m_iterator == m_uuidMap.end()) return nullptr; BLECharacteristic* pRet = m_iterator->first; m_iterator++; return pRet; @@ -85,12 +81,9 @@ BLECharacteristic* BLECharacteristicMap::getNext() { * @param [in] gatts_if * @param [in] param */ -void BLECharacteristicMap::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param) { +void BLECharacteristicMap::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) { // Invoke the handler for every Service we have. - for (auto &myPair : m_uuidMap) { + for (auto& myPair : m_uuidMap) { myPair.first->handleGATTServerEvent(event, gatts_if, param); } } // handleGATTServerEvent @@ -102,9 +95,8 @@ void BLECharacteristicMap::handleGATTServerEvent( * @param [in] characteristic The characteristic to cache. * @return N/A. */ -void BLECharacteristicMap::setByHandle(uint16_t handle, - BLECharacteristic *characteristic) { - m_handleMap.insert(std::pair(handle, characteristic)); +void BLECharacteristicMap::setByHandle(uint16_t handle, BLECharacteristic* characteristic) { + m_handleMap.insert(std::pair(handle, characteristic)); } // setByHandle @@ -114,10 +106,8 @@ void BLECharacteristicMap::setByHandle(uint16_t handle, * @param [in] characteristic The characteristic to cache. * @return N/A. */ -void BLECharacteristicMap::setByUUID( - BLECharacteristic *pCharacteristic, - BLEUUID uuid) { - m_uuidMap.insert(std::pair(pCharacteristic, uuid.toString())); +void BLECharacteristicMap::setByUUID(BLECharacteristic* pCharacteristic, BLEUUID uuid) { + m_uuidMap.insert(std::pair(pCharacteristic, uuid.toString())); } // setByUUID @@ -128,7 +118,7 @@ void BLECharacteristicMap::setByUUID( std::string BLECharacteristicMap::toString() { std::stringstream stringStream; stringStream << std::hex << std::setfill('0'); - int count=0; + int count = 0; for (auto &myPair: m_uuidMap) { if (count > 0) { stringStream << "\n"; diff --git a/cpp_utils/BLEClient.cpp b/cpp_utils/BLEClient.cpp index 141cf0f5..d6e75988 100644 --- a/cpp_utils/BLEClient.cpp +++ b/cpp_utils/BLEClient.cpp @@ -6,7 +6,6 @@ */ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) -#include #include #include #include @@ -18,10 +17,16 @@ #include #include #include -#ifdef ARDUINO_ARCH_ESP32 +#include "BLEDevice.h" +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEClient"; #endif + /* * Design * ------ @@ -42,14 +47,28 @@ * * */ -static const char* LOG_TAG = "BLEClient"; BLEClient::BLEClient() { m_pClientCallbacks = nullptr; - m_conn_id = 0; - m_gattc_if = 0; + m_conn_id = ESP_GATT_IF_NONE; + m_gattc_if = ESP_GATT_IF_NONE; m_haveServices = false; m_isConnected = false; // Initially, we are flagged as not connected. + + + m_appId = BLEDevice::m_appId++; + m_appId = m_appId%100; + BLEDevice::addPeerDevice(this, true, m_appId); + m_semaphoreRegEvt.take("connect"); + + esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreRegEvt.wait("connect"); + } // BLEClient @@ -59,10 +78,12 @@ BLEClient::BLEClient() { BLEClient::~BLEClient() { // We may have allocated service references associated with this client. Before we are finished // with the client, we must release resources. - for (auto &myPair : m_servicesMap) { - delete myPair.second; - } - m_servicesMap.clear(); + clearServices(); + esp_ble_gattc_app_unregister(m_gattc_if); + BLEDevice::removePeerDevice(m_appId, true); + if(m_deleteCallbacks) + delete m_pClientCallbacks; + } // ~BLEClient @@ -77,42 +98,38 @@ void BLEClient::clearServices() { delete myPair.second; } m_servicesMap.clear(); + m_servicesMapByInstID.clear(); m_haveServices = false; ESP_LOGD(LOG_TAG, "<< clearServices"); } // clearServices +/** + * Add overloaded function to ease connect to peer device with not public address + */ +bool BLEClient::connect(BLEAdvertisedDevice* device) { + BLEAddress address = device->getAddress(); + esp_ble_addr_type_t type = device->getAddressType(); + return connect(address, type); +} /** * @brief Connect to the partner (BLE Server). * @param [in] address The address of the partner. * @return True on success. */ -bool BLEClient::connect(BLEAddress address) { +bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) { ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str()); -// We need the connection handle that we get from registering the application. We register the app -// and then block on its completion. When the event has arrived, we will have the handle. - m_semaphoreRegEvt.take("connect"); - - clearServices(); // Delete any services that may exist. - - esp_err_t errRc = ::esp_ble_gattc_app_register(0); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return false; - } - - m_semaphoreRegEvt.wait("connect"); - + clearServices(); m_peerAddress = address; // Perform the open connection request against the target BLE Server. m_semaphoreOpenEvt.take("connect"); - errRc = ::esp_ble_gattc_open( - getGattcIf(), + esp_err_t errRc = ::esp_ble_gattc_open( + m_gattc_if, *getPeerAddress().getNative(), // address - BLE_ADDR_TYPE_PUBLIC, // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature. - 1 // direct connection + type, // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature. + 1 // direct connection <-- maybe needs to be changed in case of direct indirect connection??? ); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -131,13 +148,12 @@ bool BLEClient::connect(BLEAddress address) { */ void BLEClient::disconnect() { ESP_LOGD(LOG_TAG, ">> disconnect()"); + // ESP_LOGW(__func__, "gattIf: %d, connId: %d", getGattcIf(), getConnId()); esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId()); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; } - esp_ble_gattc_app_unregister(getGattcIf()); - m_peerAddress = BLEAddress("00:00:00:00:00:00"); ESP_LOGD(LOG_TAG, "<< disconnect()"); } // disconnect @@ -150,9 +166,22 @@ void BLEClient::gattClientEventHandler( esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) { + ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s", + gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); + // Execute handler code based on the type of event received. switch(event) { + case ESP_GATTC_SRVC_CHG_EVT: + if(m_gattc_if != gattc_if) + break; + + ESP_LOGI(LOG_TAG, "SERVICE CHANGED"); + break; + + case ESP_GATTC_CLOSE_EVT: + break; + // // ESP_GATTC_DISCONNECT_EVT // @@ -161,15 +190,20 @@ void BLEClient::gattClientEventHandler( // - uint16_t conn_id // - esp_bd_addr_t remote_bda case ESP_GATTC_DISCONNECT_EVT: { - // If we receive a disconnect event, set the class flag that indicates that we are - // no longer connected. - if (m_pClientCallbacks != nullptr) { - m_pClientCallbacks->onDisconnect(this); - } - m_isConnected = false; - m_semaphoreRssiCmplEvt.give(); - m_semaphoreSearchCmplEvt.give(1); + ESP_LOGE(__func__, "disconnect event, reason: %d, connId: %d, my connId: %d, my IF: %d, gattc_if: %d", (int)evtParam->disconnect.reason, evtParam->disconnect.conn_id, getConnId(), getGattcIf(), gattc_if); + if(m_gattc_if != gattc_if) + break; + m_semaphoreOpenEvt.give(evtParam->disconnect.reason); + if(!m_isConnected) break; + // If we receive a disconnect event, set the class flag that indicates that we are + // no longer connected. + esp_ble_gattc_close(m_gattc_if, m_conn_id); + m_isConnected = false; + if (m_pClientCallbacks != nullptr) { + m_pClientCallbacks->onDisconnect(this); + } + break; } // ESP_GATTC_DISCONNECT_EVT // @@ -179,15 +213,17 @@ void BLEClient::gattClientEventHandler( // - esp_gatt_status_t status // - uint16_t conn_id // - esp_bd_addr_t remote_bda - // - uint16_t mtu // case ESP_GATTC_OPEN_EVT: { + if(m_gattc_if != gattc_if) + break; m_conn_id = evtParam->open.conn_id; if (m_pClientCallbacks != nullptr) { m_pClientCallbacks->onConnect(this); } if (evtParam->open.status == ESP_GATT_OK) { m_isConnected = true; // Flag us as connected. + m_mtu = evtParam->open.mtu; } m_semaphoreOpenEvt.give(evtParam->open.status); break; @@ -202,11 +238,38 @@ void BLEClient::gattClientEventHandler( // uint16_t app_id // case ESP_GATTC_REG_EVT: { - m_gattc_if = gattc_if; - m_semaphoreRegEvt.give(); + if(m_appId == evtParam->reg.app_id){ + ESP_LOGI(__func__, "register app id: %d, %d, gattc_if: %d", m_appId, evtParam->reg.app_id, gattc_if); + m_gattc_if = gattc_if; + m_semaphoreRegEvt.give(); + } break; } // ESP_GATTC_REG_EVT + case ESP_GATTC_CFG_MTU_EVT: + if(evtParam->cfg_mtu.status != ESP_GATT_OK) { + ESP_LOGE(LOG_TAG,"Config mtu failed"); + } + else + m_mtu = evtParam->cfg_mtu.mtu; + break; + + case ESP_GATTC_CONNECT_EVT: { + if(m_gattc_if != gattc_if) + break; + m_conn_id = evtParam->connect.conn_id; + BLEDevice::updatePeerDevice(this, true, m_gattc_if); + esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->connect.conn_id); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig + if(BLEDevice::m_securityLevel){ + esp_ble_set_encryption(evtParam->connect.remote_bda, BLEDevice::m_securityLevel); + } +#endif // CONFIG_BLE_SMP_ENABLE + break; + } // ESP_GATTC_CONNECT_EVT // // ESP_GATTC_SEARCH_CMPL_EVT @@ -216,7 +279,22 @@ void BLEClient::gattClientEventHandler( // - uint16_t conn_id // case ESP_GATTC_SEARCH_CMPL_EVT: { - m_semaphoreSearchCmplEvt.give(0); + if(m_gattc_if != gattc_if) + break; + if (evtParam->search_cmpl.status != ESP_GATT_OK){ + ESP_LOGE(LOG_TAG, "search service failed, error status = %x", evtParam->search_cmpl.status); + } +#ifndef ARDUINO_ARCH_ESP32 +// commented out just for now to keep backward compatibility + // if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) { + // ESP_LOGI(LOG_TAG, "Get service information from remote device"); + // } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) { + // ESP_LOGI(LOG_TAG, "Get service information from flash"); + // } else { + // ESP_LOGI(LOG_TAG, "unknown service source"); + // } +#endif + m_semaphoreSearchCmplEvt.give(evtParam->search_cmpl.status); break; } // ESP_GATTC_SEARCH_CMPL_EVT @@ -231,6 +309,9 @@ void BLEClient::gattClientEventHandler( // - esp_gatt_id_t srvc_id // case ESP_GATTC_SEARCH_RES_EVT: { + if(m_gattc_if != gattc_if) + break; + BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id); BLERemoteService* pRemoteService = new BLERemoteService( evtParam->search_res.srvc_id, @@ -238,7 +319,8 @@ void BLEClient::gattClientEventHandler( evtParam->search_res.start_handle, evtParam->search_res.end_handle ); - m_servicesMap.insert(std::pair(uuid.toString(), pRemoteService)); + m_servicesMap.insert(std::pair(uuid.toString(), pRemoteService)); + m_servicesMapByInstID.insert(std::pair(pRemoteService, evtParam->search_res.srvc_id.inst_id)); break; } // ESP_GATTC_SEARCH_RES_EVT @@ -337,7 +419,7 @@ BLERemoteService* BLEClient::getService(BLEUUID uuid) { } } // End of each of the services. ESP_LOGD(LOG_TAG, "<< getService: not found"); - throw new BLEUuidNotFoundException; + return nullptr; } // getService @@ -356,14 +438,15 @@ std::map* BLEClient::getServices() { * and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received. */ ESP_LOGD(LOG_TAG, ">> getServices"); - +// TODO implement retrieving services from cache clearServices(); // Clear any services that may exist. esp_err_t errRc = esp_ble_gattc_search_service( getGattcIf(), getConnId(), - nullptr // Filter UUID + NULL // Filter UUID ); + m_semaphoreSearchCmplEvt.take("getServices"); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -400,7 +483,7 @@ void BLEClient::handleGAPEvent( esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param) { ESP_LOGD(LOG_TAG, "BLEClient ... handling GAP event!"); - switch(event) { + switch (event) { // // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT // @@ -410,7 +493,7 @@ void BLEClient::handleGAPEvent( // - esp_bd_addr_t remote_addr // case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: { - m_semaphoreRssiCmplEvt.give((uint32_t)param->read_rssi_cmpl.rssi); + m_semaphoreRssiCmplEvt.give((uint32_t) param->read_rssi_cmpl.rssi); break; } // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT @@ -434,8 +517,9 @@ bool BLEClient::isConnected() { /** * @brief Set the callbacks that will be invoked. */ -void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) { +void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks, bool deleteCallbacks) { m_pClientCallbacks = pClientCallbacks; + m_deleteCallbacks = deleteCallbacks; } // setClientCallbacks @@ -451,6 +535,9 @@ void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::s ESP_LOGD(LOG_TAG, "<< setValue"); } // setValue +uint16_t BLEClient::getMTU() { + return m_mtu; +} /** * @brief Return a string representation of this client. diff --git a/cpp_utils/BLEClient.h b/cpp_utils/BLEClient.h index a60ed102..4b3c7eea 100644 --- a/cpp_utils/BLEClient.h +++ b/cpp_utils/BLEClient.h @@ -19,9 +19,11 @@ #include "BLERemoteService.h" #include "BLEService.h" #include "BLEAddress.h" +#include "BLEAdvertisedDevice.h" class BLERemoteService; class BLEClientCallbacks; +class BLEAdvertisedDevice; /** * @brief A model of a %BLE client. @@ -31,7 +33,8 @@ class BLEClient { BLEClient(); ~BLEClient(); - bool connect(BLEAddress address); // Connect to the remote BLE Server + bool connect(BLEAdvertisedDevice* device); + bool connect(BLEAddress address, esp_ble_addr_type_t type = BLE_ADDR_TYPE_PUBLIC); // Connect to the remote BLE Server void disconnect(); // Disconnect from the remote BLE Server BLEAddress getPeerAddress(); // Get the address of the remote BLE Server int getRssi(); // Get the RSSI of the remote BLE Server @@ -47,40 +50,39 @@ class BLEClient { bool isConnected(); // Return true if we are connected. - void setClientCallbacks(BLEClientCallbacks *pClientCallbacks); + void setClientCallbacks(BLEClientCallbacks *pClientCallbacks, bool deleteCallbacks = true); void setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a given characteristic at a given service. std::string toString(); // Return a string representation of this client. + uint16_t getConnId(); + esp_gatt_if_t getGattcIf(); + uint16_t getMTU(); - +uint16_t m_appId; private: friend class BLEDevice; friend class BLERemoteService; friend class BLERemoteCharacteristic; friend class BLERemoteDescriptor; - void gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* param); + void gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* param); - uint16_t getConnId(); - esp_gatt_if_t getGattcIf(); BLEAddress m_peerAddress = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); // The BD address of the remote server. uint16_t m_conn_id; -// int m_deviceType; esp_gatt_if_t m_gattc_if; - bool m_haveServices; // Have we previously obtain the set of services from the remote server. - bool m_isConnected; // Are we currently connected. + bool m_haveServices = false; // Have we previously obtain the set of services from the remote server. + bool m_isConnected = false; // Are we currently connected. + bool m_deleteCallbacks = true; - BLEClientCallbacks* m_pClientCallbacks; + BLEClientCallbacks* m_pClientCallbacks = nullptr; FreeRTOS::Semaphore m_semaphoreRegEvt = FreeRTOS::Semaphore("RegEvt"); FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt"); FreeRTOS::Semaphore m_semaphoreSearchCmplEvt = FreeRTOS::Semaphore("SearchCmplEvt"); FreeRTOS::Semaphore m_semaphoreRssiCmplEvt = FreeRTOS::Semaphore("RssiCmplEvt"); std::map m_servicesMap; + std::map m_servicesMapByInstID; void clearServices(); // Clear any existing services. - + uint16_t m_mtu = 23; }; // class BLEDevice diff --git a/cpp_utils/BLEDescriptor.cpp b/cpp_utils/BLEDescriptor.cpp index 58ff78b4..ba5753de 100644 --- a/cpp_utils/BLEDescriptor.cpp +++ b/cpp_utils/BLEDescriptor.cpp @@ -11,16 +11,19 @@ #include #include #include "sdkconfig.h" -#include #include #include "BLEService.h" #include "BLEDescriptor.h" #include "GeneralUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEDescriptor"; #endif -static const char* LOG_TAG = "BLEDescriptor"; + #define NULL_HANDLE (0xffff) @@ -29,21 +32,21 @@ static const char* LOG_TAG = "BLEDescriptor"; /** * @brief BLEDescriptor constructor. */ -BLEDescriptor::BLEDescriptor(const char* uuid) : BLEDescriptor(BLEUUID(uuid)) { +BLEDescriptor::BLEDescriptor(const char* uuid, uint16_t len) : BLEDescriptor(BLEUUID(uuid), len) { } /** * @brief BLEDescriptor constructor. */ -BLEDescriptor::BLEDescriptor(BLEUUID uuid) { +BLEDescriptor::BLEDescriptor(BLEUUID uuid, uint16_t max_len) { m_bleUUID = uuid; - m_value.attr_value = (uint8_t *)malloc(ESP_GATT_MAX_ATTR_LEN); // Allocate storage for the value. m_value.attr_len = 0; // Initial length is 0. - m_value.attr_max_len = ESP_GATT_MAX_ATTR_LEN; // Maximum length of the data. + m_value.attr_max_len = max_len; // Maximum length of the data. m_handle = NULL_HANDLE; // Handle is initially unknown. m_pCharacteristic = nullptr; // No initial characteristic. m_pCallback = nullptr; // No initial callback. + m_value.attr_value = (uint8_t*) malloc(max_len); // Allocate storage for the value. } // BLEDescriptor @@ -70,12 +73,12 @@ void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) { m_pCharacteristic = pCharacteristic; // Save the characteristic associated with this service. esp_attr_control_t control; - control.auto_rsp = ESP_GATT_RSP_BY_APP; + control.auto_rsp = ESP_GATT_AUTO_RSP; m_semaphoreCreateEvt.take("executeCreate"); esp_err_t errRc = ::esp_ble_gatts_add_char_descr( pCharacteristic->getService()->getHandle(), getUUID().getNative(), - (esp_gatt_perm_t)(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + (esp_gatt_perm_t)m_permissions, &m_value, &control); if (errRc != ESP_OK) { @@ -133,8 +136,8 @@ uint8_t* BLEDescriptor::getValue() { void BLEDescriptor::handleGATTServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - switch(event) { + esp_ble_gatts_cb_param_t* param) { + switch (event) { // ESP_GATTS_ADD_CHAR_DESCR_EVT // // add_char_descr: @@ -143,17 +146,6 @@ void BLEDescriptor::handleGATTServerEvent( // - uint16_t service_handle // - esp_bt_uuid_t char_uuid case ESP_GATTS_ADD_CHAR_DESCR_EVT: { - /* - ESP_LOGD(LOG_TAG, "DEBUG: m_pCharacteristic: %x", (uint32_t)m_pCharacteristic); - ESP_LOGD(LOG_TAG, "DEBUG: m_bleUUID: %s, add_char_descr.char_uuid: %s, equals: %d", - m_bleUUID.toString().c_str(), - BLEUUID(param->add_char_descr.char_uuid).toString().c_str(), - m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid))); - ESP_LOGD(LOG_TAG, "DEBUG: service->getHandle: %x, add_char_descr.service_handle: %x", - m_pCharacteristic->getService()->getHandle(), param->add_char_descr.service_handle); - ESP_LOGD(LOG_TAG, "DEBUG: service->lastCharacteristic: %x", - (uint32_t)m_pCharacteristic->getService()->getLastCreatedCharacteristic()); - */ if (m_pCharacteristic != nullptr && m_bleUUID.equals(BLEUUID(param->add_char_descr.descr_uuid)) && m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle && @@ -180,23 +172,6 @@ void BLEDescriptor::handleGATTServerEvent( if (param->write.handle == m_handle) { setValue(param->write.value, param->write.len); // Set the value of the descriptor. - esp_gatt_rsp_t rsp; // Build a response. - rsp.attr_value.len = getLength(); - rsp.attr_value.handle = m_handle; - rsp.attr_value.offset = 0; - rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; - memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, - param->write.conn_id, - param->write.trans_id, - ESP_GATT_OK, - &rsp); - - if (errRc != ESP_OK) { // Check the return code from the send of the response. - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - if (m_pCallback != nullptr) { // We have completed the write, if there is a user supplied callback handler, invoke it now. m_pCallback->onWrite(this); // Invoke the onWrite callback handler. } @@ -223,34 +198,13 @@ void BLEDescriptor::handleGATTServerEvent( m_pCallback->onRead(this); // Invoke the onRead callback method in the callback handler. } - if (param->read.need_rsp) { // Do we need a response - ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); - esp_gatt_rsp_t rsp; - rsp.attr_value.len = getLength(); - rsp.attr_value.handle = param->read.handle; - rsp.attr_value.offset = 0; - rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; - memcpy(rsp.attr_value.value, getValue(), rsp.attr_value.len); - - esp_err_t errRc = ::esp_ble_gatts_send_response( - gatts_if, - param->read.conn_id, - param->read.trans_id, - ESP_GATT_OK, - &rsp); - - if (errRc != ESP_OK) { // Check the return code from the send of the response. - ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - } // End of need a response. } // End of this is our handle break; } // ESP_GATTS_READ_EVT - default: { + default: break; - } - }// switch event + } // switch event } // handleGATTServerEvent @@ -259,7 +213,7 @@ void BLEDescriptor::handleGATTServerEvent( * @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor. */ void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks* pCallback) { - ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t)pCallback); + ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t) pCallback); m_pCallback = pCallback; ESP_LOGD(LOG_TAG, "<< setCallbacks"); } // setCallbacks @@ -298,7 +252,7 @@ void BLEDescriptor::setValue(uint8_t* data, size_t length) { * @param [in] value The value of the descriptor in string form. */ void BLEDescriptor::setValue(std::string value) { - setValue((uint8_t *)value.data(), value.length()); + setValue((uint8_t*) value.data(), value.length()); } // setValue void BLEDescriptor::setAccessPermissions(esp_gatt_perm_t perm) { diff --git a/cpp_utils/BLEDescriptor.h b/cpp_utils/BLEDescriptor.h index d9e0aefb..03cc5791 100644 --- a/cpp_utils/BLEDescriptor.h +++ b/cpp_utils/BLEDescriptor.h @@ -24,8 +24,8 @@ class BLEDescriptorCallbacks; */ class BLEDescriptor { public: - BLEDescriptor(const char* uuid); - BLEDescriptor(BLEUUID uuid); + BLEDescriptor(const char* uuid, uint16_t max_len = 100); + BLEDescriptor(BLEUUID uuid, uint16_t max_len = 100); virtual ~BLEDescriptor(); uint16_t getHandle(); // Get the handle of the descriptor. diff --git a/cpp_utils/BLEDescriptorMap.cpp b/cpp_utils/BLEDescriptorMap.cpp index 4e372e1d..6b845833 100644 --- a/cpp_utils/BLEDescriptorMap.cpp +++ b/cpp_utils/BLEDescriptorMap.cpp @@ -21,7 +21,7 @@ * @return The descriptor. If not present, then nullptr is returned. */ BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) { - return getByUUID(BLEUUID(uuid)); + return getByUUID(BLEUUID(uuid)); } @@ -32,8 +32,8 @@ BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) { */ BLEDescriptor* BLEDescriptorMap::getByUUID(BLEUUID uuid) { for (auto &myPair : m_uuidMap) { - if (myPair.second->getUUID().equals(uuid)) { - return myPair.second; + if (myPair.first->getUUID().equals(uuid)) { + return myPair.first; } } //return m_uuidMap.at(uuid.toString()); @@ -57,8 +57,8 @@ BLEDescriptor* BLEDescriptorMap::getByHandle(uint16_t handle) { * @param [in] characteristic The descriptor to cache. * @return N/A. */ -void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor *pDescriptor){ - m_uuidMap.insert(std::pair(uuid, pDescriptor)); +void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor* pDescriptor){ + m_uuidMap.insert(std::pair(pDescriptor, uuid)); } // setByUUID @@ -69,8 +69,8 @@ void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor *pDescriptor){ * @param [in] characteristic The descriptor to cache. * @return N/A. */ -void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor) { - m_uuidMap.insert(std::pair(uuid.toString(), pDescriptor)); +void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor) { + m_uuidMap.insert(std::pair(pDescriptor, uuid.toString())); } // setByUUID @@ -80,9 +80,8 @@ void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor *pDescriptor) { * @param [in] descriptor The descriptor to cache. * @return N/A. */ -void BLEDescriptorMap::setByHandle(uint16_t handle, - BLEDescriptor *pDescriptor) { - m_handleMap.insert(std::pair(handle, pDescriptor)); +void BLEDescriptorMap::setByHandle(uint16_t handle, BLEDescriptor* pDescriptor) { + m_handleMap.insert(std::pair(handle, pDescriptor)); } // setByHandle @@ -93,13 +92,13 @@ void BLEDescriptorMap::setByHandle(uint16_t handle, std::string BLEDescriptorMap::toString() { std::stringstream stringStream; stringStream << std::hex << std::setfill('0'); - int count=0; - for (auto &myPair: m_uuidMap) { + int count = 0; + for (auto &myPair : m_uuidMap) { if (count > 0) { stringStream << "\n"; } count++; - stringStream << "handle: 0x" << std::setw(2) << myPair.second->getHandle() << ", uuid: " + myPair.second->getUUID().toString(); + stringStream << "handle: 0x" << std::setw(2) << myPair.first->getHandle() << ", uuid: " + myPair.first->getUUID().toString(); } return stringStream.str(); } // toString @@ -114,10 +113,10 @@ std::string BLEDescriptorMap::toString() { void BLEDescriptorMap::handleGATTServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { + esp_ble_gatts_cb_param_t* param) { // Invoke the handler for every descriptor we have. for (auto &myPair : m_uuidMap) { - myPair.second->handleGATTServerEvent(event, gatts_if, param); + myPair.first->handleGATTServerEvent(event, gatts_if, param); } } // handleGATTServerEvent @@ -128,10 +127,8 @@ void BLEDescriptorMap::handleGATTServerEvent( */ BLEDescriptor* BLEDescriptorMap::getFirst() { m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } - BLEDescriptor *pRet = m_iterator->second; + if (m_iterator == m_uuidMap.end()) return nullptr; + BLEDescriptor* pRet = m_iterator->first; m_iterator++; return pRet; } // getFirst @@ -142,10 +139,8 @@ BLEDescriptor* BLEDescriptorMap::getFirst() { * @return The next descriptor in the map. */ BLEDescriptor* BLEDescriptorMap::getNext() { - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } - BLEDescriptor *pRet = m_iterator->second; + if (m_iterator == m_uuidMap.end()) return nullptr; + BLEDescriptor* pRet = m_iterator->first; m_iterator++; return pRet; } // getNext diff --git a/cpp_utils/BLEDevice.cpp b/cpp_utils/BLEDevice.cpp index a7db454b..78bd13d3 100644 --- a/cpp_utils/BLEDevice.cpp +++ b/cpp_utils/BLEDevice.cpp @@ -19,7 +19,6 @@ #include // ESP32 BLE #include // ESP32 BLE #include // ESP32 ESP-IDF -#include // ESP32 ESP-IDF #include // Part of C++ Standard library #include // Part of C++ Standard library #include // Part of C++ Standard library @@ -28,23 +27,34 @@ #include "BLEClient.h" #include "BLEUtils.h" #include "GeneralUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" -#include "esp32-hal-bt.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEDevice"; #endif -static const char* LOG_TAG = "BLEDevice"; +#if defined(ARDUINO_ARCH_ESP32) +#include "esp32-hal-bt.h" +#endif /** * Singletons for the BLEDevice. */ BLEServer* BLEDevice::m_pServer = nullptr; BLEScan* BLEDevice::m_pScan = nullptr; -BLEClient* BLEDevice::m_pClient = nullptr; -bool initialized = false; // Have we been initialized? -esp_ble_sec_act_t BLEDevice::m_securityLevel = (esp_ble_sec_act_t)0; +// BLEClient* BLEDevice::m_pClient = nullptr; +bool initialized = false; +esp_ble_sec_act_t BLEDevice::m_securityLevel = (esp_ble_sec_act_t)0; BLESecurityCallbacks* BLEDevice::m_securityCallbacks = nullptr; -uint16_t BLEDevice::m_localMTU = 23; +uint16_t BLEDevice::m_localMTU = 23; // not sure if this variable is useful +BLEAdvertising* BLEDevice::m_bleAdvertising = nullptr; +uint16_t BLEDevice::m_appId = 0; +std::map BLEDevice::m_connectedClientsMap; +gap_event_handler BLEDevice::m_customGapHandler = nullptr; +gattc_event_handler BLEDevice::m_customGattcHandler = nullptr; +gatts_event_handler BLEDevice::m_customGattsHandler = nullptr; /** * @brief Create a new instance of a client. @@ -56,7 +66,7 @@ uint16_t BLEDevice::m_localMTU = 23; ESP_LOGE(LOG_TAG, "BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined"); abort(); #endif // CONFIG_GATTC_ENABLE - m_pClient = new BLEClient(); + BLEClient* m_pClient = new BLEClient(); ESP_LOGD(LOG_TAG, "<< createClient"); return m_pClient; } // createClient @@ -72,8 +82,8 @@ uint16_t BLEDevice::m_localMTU = 23; ESP_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined"); abort(); #endif // CONFIG_GATTS_ENABLE - m_pServer = new BLEServer(); - m_pServer->createApp(0); + BLEDevice::m_pServer = new BLEServer(); + m_pServer->createApp(m_appId++); ESP_LOGD(LOG_TAG, "<< createServer"); return m_pServer; } // createServer @@ -97,9 +107,8 @@ uint16_t BLEDevice::m_localMTU = 23; BLEUtils::dumpGattServerEvent(event, gatts_if, param); - switch(event) { + switch (event) { case ESP_GATTS_CONNECT_EVT: { - BLEDevice::m_localMTU = 23; #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityLevel){ esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); @@ -108,11 +117,6 @@ uint16_t BLEDevice::m_localMTU = 23; break; } // ESP_GATTS_CONNECT_EVT - case ESP_GATTS_MTU_EVT: { - BLEDevice::m_localMTU = param->mtu.mtu; - ESP_LOGI(LOG_TAG, "ESP_GATTS_MTU_EVT, MTU %d", BLEDevice::m_localMTU); - break; - } default: { break; } @@ -122,6 +126,11 @@ uint16_t BLEDevice::m_localMTU = 23; if (BLEDevice::m_pServer != nullptr) { BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param); } + + if(m_customGattsHandler != nullptr) { + m_customGattsHandler(event, gatts_if, param); + } + } // gattServerEventHandler @@ -145,31 +154,29 @@ uint16_t BLEDevice::m_localMTU = 23; switch(event) { case ESP_GATTC_CONNECT_EVT: { - if(BLEDevice::getMTU() != 23){ - esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, param->connect.conn_id); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - } - } #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityLevel){ esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); } #endif // CONFIG_BLE_SMP_ENABLE break; - } // ESP_GATTC_CONNECT_EVT + } // ESP_GATTS_CONNECT_EVT - default: { + default: break; - } } // switch + for(auto &myPair : BLEDevice::getPeerDevices(true)) { + conn_status_t conn_status = (conn_status_t)myPair.second; + if(((BLEClient*)conn_status.peer_device)->getGattcIf() == gattc_if || ((BLEClient*)conn_status.peer_device)->getGattcIf() == ESP_GATT_IF_NONE || gattc_if == ESP_GATT_IF_NONE){ + ((BLEClient*)conn_status.peer_device)->gattClientEventHandler(event, gattc_if, param); + } + } - - // If we have a client registered, call it. - if (BLEDevice::m_pClient != nullptr) { - BLEDevice::m_pClient->gattClientEventHandler(event, gattc_if, param); + if(m_customGattcHandler != nullptr) { + m_customGattcHandler(event, gattc_if, param); } + } // gattClientEventHandler @@ -193,10 +200,10 @@ uint16_t BLEDevice::m_localMTU = 23; case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT"); break; - case ESP_GAP_BLE_NC_REQ_EVT: + case ESP_GAP_BLE_NC_REQ_EVT: /* NUMERIC CONFIRMATION */ ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT"); #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig - if(BLEDevice::m_securityCallbacks!=nullptr){ + if(BLEDevice::m_securityCallbacks != nullptr){ esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey)); } #endif // CONFIG_BLE_SMP_ENABLE @@ -205,7 +212,7 @@ uint16_t BLEDevice::m_localMTU = 23; ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: "); // esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda)); #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig - if(BLEDevice::m_securityCallbacks!=nullptr){ + if(BLEDevice::m_securityCallbacks != nullptr){ esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest()); } #endif // CONFIG_BLE_SMP_ENABLE @@ -229,19 +236,19 @@ uint16_t BLEDevice::m_localMTU = 23; /* * */ - case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. - ///show the passkey number to the user to input it in the peer deivce. + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: //the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + //display the passkey number to the user to input it in the peer deivce within 30 seconds ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT"); #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig + ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey); if(BLEDevice::m_securityCallbacks!=nullptr){ - ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey); BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey); } #endif // CONFIG_BLE_SMP_ENABLE break; case ESP_GAP_BLE_KEY_EVT: //shows the ble key type info share with peer device to the user. - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_KEY_EVT"); + ESP_LOGD(LOG_TAG, "ESP_GAP_BLE_KEY_EVT"); #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); #endif // CONFIG_BLE_SMP_ENABLE @@ -249,7 +256,7 @@ uint16_t BLEDevice::m_localMTU = 23; case ESP_GAP_BLE_AUTH_CMPL_EVT: ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_AUTH_CMPL_EVT"); #ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig - if(BLEDevice::m_securityCallbacks!=nullptr){ + if(BLEDevice::m_securityCallbacks != nullptr){ BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); } #endif // CONFIG_BLE_SMP_ENABLE @@ -259,22 +266,17 @@ uint16_t BLEDevice::m_localMTU = 23; } } // switch - if (BLEDevice::m_pServer != nullptr) { - BLEDevice::m_pServer->handleGAPEvent(event, param); - } - - if (BLEDevice::m_pClient != nullptr) { - BLEDevice::m_pClient->handleGAPEvent(event, param); - } - if (BLEDevice::m_pScan != nullptr) { BLEDevice::getScan()->handleGAPEvent(event, param); } - /* - * Security events: - */ + if(m_bleAdvertising != nullptr) { + BLEDevice::getAdvertising()->handleGAPEvent(event, param); + } + if(m_customGapHandler != nullptr) { + BLEDevice::m_customGapHandler(event, param); + } } // gapEventHandler @@ -315,7 +317,7 @@ uint16_t BLEDevice::m_localMTU = 23; */ /* STATIC */ std::string BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) { ESP_LOGD(LOG_TAG, ">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - BLEClient *pClient = createClient(); + BLEClient* pClient = createClient(); pClient->connect(bdAddress); std::string ret = pClient->getValue(serviceUUID, characteristicUUID); pClient->disconnect(); @@ -330,7 +332,7 @@ uint16_t BLEDevice::m_localMTU = 23; */ /* STATIC */ void BLEDevice::init(std::string deviceName) { if(!initialized){ - initialized = true; // Set the initialization flag to ensure we are only initialized once. + initialized = true; // Set the initialization flag to ensure we are only initialized once. esp_err_t errRc = ESP_OK; #ifdef ARDUINO_ARCH_ESP32 @@ -345,6 +347,9 @@ uint16_t BLEDevice::m_localMTU = 23; return; } +#ifndef CLASSIC_BT_ENABLED + esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); +#endif esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); errRc = esp_bt_controller_init(&bt_cfg); if (errRc != ESP_OK) { @@ -353,9 +358,7 @@ uint16_t BLEDevice::m_localMTU = 23; } #ifndef CLASSIC_BT_ENABLED - // esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); //FIXME waiting for response from esp-idf issue errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE); - //errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; @@ -370,7 +373,7 @@ uint16_t BLEDevice::m_localMTU = 23; #endif esp_bluedroid_status_t bt_state = esp_bluedroid_get_status(); - if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){ + if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED) { errRc = esp_bluedroid_init(); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -378,7 +381,7 @@ uint16_t BLEDevice::m_localMTU = 23; } } - if (bt_state != ESP_BLUEDROID_STATUS_ENABLED){ + if (bt_state != ESP_BLUEDROID_STATUS_ENABLED) { errRc = esp_bluedroid_enable(); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -423,7 +426,7 @@ uint16_t BLEDevice::m_localMTU = 23; }; #endif // CONFIG_BLE_SMP_ENABLE } - vTaskDelay(200/portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. + vTaskDelay(200 / portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. } // init @@ -458,7 +461,7 @@ uint16_t BLEDevice::m_localMTU = 23; */ /* STATIC */ void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) { ESP_LOGD(LOG_TAG, ">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); - BLEClient *pClient = createClient(); + BLEClient* pClient = createClient(); pClient->connect(bdAddress); pClient->setValue(serviceUUID, characteristicUUID, value); pClient->disconnect(); @@ -526,7 +529,7 @@ void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) { esp_err_t BLEDevice::setMTU(uint16_t mtu) { ESP_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu); esp_err_t err = esp_ble_gatt_set_local_mtu(mtu); - if(err == ESP_OK){ + if (err == ESP_OK) { m_localMTU = mtu; } else { ESP_LOGE(LOG_TAG, "can't set local mtu value: %d", mtu); @@ -545,4 +548,97 @@ uint16_t BLEDevice::getMTU() { bool BLEDevice::getInitialized() { return initialized; } + +BLEAdvertising* BLEDevice::getAdvertising() { + if(m_bleAdvertising == nullptr) { + m_bleAdvertising = new BLEAdvertising(); + ESP_LOGI(LOG_TAG, "create advertising"); + } + ESP_LOGD(LOG_TAG, "get advertising"); + return m_bleAdvertising; +} + +void BLEDevice::startAdvertising() { + ESP_LOGD(LOG_TAG, ">> startAdvertising"); + getAdvertising()->start(); + ESP_LOGD(LOG_TAG, "<< startAdvertising"); +} // startAdvertising + +/* multi connect support */ +/* requires a little more work */ +std::map BLEDevice::getPeerDevices(bool _client) { + return m_connectedClientsMap; +} + +BLEClient* BLEDevice::getClientByGattIf(uint16_t conn_id) { + return (BLEClient*)m_connectedClientsMap.find(conn_id)->second.peer_device; +} + +void BLEDevice::updatePeerDevice(void* peer, bool _client, uint16_t conn_id) { + ESP_LOGD(LOG_TAG, "update conn_id: %d, GATT role: %s", conn_id, _client? "client":"server"); + std::map::iterator it = m_connectedClientsMap.find(ESP_GATT_IF_NONE); + if (it != m_connectedClientsMap.end()) { + std::swap(m_connectedClientsMap[conn_id], it->second); + m_connectedClientsMap.erase(it); + }else{ + it = m_connectedClientsMap.find(conn_id); + if (it != m_connectedClientsMap.end()) { + conn_status_t _st = it->second; + _st.peer_device = peer; + std::swap(m_connectedClientsMap[conn_id], _st); + } + } +} + +void BLEDevice::addPeerDevice(void* peer, bool _client, uint16_t conn_id) { + ESP_LOGI(LOG_TAG, "add conn_id: %d, GATT role: %s", conn_id, _client? "client":"server"); + conn_status_t status = { + .peer_device = peer, + .connected = true, + .mtu = 23 + }; + + m_connectedClientsMap.insert(std::pair(conn_id, status)); +} + +void BLEDevice::removePeerDevice(uint16_t conn_id, bool _client) { + ESP_LOGI(LOG_TAG, "remove: %d, GATT role %s", conn_id, _client?"client":"server"); + if(m_connectedClientsMap.find(conn_id) != m_connectedClientsMap.end()) + m_connectedClientsMap.erase(conn_id); +} + +/* multi connect support */ + +/** + * @brief de-Initialize the %BLE environment. + * @param release_memory release the internal BT stack memory + */ +/* STATIC */ void BLEDevice::deinit(bool release_memory) { + if (!initialized) return; + + esp_bluedroid_disable(); + esp_bluedroid_deinit(); + esp_bt_controller_disable(); + esp_bt_controller_deinit(); +#ifndef ARDUINO_ARCH_ESP32 + if (release_memory) { + esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); // <-- require tests because we released classic BT memory and this can cause crash (most likely not, esp-idf takes care of it) + } else { + initialized = false; + } +#endif +} + +void BLEDevice::setCustomGapHandler(gap_event_handler handler) { + m_customGapHandler = handler; +} + +void BLEDevice::setCustomGattcHandler(gattc_event_handler handler) { + m_customGattcHandler = handler; +} + +void BLEDevice::setCustomGattsHandler(gatts_event_handler handler) { + m_customGattsHandler = handler; +} + #endif // CONFIG_BT_ENABLED diff --git a/cpp_utils/BLEDevice.h b/cpp_utils/BLEDevice.h index 7a1b833d..b01f09be 100644 --- a/cpp_utils/BLEDevice.h +++ b/cpp_utils/BLEDevice.h @@ -22,8 +22,12 @@ #include "BLEAddress.h" /** - * @brief %BLE functions. + * @brief BLE functions. */ +typedef void (*gap_event_handler)(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); +typedef void (*gattc_event_handler)(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* param); +typedef void (*gatts_event_handler)(esp_gatts_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gatts_cb_param_t* param); + class BLEDevice { public: @@ -43,16 +47,31 @@ class BLEDevice { static esp_err_t setMTU(uint16_t mtu); static uint16_t getMTU(); static bool getInitialized(); // Returns the state of the device, is it initialized or not? + /* move advertising to BLEDevice for saving ram and flash in beacons */ + static BLEAdvertising* getAdvertising(); + static void startAdvertising(); + static uint16_t m_appId; + /* multi connect */ + static std::map getPeerDevices(bool client); + static void addPeerDevice(void* peer, bool is_client, uint16_t conn_id); + static void updatePeerDevice(void* peer, bool _client, uint16_t conn_id); + static void removePeerDevice(uint16_t conn_id, bool client); + static BLEClient* getClientByGattIf(uint16_t conn_id); + static void setCustomGapHandler(gap_event_handler handler); + static void setCustomGattcHandler(gattc_event_handler handler); + static void setCustomGattsHandler(gatts_event_handler handler); + static void deinit(bool release_memory = false); + static uint16_t m_localMTU; + static esp_ble_sec_act_t m_securityLevel; private: - static BLEServer *m_pServer; - static BLEScan *m_pScan; - static BLEClient *m_pClient; - static esp_ble_sec_act_t m_securityLevel; + static BLEServer* m_pServer; + static BLEScan* m_pScan; + // static BLEClient* m_pClient; static BLESecurityCallbacks* m_securityCallbacks; - static uint16_t m_localMTU; - + static BLEAdvertising* m_bleAdvertising; static esp_gatt_if_t getGattcIF(); + static std::map m_connectedClientsMap; static void gattClientEventHandler( esp_gattc_cb_event_t event, @@ -68,6 +87,12 @@ class BLEDevice { esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); +public: +/* custom gap and gatt handlers for flexibility */ + static gap_event_handler m_customGapHandler; + static gattc_event_handler m_customGattcHandler; + static gatts_event_handler m_customGattsHandler; + }; // class BLE #endif // CONFIG_BT_ENABLED diff --git a/cpp_utils/onhold/BLEEddystoneTLM.cpp b/cpp_utils/BLEEddystoneTLM.cpp old mode 100644 new mode 100755 similarity index 55% rename from cpp_utils/onhold/BLEEddystoneTLM.cpp rename to cpp_utils/BLEEddystoneTLM.cpp index 0c61ac1b..a92bcdb2 --- a/cpp_utils/onhold/BLEEddystoneTLM.cpp +++ b/cpp_utils/BLEEddystoneTLM.cpp @@ -4,10 +4,10 @@ * Created on: Mar 12, 2018 * Author: pcbreflux */ -#include "Arduino.h" #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) #include +#include #include #include "BLEEddystoneTLM.h" @@ -16,21 +16,21 @@ static const char LOG_TAG[] = "BLEEddystoneTLM"; #define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24)) BLEEddystoneTLM::BLEEddystoneTLM() { - beconUUID = 0xFEAA; - m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE; - m_eddystoneData.version = 0; - m_eddystoneData.volt = 3300; // 3300mV = 3.3V - m_eddystoneData.temp = (uint16_t)((float)23.00); - m_eddystoneData.advCount = 0; - m_eddystoneData.tmil = 0; + beaconUUID = 0xFEAA; + m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE; + m_eddystoneData.version = 0; + m_eddystoneData.volt = 3300; // 3300mV = 3.3V + m_eddystoneData.temp = (uint16_t) ((float) 23.00); + m_eddystoneData.advCount = 0; + m_eddystoneData.tmil = 0; } // BLEEddystoneTLM std::string BLEEddystoneTLM::getData() { - return std::string((char*)&m_eddystoneData, sizeof(m_eddystoneData)); + return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData)); } // getData BLEUUID BLEEddystoneTLM::getUUID() { - return BLEUUID(beconUUID); + return BLEUUID(beaconUUID); } // getUUID uint8_t BLEEddystoneTLM::getVersion() { @@ -54,46 +54,62 @@ uint32_t BLEEddystoneTLM::getTime() { } // getTime std::string BLEEddystoneTLM::toString() { + std::stringstream ss; std::string out = ""; - String buff; uint32_t rawsec; - - out += "Version "; - buff = String(m_eddystoneData.version, DEC); - out += buff.c_str(); - out += "\n"; - - out += "Battery Voltage "; - buff = String(ENDIAN_CHANGE_U16(m_eddystoneData.volt), DEC); - out += buff.c_str(); - out += " mV\n"; - - out += "Temperature "; - buff = String((float)m_eddystoneData.temp, 1); - out += buff.c_str(); - out += " °C\n"; - - out += "Adv. Count "; - buff = String(ENDIAN_CHANGE_U32(m_eddystoneData.advCount), DEC); - out += buff.c_str(); - out += "\n"; - - out += "Time "; + ss << "Version "; + ss << std::dec << m_eddystoneData.version; + ss << "\n"; + + ss << "Battery Voltage "; + ss << std::dec << ENDIAN_CHANGE_U16(m_eddystoneData.volt); + ss << " mV\n"; + + ss << "Temperature "; + ss << (float) m_eddystoneData.temp; + ss << " °C\n"; + + ss << "Adv. Count "; + ss << std::dec << ENDIAN_CHANGE_U32(m_eddystoneData.advCount); + + ss << "\n"; + + ss << "Time "; + rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil); - buff = "0000"+String(rawsec/864000, DEC); - out += buff.substring(buff.length()-4,buff.length()).c_str(); - out += "."; - buff = "00"+String((rawsec/36000)%24, DEC); - out += buff.substring(buff.length()-2,buff.length()).c_str(); - out += ":"; - buff = "00"+String((rawsec/600)%60, DEC); - out += buff.substring(buff.length()-2,buff.length()).c_str(); - out += ":"; - buff = "00"+String((rawsec/10)%60, DEC); - out += buff.substring(buff.length()-2,buff.length()).c_str(); - out += "\n"; - - return out; + std::stringstream buffstream; + buffstream << "0000"; + buffstream << std::dec << rawsec / 864000; + std::string buff = buffstream.str(); + + ss << buff.substr(buff.length() - 4, buff.length()); + ss << "."; + + buffstream.str(""); + buffstream.clear(); + buffstream << "00"; + buffstream << std::dec << (rawsec / 36000) % 24; + buff = buffstream.str(); + ss << buff.substr(buff.length()-2, buff.length()); + ss << ":"; + + buffstream.str(""); + buffstream.clear(); + buffstream << "00"; + buffstream << std::dec << (rawsec / 600) % 60; + buff = buffstream.str(); + ss << buff.substr(buff.length() - 2, buff.length()); + ss << ":"; + + buffstream.str(""); + buffstream.clear(); + buffstream << "00"; + buffstream << std::dec << (rawsec / 10) % 60; + buff = buffstream.str(); + ss << buff.substr(buff.length() - 2, buff.length()); + ss << "\n"; + + return ss.str(); } // toString /** @@ -108,7 +124,7 @@ void BLEEddystoneTLM::setData(std::string data) { } // setData void BLEEddystoneTLM::setUUID(BLEUUID l_uuid) { - beconUUID = l_uuid.getNative()->uuid.uuid16; + beaconUUID = l_uuid.getNative()->uuid.uuid16; } // setUUID void BLEEddystoneTLM::setVersion(uint8_t version) { diff --git a/cpp_utils/onhold/BLEEddystoneTLM.h b/cpp_utils/BLEEddystoneTLM.h old mode 100644 new mode 100755 similarity index 53% rename from cpp_utils/onhold/BLEEddystoneTLM.h rename to cpp_utils/BLEEddystoneTLM.h index 76bd6a43..a93e224f --- a/cpp_utils/onhold/BLEEddystoneTLM.h +++ b/cpp_utils/BLEEddystoneTLM.h @@ -17,33 +17,34 @@ * * https://github.com/google/eddystone */ class BLEEddystoneTLM { +public: + BLEEddystoneTLM(); + std::string getData(); + BLEUUID getUUID(); + uint8_t getVersion(); + uint16_t getVolt(); + float getTemp(); + uint32_t getCount(); + uint32_t getTime(); + std::string toString(); + void setData(std::string data); + void setUUID(BLEUUID l_uuid); + void setVersion(uint8_t version); + void setVolt(uint16_t volt); + void setTemp(float temp); + void setCount(uint32_t advCount); + void setTime(uint32_t tmil); + private: - uint16_t beconUUID; + uint16_t beaconUUID; struct { uint8_t frameType; - int8_t version; + uint8_t version; uint16_t volt; uint16_t temp; uint32_t advCount; uint32_t tmil; - } __attribute__((packed))m_eddystoneData; -public: - BLEEddystoneTLM(); - std::string getData(); - BLEUUID getUUID(); - uint8_t getVersion(); - uint16_t getVolt(); - float getTemp(); - uint32_t getCount(); - uint32_t getTime(); - std::string toString(); - void setData(std::string data); - void setUUID(BLEUUID l_uuid); - void setVersion(uint8_t version); - void setVolt(uint16_t volt); - void setTemp(float temp); - void setCount(uint32_t advCount); - void setTime(uint32_t tmil); + } __attribute__((packed)) m_eddystoneData; }; // BLEEddystoneTLM diff --git a/cpp_utils/BLEEddystoneURL.cpp b/cpp_utils/BLEEddystoneURL.cpp new file mode 100755 index 00000000..af3b674c --- /dev/null +++ b/cpp_utils/BLEEddystoneURL.cpp @@ -0,0 +1,148 @@ +/* + * BLEEddystoneURL.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include +#include +#include "BLEEddystoneURL.h" + +static const char LOG_TAG[] = "BLEEddystoneURL"; + +BLEEddystoneURL::BLEEddystoneURL() { + beaconUUID = 0xFEAA; + lengthURL = 0; + m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE; + m_eddystoneData.advertisedTxPower = 0; + memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); +} // BLEEddystoneURL + +std::string BLEEddystoneURL::getData() { + return std::string((char*) &m_eddystoneData, sizeof(m_eddystoneData)); +} // getData + +BLEUUID BLEEddystoneURL::getUUID() { + return BLEUUID(beaconUUID); +} // getUUID + +int8_t BLEEddystoneURL::getPower() { + return m_eddystoneData.advertisedTxPower; +} // getPower + +std::string BLEEddystoneURL::getURL() { + return std::string((char*) &m_eddystoneData.url, sizeof(m_eddystoneData.url)); +} // getURL + +std::string BLEEddystoneURL::getDecodedURL() { + std::string decodedURL = ""; + + switch (m_eddystoneData.url[0]) { + case 0x00: + decodedURL += "http://www."; + break; + case 0x01: + decodedURL += "https://www."; + break; + case 0x02: + decodedURL += "http://"; + break; + case 0x03: + decodedURL += "https://"; + break; + default: + decodedURL += m_eddystoneData.url[0]; + } + + for (int i = 1; i < lengthURL; i++) { + if (m_eddystoneData.url[i] > 33 && m_eddystoneData.url[i] < 127) { + decodedURL += m_eddystoneData.url[i]; + } else { + switch (m_eddystoneData.url[i]) { + case 0x00: + decodedURL += ".com/"; + break; + case 0x01: + decodedURL += ".org/"; + break; + case 0x02: + decodedURL += ".edu/"; + break; + case 0x03: + decodedURL += ".net/"; + break; + case 0x04: + decodedURL += ".info/"; + break; + case 0x05: + decodedURL += ".biz/"; + break; + case 0x06: + decodedURL += ".gov/"; + break; + case 0x07: + decodedURL += ".com"; + break; + case 0x08: + decodedURL += ".org"; + break; + case 0x09: + decodedURL += ".edu"; + break; + case 0x0A: + decodedURL += ".net"; + break; + case 0x0B: + decodedURL += ".info"; + break; + case 0x0C: + decodedURL += ".biz"; + break; + case 0x0D: + decodedURL += ".gov"; + break; + default: + break; + } + } + } + return decodedURL; +} // getDecodedURL + + + +/** + * Set the raw data for the beacon record. + */ +void BLEEddystoneURL::setData(std::string data) { + if (data.length() > sizeof(m_eddystoneData)) { + ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d", data.length(), sizeof(m_eddystoneData)); + return; + } + memset(&m_eddystoneData, 0, sizeof(m_eddystoneData)); + memcpy(&m_eddystoneData, data.data(), data.length()); + lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url)); +} // setData + +void BLEEddystoneURL::setUUID(BLEUUID l_uuid) { + beaconUUID = l_uuid.getNative()->uuid.uuid16; +} // setUUID + +void BLEEddystoneURL::setPower(int8_t advertisedTxPower) { + m_eddystoneData.advertisedTxPower = advertisedTxPower; +} // setPower + +void BLEEddystoneURL::setURL(std::string url) { + if (url.length() > sizeof(m_eddystoneData.url)) { + ESP_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d", url.length(), sizeof(m_eddystoneData.url)); + return; + } + memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); + memcpy(m_eddystoneData.url, url.data(), url.length()); + lengthURL = url.length(); +} // setURL + + +#endif diff --git a/cpp_utils/onhold/BLEEddystoneURL.h b/cpp_utils/BLEEddystoneURL.h old mode 100644 new mode 100755 similarity index 60% rename from cpp_utils/onhold/BLEEddystoneURL.h rename to cpp_utils/BLEEddystoneURL.h index 2025cb19..0b538c07 --- a/cpp_utils/onhold/BLEEddystoneURL.h +++ b/cpp_utils/BLEEddystoneURL.h @@ -17,25 +17,26 @@ * * https://github.com/google/eddystone */ class BLEEddystoneURL { -private: - uint16_t beconUUID; - uint8_t lengthURL; - struct { - uint8_t frameType; - int8_t advertisedTxPower; - uint8_t url[16]; - } __attribute__((packed))m_eddystoneData; public: BLEEddystoneURL(); std::string getData(); - BLEUUID getUUID(); - int8_t getPower(); + BLEUUID getUUID(); + int8_t getPower(); std::string getURL(); std::string getDecodedURL(); - void setData(std::string data); - void setUUID(BLEUUID l_uuid); - void setPower(int8_t advertisedTxPower); - void setURL(std::string url); + void setData(std::string data); + void setUUID(BLEUUID l_uuid); + void setPower(int8_t advertisedTxPower); + void setURL(std::string url); + +private: + uint16_t beaconUUID; + uint8_t lengthURL; + struct { + uint8_t frameType; + int8_t advertisedTxPower; + uint8_t url[16]; + } __attribute__((packed)) m_eddystoneData; }; // BLEEddystoneURL diff --git a/cpp_utils/BLEExceptions.h b/cpp_utils/BLEExceptions.h index 369fcaf6..ea9db855 100644 --- a/cpp_utils/BLEExceptions.h +++ b/cpp_utils/BLEExceptions.h @@ -17,13 +17,13 @@ class BLEDisconnectedException : public std::exception { - const char *what() const throw () { + const char* what() const throw () { return "BLE Disconnected"; } }; class BLEUuidNotFoundException : public std::exception { - const char *what() const throw () { + const char* what() const throw () { return "No such UUID"; } }; diff --git a/cpp_utils/BLEHIDDevice.cpp b/cpp_utils/BLEHIDDevice.cpp index 29376f3a..46770b74 100644 --- a/cpp_utils/BLEHIDDevice.cpp +++ b/cpp_utils/BLEHIDDevice.cpp @@ -22,15 +22,15 @@ BLEHIDDevice::BLEHIDDevice(BLEServer* server) { /* * Mandatory characteristic for device info service */ - m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t)0x2a50, BLECharacteristic::PROPERTY_READ); + m_pnpCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a50, BLECharacteristic::PROPERTY_READ); /* * Mandatory characteristics for HID service */ - m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4a, BLECharacteristic::PROPERTY_READ); - m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4b, BLECharacteristic::PROPERTY_READ); - m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4c, BLECharacteristic::PROPERTY_WRITE_NR); - m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4e, BLECharacteristic::PROPERTY_WRITE_NR | BLECharacteristic::PROPERTY_READ); + m_hidInfoCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4a, BLECharacteristic::PROPERTY_READ); + m_reportMapCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4b, BLECharacteristic::PROPERTY_READ); + m_hidControlCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4c, BLECharacteristic::PROPERTY_WRITE_NR); + m_protocolModeCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4e, BLECharacteristic::PROPERTY_WRITE_NR | BLECharacteristic::PROPERTY_READ); /* * Mandatory battery level characteristic with notification and presence descriptor @@ -40,7 +40,7 @@ BLEHIDDevice::BLEHIDDevice(BLEServer* server) { batteryLevelDescriptor->setNamespace(1); batteryLevelDescriptor->setUnit(0x27ad); - m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t)0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); + m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); m_batteryLevelCharacteristic->addDescriptor(batteryLevelDescriptor); m_batteryLevelCharacteristic->addDescriptor(new BLE2902()); @@ -48,8 +48,8 @@ BLEHIDDevice::BLEHIDDevice(BLEServer* server) { * This value is setup here because its default value in most usage cases, its very rare to use boot mode * and we want to simplify library using as much as possible */ - const uint8_t pMode[] = {0x01}; - protocolMode()->setValue((uint8_t*)pMode, 1); + const uint8_t pMode[] = { 0x01 }; + protocolMode()->setValue((uint8_t*) pMode, 1); } BLEHIDDevice::~BLEHIDDevice() { @@ -74,8 +74,8 @@ void BLEHIDDevice::startServices() { /* * @brief Create manufacturer characteristic (this characteristic is optional) */ -BLECharacteristic* BLEHIDDevice::manufacturer() { - m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t)0x2a29, BLECharacteristic::PROPERTY_READ); +BLECharacteristic* BLEHIDDevice::manufacturer() { + m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ); return m_manufacturerCharacteristic; } @@ -91,7 +91,7 @@ void BLEHIDDevice::manufacturer(std::string name) { * @brief */ void BLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version) { - uint8_t pnp[] = {sig, (uint8_t)(vid>>8), (uint8_t)vid, (uint8_t)(pid>>8), (uint8_t)pid, (uint8_t)(version>>8), (uint8_t)version}; + uint8_t pnp[] = { sig, (uint8_t) (vid >> 8), (uint8_t) vid, (uint8_t) (pid >> 8), (uint8_t) pid, (uint8_t) (version >> 8), (uint8_t) version }; m_pnpCharacteristic->setValue(pnp, sizeof(pnp)); } @@ -99,8 +99,8 @@ void BLEHIDDevice::pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version * @brief */ void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) { - uint8_t info[] = {0x11,0x1, country, flags}; - m_hidInfoCharacteristic->setValue(info, sizeof(info));; + uint8_t info[] = { 0x11, 0x1, country, flags }; + m_hidInfoCharacteristic->setValue(info, sizeof(info)); } /* @@ -109,12 +109,16 @@ void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) { * @return pointer to new input report characteristic */ BLECharacteristic* BLEHIDDevice::inputReport(uint8_t reportID) { - BLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); - BLEDescriptor* inputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t)0x2908)); - - uint8_t desc1_val[] = {reportID, 0x01}; - inputReportDescriptor->setValue((uint8_t*)desc1_val, 2); - inputReportCharacteristic->addDescriptor(new BLE2902()); + BLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); + BLEDescriptor* inputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908)); + BLE2902* p2902 = new BLE2902(); + inputReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + inputReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + p2902->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + + uint8_t desc1_val[] = { reportID, 0x01 }; + inputReportDescriptor->setValue((uint8_t*) desc1_val, 2); + inputReportCharacteristic->addDescriptor(p2902); inputReportCharacteristic->addDescriptor(inputReportDescriptor); return inputReportCharacteristic; @@ -126,11 +130,13 @@ BLECharacteristic* BLEHIDDevice::inputReport(uint8_t reportID) { * @return Pointer to new output report characteristic */ BLECharacteristic* BLEHIDDevice::outputReport(uint8_t reportID) { - BLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); - BLEDescriptor* outputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t)0x2908)); + BLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); + BLEDescriptor* outputReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908)); + outputReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + outputReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); - uint8_t desc1_val[] = {reportID, 0x02}; - outputReportDescriptor->setValue((uint8_t*)desc1_val, 2); + uint8_t desc1_val[] = { reportID, 0x02 }; + outputReportDescriptor->setValue((uint8_t*) desc1_val, 2); outputReportCharacteristic->addDescriptor(outputReportDescriptor); return outputReportCharacteristic; @@ -142,11 +148,14 @@ BLECharacteristic* BLEHIDDevice::outputReport(uint8_t reportID) { * @return Pointer to new feature report characteristic */ BLECharacteristic* BLEHIDDevice::featureReport(uint8_t reportID) { - BLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); - BLEDescriptor* featureReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t)0x2908)); + BLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); + BLEDescriptor* featureReportDescriptor = new BLEDescriptor(BLEUUID((uint16_t) 0x2908)); + + featureReportCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + featureReportDescriptor->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); - uint8_t desc1_val[] = {reportID, 0x03}; - featureReportDescriptor->setValue((uint8_t*)desc1_val, 2); + uint8_t desc1_val[] = { reportID, 0x03 }; + featureReportDescriptor->setValue((uint8_t*) desc1_val, 2); featureReportCharacteristic->addDescriptor(featureReportDescriptor); return featureReportCharacteristic; @@ -156,7 +165,7 @@ BLECharacteristic* BLEHIDDevice::featureReport(uint8_t reportID) { * @brief */ BLECharacteristic* BLEHIDDevice::bootInput() { - BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t)0x2a22, BLECharacteristic::PROPERTY_NOTIFY); + BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a22, BLECharacteristic::PROPERTY_NOTIFY); bootInputCharacteristic->addDescriptor(new BLE2902()); return bootInputCharacteristic; @@ -166,25 +175,26 @@ BLECharacteristic* BLEHIDDevice::bootInput() { * @brief */ BLECharacteristic* BLEHIDDevice::bootOutput() { - return m_hidService->createCharacteristic((uint16_t)0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); + return m_hidService->createCharacteristic((uint16_t) 0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); } /* * @brief */ -BLECharacteristic* BLEHIDDevice::hidControl() { +BLECharacteristic* BLEHIDDevice::hidControl() { return m_hidControlCharacteristic; } /* * @brief */ -BLECharacteristic* BLEHIDDevice::protocolMode() { +BLECharacteristic* BLEHIDDevice::protocolMode() { return m_protocolModeCharacteristic; } void BLEHIDDevice::setBatteryLevel(uint8_t level) { m_batteryLevelCharacteristic->setValue(&level, 1); + m_batteryLevelCharacteristic->notify(); } /* * @brief Returns battery level characteristic @@ -196,11 +206,11 @@ BLECharacteristic* BLEHIDDevice::batteryLevel() { -BLECharacteristic* BLEHIDDevice::reportMap() { +BLECharacteristic* BLEHIDDevice::reportMap() { return m_reportMapCharacteristic; } -BLECharacteristic* BLEHIDDevice::pnp() { +BLECharacteristic* BLEHIDDevice::pnp() { return m_pnpCharacteristic; } diff --git a/cpp_utils/BLEHIDDevice.h b/cpp_utils/BLEHIDDevice.h index 319fd42a..33e6b46c 100644 --- a/cpp_utils/BLEHIDDevice.h +++ b/cpp_utils/BLEHIDDevice.h @@ -17,15 +17,15 @@ #include "BLE2902.h" #include "HIDTypes.h" -#define GENERIC_HID 960 -#define HID_KEYBOARD 961 -#define HID_MOUSE 962 -#define HID_JOYSTICK 963 -#define HID_GAMEPAD 964 -#define HID_TABLET 965 -#define HID_CARD_READER 966 -#define HID_DIGITAL_PEN 967 -#define HID_BARCODE 968 +#define GENERIC_HID 0x03C0 +#define HID_KEYBOARD 0x03C1 +#define HID_MOUSE 0x03C2 +#define HID_JOYSTICK 0x03C3 +#define HID_GAMEPAD 0x03C4 +#define HID_TABLET 0x03C5 +#define HID_CARD_READER 0x03C6 +#define HID_DIGITAL_PEN 0x03C7 +#define HID_BARCODE 0x03C8 class BLEHIDDevice { public: diff --git a/cpp_utils/BLERemoteCharacteristic.cpp b/cpp_utils/BLERemoteCharacteristic.cpp index d9c64c91..ef16da7b 100644 --- a/cpp_utils/BLERemoteCharacteristic.cpp +++ b/cpp_utils/BLERemoteCharacteristic.cpp @@ -11,7 +11,6 @@ #if defined(CONFIG_BT_ENABLED) #include -#include #include #include @@ -19,12 +18,15 @@ #include "BLEUtils.h" #include "GeneralUtils.h" #include "BLERemoteDescriptor.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLERemoteCharacteristic"; // The logging tag for this class. #endif -static const char* LOG_TAG = "BLERemoteCharacteristic"; // The logging tag for this class. /** * @brief Constructor. @@ -55,6 +57,7 @@ BLERemoteCharacteristic::BLERemoteCharacteristic( */ BLERemoteCharacteristic::~BLERemoteCharacteristic() { removeDescriptors(); // Release resources for any descriptor information we may have allocated. + if(m_rawData != nullptr) free(m_rawData); } // ~BLERemoteCharacteristic @@ -146,12 +149,8 @@ static bool compareGattId(esp_gatt_id_t id1, esp_gatt_id_t id2) { * @param [in] evtParam Payload data for the event. * @returns N/A */ -void BLERemoteCharacteristic::gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam) { +void BLERemoteCharacteristic::gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) { switch(event) { - // // ESP_GATTC_NOTIFY_EVT // // notify @@ -165,25 +164,15 @@ void BLERemoteCharacteristic::gattClientEventHandler( // We have received a notification event which means that the server wishes us to know about a notification // piece of data. What we must now do is find the characteristic with the associated handle and then // invoke its notification callback (if it has one). - // case ESP_GATTC_NOTIFY_EVT: { - if (evtParam->notify.handle != getHandle()) { - break; - } + if (evtParam->notify.handle != getHandle()) break; if (m_notifyCallback != nullptr) { ESP_LOGD(LOG_TAG, "Invoking callback for notification on characteristic %s", toString().c_str()); - m_notifyCallback( - this, - evtParam->notify.value, - evtParam->notify.value_len, - evtParam->notify.is_notify - ); + m_notifyCallback(this, evtParam->notify.value, evtParam->notify.value_len, evtParam->notify.is_notify); } // End we have a callback function ... break; } // ESP_GATTC_NOTIFY_EVT - - // // ESP_GATTC_READ_CHAR_EVT // This event indicates that the server has responded to the read request. // @@ -193,17 +182,17 @@ void BLERemoteCharacteristic::gattClientEventHandler( // - uint16_t handle // - uint8_t* value // - uint16_t value_len - // case ESP_GATTC_READ_CHAR_EVT: { // If this event is not for us, then nothing further to do. - if (evtParam->read.handle != getHandle()) { - break; - } + if (evtParam->read.handle != getHandle()) break; // At this point, we have determined that the event is for us, so now we save the value // and unlock the semaphore to ensure that the requestor of the data can continue. if (evtParam->read.status == ESP_GATT_OK) { - m_value = std::string((char*)evtParam->read.value, evtParam->read.value_len); + m_value = std::string((char*) evtParam->read.value, evtParam->read.value_len); + if(m_rawData != nullptr) free(m_rawData); + m_rawData = (uint8_t*) calloc(evtParam->read.value_len, sizeof(uint8_t)); + memcpy(m_rawData, evtParam->read.value, evtParam->read.value_len); } else { m_value = ""; } @@ -212,56 +201,41 @@ void BLERemoteCharacteristic::gattClientEventHandler( break; } // ESP_GATTC_READ_CHAR_EVT - - // // ESP_GATTC_REG_FOR_NOTIFY_EVT // // reg_for_notify: // - esp_gatt_status_t status // - uint16_t handle - // case ESP_GATTC_REG_FOR_NOTIFY_EVT: { // If the request is not for this BLERemoteCharacteristic then move on to the next. - if (evtParam->reg_for_notify.handle != getHandle()) { - break; - } + if (evtParam->reg_for_notify.handle != getHandle()) break; // We have processed the notify registration and can unlock the semaphore. m_semaphoreRegForNotifyEvt.give(); break; } // ESP_GATTC_REG_FOR_NOTIFY_EVT - - // // ESP_GATTC_UNREG_FOR_NOTIFY_EVT // // unreg_for_notify: // - esp_gatt_status_t status // - uint16_t handle - // case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: { - if (evtParam->unreg_for_notify.handle != getHandle()) { - break; - } + if (evtParam->unreg_for_notify.handle != getHandle()) break; // We have processed the notify un-registration and can unlock the semaphore. m_semaphoreRegForNotifyEvt.give(); break; } // ESP_GATTC_UNREG_FOR_NOTIFY_EVT: - - // // ESP_GATTC_WRITE_CHAR_EVT // // write: // - esp_gatt_status_t status // - uint16_t conn_id // - uint16_t handle - // case ESP_GATTC_WRITE_CHAR_EVT: { // Determine if this event is for us and, if not, pass onwards. - if (evtParam->write.handle != getHandle()) { - break; - } + if (evtParam->write.handle != getHandle()) break; // There is nothing further we need to do here. This is merely an indication // that the write has completed and we can unlock the caller. @@ -270,9 +244,8 @@ void BLERemoteCharacteristic::gattClientEventHandler( } // ESP_GATTC_WRITE_CHAR_EVT - default: { + default: break; - } } // End switch }; // gattClientEventHandler @@ -289,7 +262,7 @@ void BLERemoteCharacteristic::retrieveDescriptors() { // For each descriptor we find, create a BLERemoteDescriptor instance. uint16_t offset = 0; esp_gattc_descr_elem_t result; - while(1) { + while(true) { uint16_t count = 1; esp_gatt_status_t status = ::esp_ble_gattc_get_all_descr( getRemoteService()->getClient()->getGattcIf(), @@ -300,7 +273,7 @@ void BLERemoteCharacteristic::retrieveDescriptors() { offset ); - if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries. + if (status == ESP_GATT_INVALID_OFFSET || status == ESP_GATT_NOT_FOUND) { // We have reached the end of the entries. break; } @@ -309,14 +282,12 @@ void BLERemoteCharacteristic::retrieveDescriptors() { break; } - if (count == 0) { - break; - } - ESP_LOGE(LOG_TAG, ""); + if (count == 0) break; + ESP_LOGD(LOG_TAG, "Found a descriptor: Handle: %d, UUID: %s", result.handle, BLEUUID(result.uuid).toString().c_str()); // We now have a new characteristic ... let us add that to our set of known characteristics - BLERemoteDescriptor *pNewRemoteDescriptor = new BLERemoteDescriptor( + BLERemoteDescriptor* pNewRemoteDescriptor = new BLERemoteDescriptor( result.handle, BLEUUID(result.uuid), this @@ -334,7 +305,7 @@ void BLERemoteCharacteristic::retrieveDescriptors() { /** * @brief Retrieve the map of descriptors keyed by UUID. */ -std::map* BLERemoteCharacteristic::getDescriptors() { +std::map* BLERemoteCharacteristic::getDescriptors() { return &m_descriptorMap; } // getDescriptors @@ -391,7 +362,7 @@ BLEUUID BLERemoteCharacteristic::getUUID() { * @brief Read an unsigned 16 bit value * @return The unsigned 16 bit value. */ -uint16_t BLERemoteCharacteristic::readUInt16(void) { +uint16_t BLERemoteCharacteristic::readUInt16() { std::string value = readValue(); if (value.length() >= 2) { return *(uint16_t*)(value.data()); @@ -404,7 +375,7 @@ uint16_t BLERemoteCharacteristic::readUInt16(void) { * @brief Read an unsigned 32 bit value. * @return the unsigned 32 bit value. */ -uint32_t BLERemoteCharacteristic::readUInt32(void) { +uint32_t BLERemoteCharacteristic::readUInt32() { std::string value = readValue(); if (value.length() >= 4) { return *(uint32_t*)(value.data()); @@ -417,7 +388,7 @@ uint32_t BLERemoteCharacteristic::readUInt32(void) { * @brief Read a byte value * @return The value as a byte */ -uint8_t BLERemoteCharacteristic::readUInt8(void) { +uint8_t BLERemoteCharacteristic::readUInt8() { std::string value = readValue(); if (value.length() >= 1) { return (uint8_t)value[0]; @@ -470,12 +441,7 @@ std::string BLERemoteCharacteristic::readValue() { * unregistering a notification. * @return N/A. */ -void BLERemoteCharacteristic::registerForNotify( - void (*notifyCallback)( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify)) { +void BLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications) { ESP_LOGD(LOG_TAG, ">> registerForNotify(): %s", toString().c_str()); m_notifyCallback = notifyCallback; // Save the notification callback. @@ -492,6 +458,12 @@ void BLERemoteCharacteristic::registerForNotify( if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } + + uint8_t val[] = {0x01, 0x00}; + if(!notifications) val[0] = 0x02; + BLERemoteDescriptor* desc = getDescriptor(BLEUUID((uint16_t)0x2902)); + if(desc != nullptr) + desc->writeValue(val, 2); } // End Register else { // If we weren't passed a callback function, then this is an unregistration. esp_err_t errRc = ::esp_ble_gattc_unregister_for_notify( @@ -503,6 +475,11 @@ void BLERemoteCharacteristic::registerForNotify( if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_unregister_for_notify: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } + + uint8_t val[] = {0x00, 0x00}; + BLERemoteDescriptor* desc = getDescriptor((uint16_t)0x2902); + if(desc != nullptr) + desc->writeValue(val, 2); } // End Unregister m_semaphoreRegForNotifyEvt.wait("registerForNotify"); @@ -545,62 +522,72 @@ std::string BLERemoteCharacteristic::toString() { * @brief Write the new value for the characteristic. * @param [in] newValue The new value to write. * @param [in] response Do we expect a response? - * @return N/A. + * @return false if not connected or cant perform write for some reason. + */ +bool BLERemoteCharacteristic::writeValue(std::string newValue, bool response) { + return writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response); +} // writeValue + + +/** + * @brief Write the new value for the characteristic. + * + * This is a convenience function. Many BLE characteristics are a single byte of data. + * @param [in] newValue The new byte value to write. + * @param [in] response Whether we require a response from the write. + * @return false if not connected or cant perform write for some reason. */ -void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) { - ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", newValue.length()); +bool BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) { + return writeValue(&newValue, 1, response); +} // writeValue + + +/** + * @brief Write the new value for the characteristic from a data buffer. + * @param [in] data A pointer to a data buffer. + * @param [in] length The length of the data in the data buffer. + * @param [in] response Whether we require a response from the write. + * @return false if not connected or cant perform write for some reason. + */ +bool BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) { + // writeValue(std::string((char*)data, length), response); + ESP_LOGD(LOG_TAG, ">> writeValue(), length: %d", length); // Check to see that we are connected. if (!getRemoteService()->getClient()->isConnected()) { ESP_LOGE(LOG_TAG, "Disconnected"); - throw BLEDisconnectedException(); + return false; } m_semaphoreWriteCharEvt.take("writeValue"); - // Invoke the ESP-IDF API to perform the write. esp_err_t errRc = ::esp_ble_gattc_write_char( m_pRemoteService->getClient()->getGattcIf(), m_pRemoteService->getClient()->getConnId(), getHandle(), - newValue.length(), - (uint8_t*)newValue.data(), + length, + data, response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE ); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gattc_write_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + return false; } m_semaphoreWriteCharEvt.wait("writeValue"); ESP_LOGD(LOG_TAG, "<< writeValue"); + return true; } // writeValue - -/** - * @brief Write the new value for the characteristic. - * - * This is a convenience function. Many BLE characteristics are a single byte of data. - * @param [in] newValue The new byte value to write. - * @param [in] response Whether we require a response from the write. - * @return N/A. - */ -void BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) { - writeValue(std::string(reinterpret_cast(&newValue), 1), response); -} // writeValue - - /** - * @brief Write the new value for the characteristic from a data buffer. - * @param [in] data A pointer to a data buffer. - * @param [in] length The length of the data in the data buffer. - * @param [in] response Whether we require a response from the write. + * @brief Read raw data from remote characteristic as hex bytes + * @return return pointer data read */ -void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) { - writeValue(std::string((char *)data, length), response); -} // writeValue +uint8_t* BLERemoteCharacteristic::readRawData() { + return m_rawData; +} #endif /* CONFIG_BT_ENABLED */ diff --git a/cpp_utils/BLERemoteCharacteristic.h b/cpp_utils/BLERemoteCharacteristic.h index 6f23f497..910b11a4 100644 --- a/cpp_utils/BLERemoteCharacteristic.h +++ b/cpp_utils/BLERemoteCharacteristic.h @@ -21,6 +21,7 @@ class BLERemoteService; class BLERemoteDescriptor; +typedef void (*notify_callback)(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify); /** * @brief A model of a remote %BLE characteristic. @@ -37,18 +38,20 @@ class BLERemoteCharacteristic { bool canWrite(); bool canWriteNoResponse(); BLERemoteDescriptor* getDescriptor(BLEUUID uuid); - std::map* getDescriptors(); + std::map* getDescriptors(); uint16_t getHandle(); BLEUUID getUUID(); - std::string readValue(void); - uint8_t readUInt8(void); - uint16_t readUInt16(void); - uint32_t readUInt32(void); - void registerForNotify(void (*notifyCallback)(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify)); - void writeValue(uint8_t* data, size_t length, bool response = false); - void writeValue(std::string newValue, bool response = false); - void writeValue(uint8_t newValue, bool response = false); - std::string toString(void); + std::string readValue(); + uint8_t readUInt8(); + uint16_t readUInt16(); + uint32_t readUInt32(); + void registerForNotify(notify_callback _callback, bool notifications = true); + bool writeValue(uint8_t* data, size_t length, bool response = false); + bool writeValue(std::string newValue, bool response = false); + bool writeValue(uint8_t newValue, bool response = false); + std::string toString(); + uint8_t* readRawData(); + BLERemoteService* getRemoteService(); private: BLERemoteCharacteristic(uint16_t handle, BLEUUID uuid, esp_gatt_char_prop_t charProp, BLERemoteService* pRemoteService); @@ -57,13 +60,8 @@ class BLERemoteCharacteristic { friend class BLERemoteDescriptor; // Private member functions - void gattClientEventHandler( - esp_gattc_cb_event_t event, - esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t* evtParam); - + void gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam); - BLERemoteService* getRemoteService(); void removeDescriptors(); void retrieveDescriptors(); @@ -76,7 +74,8 @@ class BLERemoteCharacteristic { FreeRTOS::Semaphore m_semaphoreRegForNotifyEvt = FreeRTOS::Semaphore("RegForNotifyEvt"); FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt"); std::string m_value; - void (*m_notifyCallback)(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify); + uint8_t *m_rawData = nullptr; + notify_callback m_notifyCallback = nullptr; // We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID. std::map m_descriptorMap; diff --git a/cpp_utils/BLERemoteDescriptor.cpp b/cpp_utils/BLERemoteDescriptor.cpp index 4d14ba80..96a8a577 100644 --- a/cpp_utils/BLERemoteDescriptor.cpp +++ b/cpp_utils/BLERemoteDescriptor.cpp @@ -9,12 +9,15 @@ #include #include "BLERemoteDescriptor.h" #include "GeneralUtils.h" -#include -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLERemoteDescriptor"; #endif -static const char* LOG_TAG = "BLERemoteDescriptor"; + BLERemoteDescriptor::BLERemoteDescriptor( @@ -55,7 +58,7 @@ BLEUUID BLERemoteDescriptor::getUUID() { } // getUUID -std::string BLERemoteDescriptor::readValue(void) { +std::string BLERemoteDescriptor::readValue() { ESP_LOGD(LOG_TAG, ">> readValue: %s", toString().c_str()); // Check to see that we are connected. @@ -87,28 +90,28 @@ std::string BLERemoteDescriptor::readValue(void) { } // readValue -uint8_t BLERemoteDescriptor::readUInt8(void) { +uint8_t BLERemoteDescriptor::readUInt8() { std::string value = readValue(); if (value.length() >= 1) { - return (uint8_t)value[0]; + return (uint8_t) value[0]; } return 0; } // readUInt8 -uint16_t BLERemoteDescriptor::readUInt16(void) { +uint16_t BLERemoteDescriptor::readUInt16() { std::string value = readValue(); if (value.length() >= 2) { - return *(uint16_t*)(value.data()); + return *(uint16_t*) value.data(); } return 0; } // readUInt16 -uint32_t BLERemoteDescriptor::readUInt32(void) { +uint32_t BLERemoteDescriptor::readUInt32() { std::string value = readValue(); if (value.length() >= 4) { - return *(uint32_t*)(value.data()); + return *(uint32_t*) value.data(); } return 0; } // readUInt32 @@ -118,7 +121,7 @@ uint32_t BLERemoteDescriptor::readUInt32(void) { * @brief Return a string representation of this BLE Remote Descriptor. * @retun A string representation of this BLE Remote Descriptor. */ -std::string BLERemoteDescriptor::toString(void) { +std::string BLERemoteDescriptor::toString() { std::stringstream ss; ss << "handle: " << getHandle() << ", uuid: " << getUUID().toString(); return ss.str(); @@ -131,10 +134,7 @@ std::string BLERemoteDescriptor::toString(void) { * @param [in] length The length of the data to send. * @param [in] response True if we expect a response. */ -void BLERemoteDescriptor::writeValue( - uint8_t* data, - size_t length, - bool response) { +void BLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response) { ESP_LOGD(LOG_TAG, ">> writeValue: %s", toString().c_str()); // Check to see that we are connected. if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) { @@ -148,7 +148,7 @@ void BLERemoteDescriptor::writeValue( getHandle(), length, // Data length data, // Data - ESP_GATT_WRITE_TYPE_NO_RSP, + response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE ); if (errRc != ESP_OK) { @@ -163,10 +163,8 @@ void BLERemoteDescriptor::writeValue( * @param [in] newValue The data to send to the remote descriptor. * @param [in] response True if we expect a response. */ -void BLERemoteDescriptor::writeValue( - std::string newValue, - bool response) { - writeValue(newValue.data(), newValue.length()); +void BLERemoteDescriptor::writeValue(std::string newValue, bool response) { + writeValue((uint8_t*) newValue.data(), newValue.length(), response); } // writeValue @@ -175,9 +173,7 @@ void BLERemoteDescriptor::writeValue( * @param [in] The single byte to write. * @param [in] True if we expect a response. */ -void BLERemoteDescriptor::writeValue( - uint8_t newValue, - bool response) { +void BLERemoteDescriptor::writeValue(uint8_t newValue, bool response) { writeValue(&newValue, 1, response); } // writeValue diff --git a/cpp_utils/BLERemoteService.cpp b/cpp_utils/BLERemoteService.cpp index 78ff9914..91089eab 100644 --- a/cpp_utils/BLERemoteService.cpp +++ b/cpp_utils/BLERemoteService.cpp @@ -11,13 +11,16 @@ #include "BLERemoteService.h" #include "BLEUtils.h" #include "GeneralUtils.h" -#include #include -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLERemoteService"; #endif -static const char* LOG_TAG = "BLERemoteService"; + BLERemoteService::BLERemoteService( esp_gatt_id_t srvcId, @@ -60,61 +63,14 @@ static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { void BLERemoteService::gattClientEventHandler( esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, - esp_ble_gattc_cb_param_t *evtParam) { - switch(event) { - // - // ESP_GATTC_GET_CHAR_EVT - // - // get_char: - // - esp_gatt_status_t status - // - uin1t6_t conn_id - // - esp_gatt_srvc_id_t srvc_id - // - esp_gatt_id_t char_id - // - esp_gatt_char_prop_t char_prop - // - /* - case ESP_GATTC_GET_CHAR_EVT: { - // Is this event for this service? If yes, then the local srvc_id and the event srvc_id will be - // the same. - if (compareSrvcId(m_srvcId, evtParam->get_char.srvc_id) == false) { - break; - } - - // If the status is NOT OK then we have a problem and continue. - if (evtParam->get_char.status != ESP_GATT_OK) { - m_semaphoreGetCharEvt.give(); - break; - } - - // This is an indication that we now have the characteristic details for a characteristic owned - // by this service so remember it. - m_characteristicMap.insert(std::pair( - BLEUUID(evtParam->get_char.char_id.uuid).toString(), - new BLERemoteCharacteristic(evtParam->get_char.char_id, evtParam->get_char.char_prop, this) )); - - - // Now that we have received a characteristic, lets ask for the next one. - esp_err_t errRc = ::esp_ble_gattc_get_characteristic( - m_pClient->getGattcIf(), - m_pClient->getConnId(), - &m_srvcId, - &evtParam->get_char.char_id); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - break; - } - - //m_semaphoreGetCharEvt.give(); + esp_ble_gattc_cb_param_t* evtParam) { + switch (event) { + default: break; - } // ESP_GATTC_GET_CHAR_EVT -*/ - default: { - break; - } } // switch // Send the event to each of the characteristics owned by this service. - for (auto &myPair : m_characteristicMap) { + for (auto &myPair : m_characteristicMapByHandle) { myPair.second->gattClientEventHandler(event, gattc_if, evtParam); } } // gattClientEventHandler @@ -130,7 +86,6 @@ BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) { return getCharacteristic(BLEUUID(uuid)); } // getCharacteristic - /** * @brief Get the characteristic object for the UUID. * @param [in] uuid Characteristic uuid. @@ -153,7 +108,8 @@ BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) { return myPair.second; } } - throw new BLEUuidNotFoundException(); + // throw new BLEUuidNotFoundException(); // <-- we dont want exception here, which will cause app crash, we want to search if any characteristic can be found one after another + return nullptr; } // getCharacteristic @@ -163,15 +119,14 @@ BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) { * @return N/A */ void BLERemoteService::retrieveCharacteristics() { - - ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str()); + ESP_LOGD(LOG_TAG, ">> retrieveCharacteristics() for service: %s", getUUID().toString().c_str()); removeCharacteristics(); // Forget any previous characteristics. uint16_t offset = 0; esp_gattc_char_elem_t result; - while(1) { - uint16_t count = 1; + while (true) { + uint16_t count = 1; // this value is used as in parameter that allows to search max 10 chars with the same uuid esp_gatt_status_t status = ::esp_ble_gattc_get_all_char( getClient()->getGattcIf(), getClient()->getConnId(), @@ -182,7 +137,7 @@ void BLERemoteService::retrieveCharacteristics() { offset ); - if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries. + if (status == ESP_GATT_INVALID_OFFSET || status == ESP_GATT_NOT_FOUND) { // We have reached the end of the entries. break; } @@ -206,20 +161,20 @@ void BLERemoteService::retrieveCharacteristics() { ); m_characteristicMap.insert(std::pair(pNewRemoteCharacteristic->getUUID().toString(), pNewRemoteCharacteristic)); - + m_characteristicMapByHandle.insert(std::pair(result.char_handle, pNewRemoteCharacteristic)); offset++; // Increment our count of number of descriptors found. } // Loop forever (until we break inside the loop). m_haveCharacteristics = true; // Remember that we have received the characteristics. - ESP_LOGD(LOG_TAG, "<< getCharacteristics()"); -} // getCharacteristics + ESP_LOGD(LOG_TAG, "<< retrieveCharacteristics()"); +} // retrieveCharacteristics /** * @brief Retrieve a map of all the characteristics of this service. * @return A map of all the characteristics of this service. */ -std::map * BLERemoteService::getCharacteristics() { +std::map* BLERemoteService::getCharacteristics() { ESP_LOGD(LOG_TAG, ">> getCharacteristics() for service: %s", getUUID().toString().c_str()); // If is possible that we have not read the characteristics associated with the service so do that // now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking @@ -231,6 +186,29 @@ std::map * BLERemoteService::getCharacte return &m_characteristicMap; } // getCharacteristics +/** + * @brief Retrieve a map of all the characteristics of this service. + * @return A map of all the characteristics of this service. + */ +std::map* BLERemoteService::getCharacteristicsByHandle() { + ESP_LOGD(LOG_TAG, ">> getCharacteristicsByHandle() for service: %s", getUUID().toString().c_str()); + // If is possible that we have not read the characteristics associated with the service so do that + // now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking + // call and does not return until all the characteristics are available. + if (!m_haveCharacteristics) { + retrieveCharacteristics(); + } + ESP_LOGD(LOG_TAG, "<< getCharacteristicsByHandle() for service: %s", getUUID().toString().c_str()); + return &m_characteristicMapByHandle; +} // getCharacteristicsByHandle + +/** + * @brief This function is designed to get characteristics map when we have multiple characteristics with the same UUID + */ +void BLERemoteService::getCharacteristics(std::map* pCharacteristicMap) { +#pragma GCC diagnostic ignored "-Wunused-but-set-parameter" + *pCharacteristicMap = m_characteristicMapByHandle; +} // Get the characteristics map. /** * @brief Get the client associated with this service. @@ -287,11 +265,11 @@ std::string BLERemoteService::getValue(BLEUUID characteristicUuid) { * @return N/A. */ void BLERemoteService::removeCharacteristics() { - for (auto &myPair : m_characteristicMap) { + m_characteristicMap.clear(); // Clear the map + for (auto &myPair : m_characteristicMapByHandle) { delete myPair.second; - //m_characteristicMap.erase(myPair.first); // Should be no need to delete as it will be deleted by the clear } - m_characteristicMap.clear(); // Clear the map + m_characteristicMapByHandle.clear(); // Clear the map } // removeCharacteristics diff --git a/cpp_utils/BLERemoteService.h b/cpp_utils/BLERemoteService.h index 222c6e45..2ab86738 100644 --- a/cpp_utils/BLERemoteService.h +++ b/cpp_utils/BLERemoteService.h @@ -26,7 +26,6 @@ class BLERemoteCharacteristic; */ class BLERemoteService { public: - virtual ~BLERemoteService(); // Public methods @@ -34,7 +33,8 @@ class BLERemoteService { BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); // Get the specified characteristic reference. BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference. std::map* getCharacteristics(); - void getCharacteristics(std::map* pCharacteristicMap); // Get the characteristics map. + std::map* getCharacteristicsByHandle(); // Get the characteristics map. + void getCharacteristics(std::map* pCharacteristicMap); BLEClient* getClient(void); // Get a reference to the client associated with this service. uint16_t getHandle(); // Get the handle of this service. @@ -67,10 +67,10 @@ class BLERemoteService { // Properties // We maintain a map of characteristics owned by this service keyed by a string representation of the UUID. - std::map m_characteristicMap; + std::map m_characteristicMap; // We maintain a map of characteristics owned by this service keyed by a handle. - std::map m_characteristicMapByHandle; + std::map m_characteristicMapByHandle; bool m_haveCharacteristics; // Have we previously obtained the characteristics. BLEClient* m_pClient; diff --git a/cpp_utils/BLEScan.cpp b/cpp_utils/BLEScan.cpp index 3046b7c8..a96e6df6 100644 --- a/cpp_utils/BLEScan.cpp +++ b/cpp_utils/BLEScan.cpp @@ -8,7 +8,6 @@ #if defined(CONFIG_BT_ENABLED) -#include #include #include @@ -17,11 +16,15 @@ #include "BLEScan.h" #include "BLEUtils.h" #include "GeneralUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEScan"; #endif -static const char* LOG_TAG = "BLEScan"; + /** @@ -50,20 +53,19 @@ void BLEScan::handleGAPEvent( switch(event) { - // ESP_GAP_BLE_SCAN_RESULT_EVT - // --------------------------- - // scan_rst: - // esp_gap_search_evt_t search_evt - // esp_bd_addr_t bda - // esp_bt_dev_type_t dev_type - // esp_ble_addr_type_t ble_addr_type - // esp_ble_evt_type_t ble_evt_type - // int rssi - // uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX] - // int flag - // int num_resps - // uint8_t adv_data_len - // uint8_t scan_rsp_len + // --------------------------- + // scan_rst: + // esp_gap_search_evt_t search_evt + // esp_bd_addr_t bda + // esp_bt_dev_type_t dev_type + // esp_ble_addr_type_t ble_addr_type + // esp_ble_evt_type_t ble_evt_type + // int rssi + // uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX] + // int flag + // int num_resps + // uint8_t adv_data_len + // uint8_t scan_rsp_len case ESP_GAP_BLE_SCAN_RESULT_EVT: { switch(param->scan_rst.search_evt) { @@ -73,11 +75,12 @@ void BLEScan::handleGAPEvent( // Event that indicates that the duration allowed for the search has completed or that we have been // asked to stop. case ESP_GAP_SEARCH_INQ_CMPL_EVT: { + ESP_LOGW(LOG_TAG, "ESP_GAP_SEARCH_INQ_CMPL_EVT"); m_stopped = true; + m_semaphoreScanEnd.give(); if (m_scanCompleteCB != nullptr) { m_scanCompleteCB(m_scanResults); } - m_semaphoreScanEnd.give(); break; } // ESP_GAP_SEARCH_INQ_CMPL_EVT @@ -95,33 +98,38 @@ void BLEScan::handleGAPEvent( BLEAddress advertisedAddress(param->scan_rst.bda); bool found = false; - for (int i=0; iscan_rst.rssi); - advertisedDevice.setAdFlag(param->scan_rst.flag); - advertisedDevice.parseAdvertisement((uint8_t*)param->scan_rst.ble_adv); - advertisedDevice.setScan(this); + // ESP_LOG_BUFFER_HEXDUMP(LOG_TAG, (uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len, ESP_LOG_DEBUG); + // ESP_LOGW(LOG_TAG, "bytes length: %d + %d, addr type: %d", param->scan_rst.adv_data_len, param->scan_rst.scan_rsp_len, param->scan_rst.ble_addr_type); + BLEAdvertisedDevice *advertisedDevice = new BLEAdvertisedDevice(); + advertisedDevice->setAddress(advertisedAddress); + advertisedDevice->setRSSI(param->scan_rst.rssi); + advertisedDevice->setAdFlag(param->scan_rst.flag); + advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len); + advertisedDevice->setScan(this); + advertisedDevice->setAddressType(param->scan_rst.ble_addr_type); - if (m_pAdvertisedDeviceCallbacks) { - m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + if (!found) { // If we have previously seen this device, don't record it again. + m_scanResults.m_vectorAdvertisedDevices.insert(std::pair(advertisedAddress.toString(), advertisedDevice)); } - if (!found) { // If we have previously seen this device, don't record it again. - m_scanResults.m_vectorAdvertisedDevices.push_back(advertisedDevice); + if (m_pAdvertisedDeviceCallbacks) { + m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice); + m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice); } + if(found) + delete advertisedDevice; break; } // ESP_GAP_SEARCH_INQ_RES_EVT @@ -190,15 +198,23 @@ void BLEScan::setWindow(uint16_t windowMSecs) { * @brief Start scanning. * @param [in] duration The duration in seconds for which to scan. * @param [in] scanCompleteCB A function to be called when scanning has completed. + * @param [in] are we continue scan (true) or we want to clear stored devices (false) * @return True if scan started or false if there was an error. */ -bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults)) { +bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue) { ESP_LOGD(LOG_TAG, ">> start(duration=%d)", duration); m_semaphoreScanEnd.take(std::string("start")); m_scanCompleteCB = scanCompleteCB; // Save the callback to be invoked when the scan completes. - m_scanResults.m_vectorAdvertisedDevices.clear(); + // if we are connecting to devices that are advertising even after being connected, multiconnecting peripherals + // then we should not clear map or we will connect the same device few times + if(!is_continue) { + for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){ + delete _dev.second; + } + m_scanResults.m_vectorAdvertisedDevices.clear(); + } esp_err_t errRc = ::esp_ble_gap_set_scan_params(&m_scan_params); @@ -228,8 +244,8 @@ bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults)) { * @param [in] duration The duration in seconds for which to scan. * @return The BLEScanResults. */ -BLEScanResults BLEScan::start(uint32_t duration) { - if(start(duration, nullptr)) { +BLEScanResults BLEScan::start(uint32_t duration, bool is_continue) { + if(start(duration, nullptr, is_continue)) { m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release. } return m_scanResults; @@ -246,17 +262,24 @@ void BLEScan::stop() { esp_err_t errRc = ::esp_ble_gap_stop_scanning(); m_stopped = true; + m_semaphoreScanEnd.give(); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); return; } - m_semaphoreScanEnd.give(); - ESP_LOGD(LOG_TAG, "<< stop()"); } // stop +// delete peer device from cache after disconnecting, it is required in case we are connecting to devices with not public address +void BLEScan::erase(BLEAddress address) { + ESP_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str()); + BLEAdvertisedDevice *advertisedDevice = m_scanResults.m_vectorAdvertisedDevices.find(address.toString())->second; + m_scanResults.m_vectorAdvertisedDevices.erase(address.toString()); + delete advertisedDevice; +} + /** * @brief Dump the scan results to the log. @@ -285,8 +308,25 @@ int BLEScanResults::getCount() { * @return The device at the specified index. */ BLEAdvertisedDevice BLEScanResults::getDevice(uint32_t i) { - return m_vectorAdvertisedDevices.at(i); + uint32_t x = 0; + BLEAdvertisedDevice dev = *m_vectorAdvertisedDevices.begin()->second; + for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) { + dev = *it->second; + if (x==i) break; + x++; + } + return dev; } +BLEScanResults BLEScan::getResults() { + return m_scanResults; +} + +void BLEScan::clearResults() { + for(auto _dev : m_scanResults.m_vectorAdvertisedDevices){ + delete _dev.second; + } + m_scanResults.m_vectorAdvertisedDevices.clear(); +} #endif /* CONFIG_BT_ENABLED */ diff --git a/cpp_utils/BLEScan.h b/cpp_utils/BLEScan.h index 76c7c7cc..2f71a727 100644 --- a/cpp_utils/BLEScan.h +++ b/cpp_utils/BLEScan.h @@ -11,7 +11,8 @@ #if defined(CONFIG_BT_ENABLED) #include -#include +// #include +#include #include "BLEAdvertisedDevice.h" #include "BLEClient.h" #include "FreeRTOS.h" @@ -37,7 +38,7 @@ class BLEScanResults { private: friend BLEScan; - std::vector m_vectorAdvertisedDevices; + std::map m_vectorAdvertisedDevices; }; /** @@ -53,9 +54,12 @@ class BLEScan { bool wantDuplicates = false); void setInterval(uint16_t intervalMSecs); void setWindow(uint16_t windowMSecs); - bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults)); - BLEScanResults start(uint32_t duration); + bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue = false); + BLEScanResults start(uint32_t duration, bool is_continue = false); void stop(); + void erase(BLEAddress address); + BLEScanResults getResults(); + void clearResults(); private: BLEScan(); // One doesn't create a new instance instead one asks the BLEDevice for the singleton. @@ -67,8 +71,8 @@ class BLEScan { esp_ble_scan_params_t m_scan_params; - BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks; - bool m_stopped; + BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr; + bool m_stopped = true; FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd"); BLEScanResults m_scanResults; bool m_wantDuplicates; diff --git a/cpp_utils/BLESecurity.cpp b/cpp_utils/BLESecurity.cpp index 4cf964a7..f3b2cd3c 100644 --- a/cpp_utils/BLESecurity.cpp +++ b/cpp_utils/BLESecurity.cpp @@ -5,7 +5,7 @@ * Author: chegewara */ -#include +#include "BLESecurity.h" #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) @@ -61,44 +61,54 @@ void BLESecurity::setKeySize(uint8_t key_size) { esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t)); } //setKeySize +/** + * Setup for static PIN connection, call it first and then call setAuthenticationMode eventually to change it + */ +void BLESecurity::setStaticPIN(uint32_t pin){ + uint32_t passkey = pin; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + setCapability(ESP_IO_CAP_OUT); + setKeySize(); + setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY); + setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); +} /** * @brief Debug function to display what keys are exchanged by peers */ -char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) -{ +char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) { char* key_str = nullptr; - switch(key_type) { - case ESP_LE_KEY_NONE: - key_str = (char*)"ESP_LE_KEY_NONE"; - break; + switch (key_type) { + case ESP_LE_KEY_NONE: + key_str = (char*) "ESP_LE_KEY_NONE"; + break; case ESP_LE_KEY_PENC: - key_str = (char*)"ESP_LE_KEY_PENC"; + key_str = (char*) "ESP_LE_KEY_PENC"; break; case ESP_LE_KEY_PID: - key_str = (char*)"ESP_LE_KEY_PID"; + key_str = (char*) "ESP_LE_KEY_PID"; break; case ESP_LE_KEY_PCSRK: - key_str = (char*)"ESP_LE_KEY_PCSRK"; + key_str = (char*) "ESP_LE_KEY_PCSRK"; break; case ESP_LE_KEY_PLK: - key_str = (char*)"ESP_LE_KEY_PLK"; + key_str = (char*) "ESP_LE_KEY_PLK"; break; case ESP_LE_KEY_LLK: - key_str = (char*)"ESP_LE_KEY_LLK"; + key_str = (char*) "ESP_LE_KEY_LLK"; + break; + case ESP_LE_KEY_LENC: + key_str = (char*) "ESP_LE_KEY_LENC"; + break; + case ESP_LE_KEY_LID: + key_str = (char*) "ESP_LE_KEY_LID"; + break; + case ESP_LE_KEY_LCSRK: + key_str = (char*) "ESP_LE_KEY_LCSRK"; + break; + default: + key_str = (char*) "INVALID BLE KEY TYPE"; break; - case ESP_LE_KEY_LENC: - key_str = (char*)"ESP_LE_KEY_LENC"; - break; - case ESP_LE_KEY_LID: - key_str = (char*)"ESP_LE_KEY_LID"; - break; - case ESP_LE_KEY_LCSRK: - key_str = (char*)"ESP_LE_KEY_LCSRK"; - break; - default: - key_str = (char*)"INVALID BLE KEY TYPE"; - break; } return key_str; } // esp_key_type_to_str diff --git a/cpp_utils/BLESecurity.h b/cpp_utils/BLESecurity.h index 67c41efb..dc6d6d71 100644 --- a/cpp_utils/BLESecurity.h +++ b/cpp_utils/BLESecurity.h @@ -21,6 +21,7 @@ class BLESecurity { void setInitEncryptionKey(uint8_t init_key); void setRespEncryptionKey(uint8_t resp_key); void setKeySize(uint8_t key_size = 16); + void setStaticPIN(uint32_t pin); static char* esp_key_type_to_str(esp_ble_key_type_t key_type); private: @@ -29,6 +30,7 @@ class BLESecurity { uint8_t m_initKey; uint8_t m_respKey; uint8_t m_keySize; + }; // BLESecurity @@ -51,20 +53,20 @@ class BLESecurityCallbacks { * It requires that our device is capable to display this code to end user * @param */ - virtual void onPassKeyNotify(uint32_t pass_key); + virtual void onPassKeyNotify(uint32_t pass_key) = 0; /** * @brief Here we can make decision if we want to let negotiate authorization with peer device or not * return Return true if we accept this peer device request */ - virtual bool onSecurityRequest(); + virtual bool onSecurityRequest() = 0 ; /** * Provide us information when authentication process is completed */ - virtual void onAuthenticationComplete(esp_ble_auth_cmpl_t); + virtual void onAuthenticationComplete(esp_ble_auth_cmpl_t) = 0; - virtual bool onConfirmPIN(uint32_t pin); + virtual bool onConfirmPIN(uint32_t pin) = 0; }; // BLESecurityCallbacks #endif // CONFIG_BT_ENABLED diff --git a/cpp_utils/BLEServer.cpp b/cpp_utils/BLEServer.cpp old mode 100644 new mode 100755 index d5c9de68..83497331 --- a/cpp_utils/BLEServer.cpp +++ b/cpp_utils/BLEServer.cpp @@ -7,11 +7,10 @@ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) -#include #include #include -#include -//#include +#include +#include "GeneralUtils.h" #include "BLEDevice.h" #include "BLEServer.h" #include "BLEService.h" @@ -19,11 +18,15 @@ #include #include #include -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEServer"; #endif -static const char* LOG_TAG = "BLEServer"; + /** @@ -33,19 +36,17 @@ static const char* LOG_TAG = "BLEServer"; * the BLEDevice class. */ BLEServer::BLEServer() { - m_appId = -1; - m_gatts_if = -1; + m_appId = ESP_GATT_IF_NONE; + m_gatts_if = ESP_GATT_IF_NONE; m_connectedCount = 0; - m_connId = -1; + m_connId = ESP_GATT_IF_NONE; m_pServerCallbacks = nullptr; - - //createApp(0); } // BLEServer void BLEServer::createApp(uint16_t appId) { m_appId = appId; - registerApp(); + registerApp(appId); } // createApp @@ -80,12 +81,10 @@ BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t if (m_serviceMap.getByUUID(uuid) != nullptr) { ESP_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", uuid.toString().c_str()); - //m_semaphoreCreateEvt.give(); - //return nullptr; } BLEService* pService = new BLEService(uuid, numHandles); - pService->m_id = inst_id; + pService->m_instId = inst_id; m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server. pService->executeCreate(this); // Perform the API calls to actually create the service. @@ -96,13 +95,31 @@ BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t } // createService +/** + * @brief Get a %BLE Service by its UUID + * @param [in] uuid The UUID of the new service. + * @return A reference to the service object. + */ +BLEService* BLEServer::getServiceByUUID(const char* uuid) { + return m_serviceMap.getByUUID(uuid); +} + +/** + * @brief Get a %BLE Service by its UUID + * @param [in] uuid The UUID of the new service. + * @return A reference to the service object. + */ +BLEService* BLEServer::getServiceByUUID(BLEUUID uuid) { + return m_serviceMap.getByUUID(uuid); +} + /** * @brief Retrieve the advertising object that can be used to advertise the existence of the server. * * @return An advertising object. */ BLEAdvertising* BLEServer::getAdvertising() { - return &m_bleAdvertising; + return BLEDevice::getAdvertising(); } uint16_t BLEServer::getConnId() { @@ -123,42 +140,6 @@ uint16_t BLEServer::getGattsIf() { return m_gatts_if; } -/** - * @brief Handle a received GAP event. - * - * @param [in] event - * @param [in] param - */ -void BLEServer::handleGAPEvent( - esp_gap_ble_cb_event_t event, - esp_ble_gap_cb_param_t* param) { - ESP_LOGD(LOG_TAG, "BLEServer ... handling GAP event!"); - switch(event) { - case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { - /* - esp_ble_adv_params_t adv_params; - adv_params.adv_int_min = 0x20; - adv_params.adv_int_max = 0x40; - adv_params.adv_type = ADV_TYPE_IND; - adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; - adv_params.channel_map = ADV_CHNL_ALL; - adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; - ESP_LOGD(tag, "Starting advertising"); - esp_err_t errRc = ::esp_ble_gap_start_advertising(&adv_params); - if (errRc != ESP_OK) { - ESP_LOGE(tag, "esp_ble_gap_start_advertising: rc=%d %s", errRc, espToString(errRc)); - return; - } - */ - break; - } - - default: - break; - } -} // handleGAPEvent - - /** * @brief Handle a GATT Server Event. @@ -168,17 +149,10 @@ void BLEServer::handleGAPEvent( * @param [in] param * */ -void BLEServer::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param) { - +void BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) { ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); - // Invoke the handler for every Service we have. - m_serviceMap.handleGATTServerEvent(event, gatts_if, param); - switch(event) { // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. // add_char: @@ -191,19 +165,23 @@ void BLEServer::handleGATTServerEvent( break; } // ESP_GATTS_ADD_CHAR_EVT + case ESP_GATTS_MTU_EVT: + updatePeerMTU(param->mtu.conn_id, param->mtu.mtu); + break; // ESP_GATTS_CONNECT_EVT // connect: // - uint16_t conn_id // - esp_bd_addr_t remote_bda - // - bool is_connected // case ESP_GATTS_CONNECT_EVT: { - m_connId = param->connect.conn_id; // Save the connection id. + m_connId = param->connect.conn_id; + addPeerDevice((void*)this, false, m_connId); if (m_pServerCallbacks != nullptr) { m_pServerCallbacks->onConnect(this); + m_pServerCallbacks->onConnect(this, param); } - m_connectedCount++; // Increment the number of connected devices count. + m_connectedCount++; // Increment the number of connected devices count. break; } // ESP_GATTS_CONNECT_EVT @@ -217,7 +195,7 @@ void BLEServer::handleGATTServerEvent( // * esp_gatt_srvc_id_t service_id // case ESP_GATTS_CREATE_EVT: { - BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid); + BLEService* pService = m_serviceMap.getByUUID(param->create.service_id.id.uuid, param->create.service_id.id.inst_id); // <--- very big bug for multi services with the same uuid m_serviceMap.setByHandle(param->create.service_handle, pService); m_semaphoreCreateEvt.give(); break; @@ -227,9 +205,9 @@ void BLEServer::handleGATTServerEvent( // ESP_GATTS_DISCONNECT_EVT // // disconnect - // - uint16_t conn_id - // - esp_bd_addr_t remote_bda - // - bool is_connected + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - esp_gatt_conn_reason_t reason // // If we receive a disconnect event then invoke the callback for disconnects (if one is present). // we also want to start advertising again. @@ -239,6 +217,7 @@ void BLEServer::handleGATTServerEvent( m_pServerCallbacks->onDisconnect(this); } startAdvertising(); //- do this with some delay from the loop() + removePeerDevice(param->disconnect.conn_id, false); break; } // ESP_GATTS_DISCONNECT_EVT @@ -288,10 +267,17 @@ void BLEServer::handleGATTServerEvent( break; } - default: { + case ESP_GATTS_OPEN_EVT: + m_semaphoreOpenEvt.give(param->open.status); + break; + + default: break; - } } + + // Invoke the handler for every Service we have. + m_serviceMap.handleGATTServerEvent(event, gatts_if, param); + ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent"); } // handleGATTServerEvent @@ -301,7 +287,7 @@ void BLEServer::handleGATTServerEvent( * * @return N/A */ -void BLEServer::registerApp() { +void BLEServer::registerApp(uint16_t m_appId) { ESP_LOGD(LOG_TAG, ">> registerApp - %d", m_appId); m_semaphoreRegisterAppEvt.take("registerApp"); // Take the mutex, will be released by ESP_GATTS_REG_EVT event. ::esp_ble_gatts_app_register(m_appId); @@ -326,7 +312,7 @@ void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) { /* * Remove service */ -void BLEServer::removeService(BLEService *service) { +void BLEServer::removeService(BLEService* service) { service->stop(); service->executeDelete(); m_serviceMap.removeService(service); @@ -340,10 +326,35 @@ void BLEServer::removeService(BLEService *service) { */ void BLEServer::startAdvertising() { ESP_LOGD(LOG_TAG, ">> startAdvertising"); - m_bleAdvertising.start(); + BLEDevice::startAdvertising(); ESP_LOGD(LOG_TAG, "<< startAdvertising"); } // startAdvertising +/** + * Allow to connect GATT server to peer device + * Probably can be used in ANCS for iPhone + */ +bool BLEServer::connect(BLEAddress address) { + esp_bd_addr_t addr; + memcpy(&addr, address.getNative(), 6); + // Perform the open connection request against the target BLE Server. + m_semaphoreOpenEvt.take("connect"); + esp_err_t errRc = ::esp_ble_gatts_open( + getGattsIf(), + addr, // address + 1 // direct connection + ); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return false; + } + + uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete. + ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK); + return rc == ESP_GATT_OK; +} // connect + + void BLEServerCallbacks::onConnect(BLEServer* pServer) { ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default"); @@ -351,6 +362,12 @@ void BLEServerCallbacks::onConnect(BLEServer* pServer) { ESP_LOGD("BLEServerCallbacks", "<< onConnect()"); } // onConnect +void BLEServerCallbacks::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) { + ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default"); + ESP_LOGD("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str()); + ESP_LOGD("BLEServerCallbacks", "<< onConnect()"); +} // onConnect + void BLEServerCallbacks::onDisconnect(BLEServer* pServer) { ESP_LOGD("BLEServerCallbacks", ">> onDisconnect(): Default"); @@ -358,4 +375,56 @@ void BLEServerCallbacks::onDisconnect(BLEServer* pServer) { ESP_LOGD("BLEServerCallbacks", "<< onDisconnect()"); } // onDisconnect +/* multi connect support */ +/* TODO do some more tweaks */ +void BLEServer::updatePeerMTU(uint16_t conn_id, uint16_t mtu) { + // set mtu in conn_status_t + const std::map::iterator it = m_connectedServersMap.find(conn_id); + if (it != m_connectedServersMap.end()) { + it->second.mtu = mtu; + std::swap(m_connectedServersMap[conn_id], it->second); + } +} + +std::map BLEServer::getPeerDevices(bool _client) { + return m_connectedServersMap; +} + + +uint16_t BLEServer::getPeerMTU(uint16_t conn_id) { + return m_connectedServersMap.find(conn_id)->second.mtu; +} + +void BLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) { + conn_status_t status = { + .peer_device = peer, + .connected = true, + .mtu = 23 + }; + + m_connectedServersMap.insert(std::pair(conn_id, status)); +} + +void BLEServer::removePeerDevice(uint16_t conn_id, bool _client) { + m_connectedServersMap.erase(conn_id); +} +/* multi connect support */ + +/** + * Update connection parameters can be called only after connection has been established + */ +void BLEServer::updateConnParams(esp_bd_addr_t remote_bda, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) { + esp_ble_conn_update_params_t conn_params; + memcpy(conn_params.bda, remote_bda, sizeof(esp_bd_addr_t)); + conn_params.latency = latency; + conn_params.max_int = maxInterval; // max_int = 0x20*1.25ms = 40ms + conn_params.min_int = minInterval; // min_int = 0x10*1.25ms = 20ms + conn_params.timeout = timeout; // timeout = 400*10ms = 4000ms + esp_ble_gap_update_conn_params(&conn_params); +} + +void BLEServer::disconnect(uint16_t connId){ + esp_ble_gatts_close(m_gatts_if, connId); +} + #endif // CONFIG_BT_ENABLED diff --git a/cpp_utils/BLEServer.h b/cpp_utils/BLEServer.h old mode 100644 new mode 100755 index 95c55d53..d2f8038d --- a/cpp_utils/BLEServer.h +++ b/cpp_utils/BLEServer.h @@ -13,6 +13,7 @@ #include #include +// #include "BLEDevice.h" #include "BLEUUID.h" #include "BLEAdvertising.h" @@ -20,8 +21,15 @@ #include "BLEService.h" #include "BLESecurity.h" #include "FreeRTOS.h" +#include "BLEAddress.h" class BLEServerCallbacks; +/* TODO possibly refactor this struct */ +typedef struct { + void *peer_device; // peer device BLEClient or BLEServer - maybe its better to have 2 structures or union here + bool connected; // do we need it? + uint16_t mtu; // every peer device negotiate own mtu +} conn_status_t; /** @@ -31,11 +39,8 @@ class BLEServiceMap { public: BLEService* getByHandle(uint16_t handle); BLEService* getByUUID(const char* uuid); - BLEService* getByUUID(BLEUUID uuid); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); + BLEService* getByUUID(BLEUUID uuid, uint8_t inst_id = 0); + void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); void setByHandle(uint16_t handle, BLEService* service); void setByUUID(const char* uuid, BLEService* service); void setByUUID(BLEUUID uuid, BLEService* service); @@ -43,6 +48,7 @@ class BLEServiceMap { BLEService* getFirst(); BLEService* getNext(); void removeService(BLEService *service); + int getRegisteredServiceCount(); private: std::map m_handleMap; @@ -62,7 +68,22 @@ class BLEServer { BLEAdvertising* getAdvertising(); void setCallbacks(BLEServerCallbacks* pCallbacks); void startAdvertising(); - void removeService(BLEService *service); + void removeService(BLEService* service); + BLEService* getServiceByUUID(const char* uuid); + BLEService* getServiceByUUID(BLEUUID uuid); + bool connect(BLEAddress address); + void disconnect(uint16_t connId); + uint16_t m_appId; + void updateConnParams(esp_bd_addr_t remote_bda, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout); + + /* multi connection support */ + std::map getPeerDevices(bool client); + void addPeerDevice(void* peer, bool is_client, uint16_t conn_id); + void removePeerDevice(uint16_t conn_id, bool client); + BLEServer* getServerByConnId(uint16_t conn_id); + void updatePeerMTU(uint16_t connId, uint16_t mtu); + uint16_t getPeerMTU(uint16_t conn_id); + uint16_t getConnId(); private: @@ -71,22 +92,22 @@ class BLEServer { friend class BLECharacteristic; friend class BLEDevice; esp_ble_adv_data_t m_adv_data; - uint16_t m_appId; - BLEAdvertising m_bleAdvertising; - uint16_t m_connId; - uint32_t m_connectedCount; - uint16_t m_gatts_if; - FreeRTOS::Semaphore m_semaphoreRegisterAppEvt = FreeRTOS::Semaphore("RegisterAppEvt"); - FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + // BLEAdvertising m_bleAdvertising; + uint16_t m_connId; + uint32_t m_connectedCount; + uint16_t m_gatts_if; + std::map m_connectedServersMap; + + FreeRTOS::Semaphore m_semaphoreRegisterAppEvt = FreeRTOS::Semaphore("RegisterAppEvt"); + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + FreeRTOS::Semaphore m_semaphoreOpenEvt = FreeRTOS::Semaphore("OpenEvt"); BLEServiceMap m_serviceMap; - BLEServerCallbacks* m_pServerCallbacks; + BLEServerCallbacks* m_pServerCallbacks = nullptr; void createApp(uint16_t appId); - uint16_t getConnId(); uint16_t getGattsIf(); - void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); - void registerApp(); + void registerApp(uint16_t); }; // BLEServer @@ -104,7 +125,7 @@ class BLEServerCallbacks { * @param [in] pServer A reference to the %BLE server that received the client connection. */ virtual void onConnect(BLEServer* pServer); - + virtual void onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param); /** * @brief Handle an existing client disconnection. * @@ -116,6 +137,5 @@ class BLEServerCallbacks { }; // BLEServerCallbacks - #endif /* CONFIG_BT_ENABLED */ #endif /* COMPONENTS_CPP_UTILS_BLESERVER_H_ */ diff --git a/cpp_utils/BLEService.cpp b/cpp_utils/BLEService.cpp index 340ea560..3034cf18 100644 --- a/cpp_utils/BLEService.cpp +++ b/cpp_utils/BLEService.cpp @@ -11,7 +11,6 @@ #if defined(CONFIG_BT_ENABLED) #include #include -#include #include #include @@ -22,20 +21,23 @@ #include "BLEUtils.h" #include "GeneralUtils.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEService"; // Tag for logging. #endif #define NULL_HANDLE (0xffff) -static const char* LOG_TAG = "BLEService"; // Tag for logging. /** * @brief Construct an instance of the BLEService * @param [in] uuid The UUID of the service. * @param [in] numHandles The maximum number of handles associated with the service. */ -BLEService::BLEService(const char* uuid, uint32_t numHandles) : BLEService(BLEUUID(uuid), numHandles) { +BLEService::BLEService(const char* uuid, uint16_t numHandles) : BLEService(BLEUUID(uuid), numHandles) { } @@ -44,7 +46,7 @@ BLEService::BLEService(const char* uuid, uint32_t numHandles) : BLEService(BLEUU * @param [in] uuid The UUID of the service. * @param [in] numHandles The maximum number of handles associated with the service. */ -BLEService::BLEService(BLEUUID uuid, uint32_t numHandles) { +BLEService::BLEService(BLEUUID uuid, uint16_t numHandles) { m_uuid = uuid; m_handle = NULL_HANDLE; m_pServer = nullptr; @@ -61,25 +63,16 @@ BLEService::BLEService(BLEUUID uuid, uint32_t numHandles) { * @return N/A. */ -void BLEService::executeCreate(BLEServer *pServer) { - //ESP_LOGD(LOG_TAG, ">> executeCreate() - Creating service (esp_ble_gatts_create_service) service uuid: %s", getUUID().toString().c_str()); - //getUUID(); // Needed for a weird bug fix - //char x[1000]; - //memcpy(x, &m_uuid, sizeof(m_uuid)); - //char x[10]; - //memcpy(x, &deleteMe, 10); +void BLEService::executeCreate(BLEServer* pServer) { + ESP_LOGD(LOG_TAG, ">> executeCreate() - Creating service (esp_ble_gatts_create_service) service uuid: %s", getUUID().toString().c_str()); m_pServer = pServer; m_semaphoreCreateEvt.take("executeCreate"); // Take the mutex and release at event ESP_GATTS_CREATE_EVT esp_gatt_srvc_id_t srvc_id; srvc_id.is_primary = true; - srvc_id.id.inst_id = m_id; + srvc_id.id.inst_id = m_instId; srvc_id.id.uuid = *m_uuid.getNative(); - esp_err_t errRc = ::esp_ble_gatts_create_service( - getServer()->getGattsIf(), - &srvc_id, - m_numHandles // The maximum number of handles associated with the service. - ); + esp_err_t errRc = ::esp_ble_gatts_create_service(getServer()->getGattsIf(), &srvc_id, m_numHandles); // The maximum number of handles associated with the service. if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gatts_create_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -101,7 +94,7 @@ void BLEService::executeDelete() { ESP_LOGD(LOG_TAG, ">> executeDelete()"); m_semaphoreDeleteEvt.take("executeDelete"); // Take the mutex and release at event ESP_GATTS_DELETE_EVT - esp_err_t errRc = ::esp_ble_gatts_delete_service( getHandle() ); + esp_err_t errRc = ::esp_ble_gatts_delete_service(getHandle()); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gatts_delete_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -151,10 +144,9 @@ void BLEService::start() { return; } - BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst(); - while(pCharacteristic != nullptr) { + while (pCharacteristic != nullptr) { m_lastCreatedCharacteristic = pCharacteristic; pCharacteristic->executeCreate(this); @@ -177,13 +169,11 @@ void BLEService::start() { /** * @brief Stop the service. - * @return Stop the service. */ void BLEService::stop() { // We ask the BLE runtime to start the service and then create each of the characteristics. // We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event // obtained as a result of calling esp_ble_gatts_create_service(). -// ESP_LOGD(LOG_TAG, ">> stop(): Stopping service (esp_ble_gatts_stop_service): %s", toString().c_str()); if (m_handle == NULL_HANDLE) { ESP_LOGE(LOG_TAG, "<< !!! We attempted to stop a service but don't know its handle!"); @@ -232,10 +222,10 @@ uint16_t BLEService::getHandle() { * @param [in] pCharacteristic A pointer to the characteristic to be added. */ void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) { -// We maintain a mapping of characteristics owned by this service. These are managed by the -// BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic -// to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF). -// + // We maintain a mapping of characteristics owned by this service. These are managed by the + // BLECharacteristicMap class instance found in m_characteristicMap. We add the characteristic + // to the map and then ask the service to add the characteristic at the BLE level (ESP-IDF). + ESP_LOGD(LOG_TAG, ">> addCharacteristic()"); ESP_LOGD(LOG_TAG, "Adding characteristic: uuid=%s to service: %s", pCharacteristic->getUUID().toString().c_str(), @@ -273,7 +263,7 @@ BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t p * @return The new BLE characteristic. */ BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t properties) { - BLECharacteristic *pCharacteristic = new BLECharacteristic(uuid, properties); + BLECharacteristic* pCharacteristic = new BLECharacteristic(uuid, properties); addCharacteristic(pCharacteristic); return pCharacteristic; } // createCharacteristic @@ -282,13 +272,8 @@ BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t prope /** * @brief Handle a GATTS server event. */ -void BLEService::handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { - - - switch(event) { +void BLEService::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param) { + switch (event) { // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. // add_char: // - esp_gatt_status_t status @@ -309,7 +294,6 @@ void BLEService::handleGATTServerEvent( } pCharacteristic->setHandle(param->add_char.attr_handle); m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic); - //ESP_LOGD(tag, "Characteristic map: %s", m_characteristicMap.toString().c_str()); break; } // Reached the correct service. break; @@ -355,7 +339,7 @@ void BLEService::handleGATTServerEvent( // * - bool is_primary // case ESP_GATTS_CREATE_EVT: { - if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid)) && m_id == param->create.service_id.id.inst_id) { + if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid)) && m_instId == param->create.service_id.id.inst_id) { setHandle(param->create.service_handle); m_semaphoreCreateEvt.give(); } @@ -377,9 +361,8 @@ void BLEService::handleGATTServerEvent( break; } // ESP_GATTS_DELETE_EVT - default: { + default: break; - } // Default } // Switch // Invoke the GATTS handler in each of the associated characteristics. diff --git a/cpp_utils/BLEService.h b/cpp_utils/BLEService.h index 93b4b2c6..b42d57f2 100644 --- a/cpp_utils/BLEService.h +++ b/cpp_utils/BLEService.h @@ -33,11 +33,7 @@ class BLECharacteristicMap { BLECharacteristic* getFirst(); BLECharacteristic* getNext(); std::string toString(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); - + void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); private: std::map m_uuidMap; @@ -66,11 +62,11 @@ class BLEService { void stop(); std::string toString(); uint16_t getHandle(); - uint8_t m_id = 0; + uint8_t m_instId = 0; private: - BLEService(const char* uuid, uint32_t numHandles); - BLEService(BLEUUID uuid, uint32_t numHandles); + BLEService(const char* uuid, uint16_t numHandles); + BLEService(BLEUUID uuid, uint16_t numHandles); friend class BLEServer; friend class BLEServiceMap; friend class BLEDescriptor; @@ -79,8 +75,8 @@ class BLEService { BLECharacteristicMap m_characteristicMap; uint16_t m_handle; - BLECharacteristic* m_lastCreatedCharacteristic; - BLEServer* m_pServer; + BLECharacteristic* m_lastCreatedCharacteristic = nullptr; + BLEServer* m_pServer = nullptr; BLEUUID m_uuid; FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); @@ -88,13 +84,10 @@ class BLEService { FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt"); FreeRTOS::Semaphore m_semaphoreStopEvt = FreeRTOS::Semaphore("StopEvt"); - uint32_t m_numHandles; + uint16_t m_numHandles; BLECharacteristic* getLastCreatedCharacteristic(); - void handleGATTServerEvent( - esp_gatts_cb_event_t event, - esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t* param); + void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* param); void setHandle(uint16_t handle); //void setService(esp_gatt_srvc_id_t srvc_id); }; // BLEService diff --git a/cpp_utils/BLEServiceMap.cpp b/cpp_utils/BLEServiceMap.cpp old mode 100644 new mode 100755 index dd828fae..cf4f75f4 --- a/cpp_utils/BLEServiceMap.cpp +++ b/cpp_utils/BLEServiceMap.cpp @@ -17,15 +17,15 @@ * @return The characteristic. */ BLEService* BLEServiceMap::getByUUID(const char* uuid) { - return getByUUID(BLEUUID(uuid)); + return getByUUID(BLEUUID(uuid)); } - + /** * @brief Return the service by UUID. * @param [in] UUID The UUID to look up the service. * @return The characteristic. */ -BLEService* BLEServiceMap::getByUUID(BLEUUID uuid) { +BLEService* BLEServiceMap::getByUUID(BLEUUID uuid, uint8_t inst_id) { for (auto &myPair : m_uuidMap) { if (myPair.first->getUUID().equals(uuid)) { return myPair.first; @@ -52,9 +52,8 @@ BLEService* BLEServiceMap::getByHandle(uint16_t handle) { * @param [in] characteristic The service to cache. * @return N/A. */ -void BLEServiceMap::setByUUID(BLEUUID uuid, - BLEService *service) { - m_uuidMap.insert(std::pair(service, uuid.toString())); +void BLEServiceMap::setByUUID(BLEUUID uuid, BLEService* service) { + m_uuidMap.insert(std::pair(service, uuid.toString())); } // setByUUID @@ -64,9 +63,8 @@ void BLEServiceMap::setByUUID(BLEUUID uuid, * @param [in] service The service to cache. * @return N/A. */ -void BLEServiceMap::setByHandle(uint16_t handle, - BLEService* service) { - m_handleMap.insert(std::pair(handle, service)); +void BLEServiceMap::setByHandle(uint16_t handle, BLEService* service) { + m_handleMap.insert(std::pair(handle, service)); } // setByHandle @@ -86,7 +84,7 @@ std::string BLEServiceMap::toString() { void BLEServiceMap::handleGATTServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, - esp_ble_gatts_cb_param_t *param) { + esp_ble_gatts_cb_param_t* param) { // Invoke the handler for every Service we have. for (auto &myPair : m_uuidMap) { myPair.first->handleGATTServerEvent(event, gatts_if, param); @@ -99,9 +97,7 @@ void BLEServiceMap::handleGATTServerEvent( */ BLEService* BLEServiceMap::getFirst() { m_iterator = m_uuidMap.begin(); - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } + if (m_iterator == m_uuidMap.end()) return nullptr; BLEService* pRet = m_iterator->first; m_iterator++; return pRet; @@ -112,9 +108,7 @@ BLEService* BLEServiceMap::getFirst() { * @return The next service in the map. */ BLEService* BLEServiceMap::getNext() { - if (m_iterator == m_uuidMap.end()) { - return nullptr; - } + if (m_iterator == m_uuidMap.end()) return nullptr; BLEService* pRet = m_iterator->first; m_iterator++; return pRet; @@ -124,9 +118,17 @@ BLEService* BLEServiceMap::getNext() { * @brief Removes service from maps. * @return N/A. */ -void BLEServiceMap::removeService(BLEService *service){ +void BLEServiceMap::removeService(BLEService* service) { m_handleMap.erase(service->getHandle()); m_uuidMap.erase(service); } // removeService +/** + * @brief Returns the amount of registered services + * @return amount of registered services + */ +int BLEServiceMap::getRegisteredServiceCount(){ + return m_handleMap.size(); +} + #endif /* CONFIG_BT_ENABLED */ diff --git a/cpp_utils/BLEUUID.cpp b/cpp_utils/BLEUUID.cpp index 9ca7cdd7..4ddf8fc2 100644 --- a/cpp_utils/BLEUUID.cpp +++ b/cpp_utils/BLEUUID.cpp @@ -6,7 +6,6 @@ */ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) -#include #include #include #include @@ -14,12 +13,16 @@ #include #include #include "BLEUUID.h" -static const char* LOG_TAG = "BLEUUID"; -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG = "BLEUUID"; #endif + /** * @brief Copy memory from source to target but in reverse order. * @@ -41,7 +44,7 @@ static const char* LOG_TAG = "BLEUUID"; */ static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) { assert(size > 0); - target+=(size-1); // Point target to the last byte of the target data + target += (size - 1); // Point target to the last byte of the target data while (size > 0) { *target = *source; target--; @@ -70,45 +73,51 @@ static void memrcpy(uint8_t* target, uint8_t* source, uint32_t size) { */ BLEUUID::BLEUUID(std::string value) { m_valueSet = true; - if (value.length() == 2) { + if (value.length() == 4) { m_uuid.len = ESP_UUID_LEN_16; - m_uuid.uuid.uuid16 = value[0] | (value[1] << 8); + m_uuid.uuid.uuid16 = 0; + for(int i=0;i '9') MSB -= 7; + if(LSB > '9') LSB -= 7; + m_uuid.uuid.uuid16 += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(2-i)*4; + i+=2; + } } - else if (value.length() == 4) { + else if (value.length() == 8) { m_uuid.len = ESP_UUID_LEN_32; - m_uuid.uuid.uuid32 = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); + m_uuid.uuid.uuid32 = 0; + for(int i=0;i '9') MSB -= 7; + if(LSB > '9') LSB -= 7; + m_uuid.uuid.uuid32 += (((MSB&0x0F) <<4) | (LSB & 0x0F))<<(6-i)*4; + i+=2; + } } - else if (value.length() == 16) { + else if (value.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be investigated (lack of time) m_uuid.len = ESP_UUID_LEN_128; memrcpy(m_uuid.uuid.uuid128, (uint8_t*)value.data(), 16); } else if (value.length() == 36) { -// If the length of the string is 36 bytes then we will assume it is a long hex string in -// UUID format. + // If the length of the string is 36 bytes then we will assume it is a long hex string in + // UUID format. m_uuid.len = ESP_UUID_LEN_128; - int vals[16]; - sscanf(value.c_str(), "%2x%2x%2x%2x-%2x%2x-%2x%2x-%2x%2x-%2x%2x%2x%2x%2x%2x", - &vals[15], - &vals[14], - &vals[13], - &vals[12], - &vals[11], - &vals[10], - &vals[9], - &vals[8], - &vals[7], - &vals[6], - &vals[5], - &vals[4], - &vals[3], - &vals[2], - &vals[1], - &vals[0] - ); - - int i; - for (i=0; i<16; i++) { - m_uuid.uuid.uuid128[i] = vals[i]; + int n = 0; + for(int i=0;i '9') MSB -= 7; + if(LSB > '9') LSB -= 7; + m_uuid.uuid.uuid128[15-n++] = ((MSB&0x0F) <<4) | (LSB & 0x0F); + i+=2; } } else { @@ -136,7 +145,7 @@ BLEUUID::BLEUUID(uint8_t* pData, size_t size, bool msbFirst) { } else { memcpy(m_uuid.uuid.uuid128, pData, 16); } - m_valueSet = true; + m_valueSet = true; } // BLEUUID @@ -149,7 +158,6 @@ BLEUUID::BLEUUID(uint16_t uuid) { m_uuid.len = ESP_UUID_LEN_16; m_uuid.uuid.uuid16 = uuid; m_valueSet = true; - } // BLEUUID @@ -194,24 +202,18 @@ BLEUUID::BLEUUID() { * @brief Get the number of bits in this uuid. * @return The number of bits in the UUID. One of 16, 32 or 128. */ -int BLEUUID::bitSize() { - if (m_valueSet == false) { - return 0; - } - switch(m_uuid.len) { - case ESP_UUID_LEN_16: { +uint8_t BLEUUID::bitSize() { + if (!m_valueSet) return 0; + switch (m_uuid.len) { + case ESP_UUID_LEN_16: return 16; - } - case ESP_UUID_LEN_32: { + case ESP_UUID_LEN_32: return 32; - } - case ESP_UUID_LEN_128: { + case ESP_UUID_LEN_128: return 128; - } - default: { + default: ESP_LOGE(LOG_TAG, "Unknown UUID length: %d", m_uuid.len); return 0; - } } // End of switch } // bitSize @@ -224,9 +226,7 @@ int BLEUUID::bitSize() { */ bool BLEUUID::equals(BLEUUID uuid) { //ESP_LOGD(TAG, "Comparing: %s to %s", toString().c_str(), uuid.toString().c_str()); - if (m_valueSet == false || uuid.m_valueSet == false) { - return false; - } + if (!m_valueSet || !uuid.m_valueSet) return false; if (uuid.m_uuid.len != m_uuid.len) { return uuid.toString() == toString(); @@ -253,14 +253,14 @@ bool BLEUUID::equals(BLEUUID uuid) { * NNNNNNNN * */ -BLEUUID BLEUUID::fromString(std::string _uuid){ +BLEUUID BLEUUID::fromString(std::string _uuid) { uint8_t start = 0; if (strstr(_uuid.c_str(), "0x") != nullptr) { // If the string starts with 0x, skip those characters. start = 2; } uint8_t len = _uuid.length() - start; // Calculate the length of the string we are going to use. - if( len == 4) { + if(len == 4) { uint16_t x = strtoul(_uuid.substr(start, len).c_str(), NULL, 16); return BLEUUID(x); } else if (len == 8) { @@ -299,7 +299,7 @@ BLEUUID BLEUUID::to128() { //ESP_LOGD(LOG_TAG, ">> toFull() - %s", toString().c_str()); // If we either don't have a value or are already a 128 bit UUID, nothing further to do. - if (m_valueSet == false || m_uuid.len == ESP_UUID_LEN_128) { + if (!m_valueSet || m_uuid.len == ESP_UUID_LEN_128) { return *this; } @@ -356,9 +356,7 @@ BLEUUID BLEUUID::to128() { * @return A string representation of the UUID. */ std::string BLEUUID::toString() { - if (m_valueSet == false) { // If we have no value, nothing to format. - return ""; - } + if (!m_valueSet) return ""; // If we have no value, nothing to format. // If the UUIDs are 16 or 32 bit, pad correctly. std::stringstream ss; @@ -386,24 +384,23 @@ std::string BLEUUID::toString() { // // UUID string format: // AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP - // ss << std::hex << std::setfill('0') << - std::setw(2) << (int)m_uuid.uuid.uuid128[15] << - std::setw(2) << (int)m_uuid.uuid.uuid128[14] << - std::setw(2) << (int)m_uuid.uuid.uuid128[13] << - std::setw(2) << (int)m_uuid.uuid.uuid128[12] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[11] << - std::setw(2) << (int)m_uuid.uuid.uuid128[10] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[9] << - std::setw(2) << (int)m_uuid.uuid.uuid128[8] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[7] << - std::setw(2) << (int)m_uuid.uuid.uuid128[6] << "-" << - std::setw(2) << (int)m_uuid.uuid.uuid128[5] << - std::setw(2) << (int)m_uuid.uuid.uuid128[4] << - std::setw(2) << (int)m_uuid.uuid.uuid128[3] << - std::setw(2) << (int)m_uuid.uuid.uuid128[2] << - std::setw(2) << (int)m_uuid.uuid.uuid128[1] << - std::setw(2) << (int)m_uuid.uuid.uuid128[0]; + std::setw(2) << (int) m_uuid.uuid.uuid128[15] << + std::setw(2) << (int) m_uuid.uuid.uuid128[14] << + std::setw(2) << (int) m_uuid.uuid.uuid128[13] << + std::setw(2) << (int) m_uuid.uuid.uuid128[12] << "-" << + std::setw(2) << (int) m_uuid.uuid.uuid128[11] << + std::setw(2) << (int) m_uuid.uuid.uuid128[10] << "-" << + std::setw(2) << (int) m_uuid.uuid.uuid128[9] << + std::setw(2) << (int) m_uuid.uuid.uuid128[8] << "-" << + std::setw(2) << (int) m_uuid.uuid.uuid128[7] << + std::setw(2) << (int) m_uuid.uuid.uuid128[6] << "-" << + std::setw(2) << (int) m_uuid.uuid.uuid128[5] << + std::setw(2) << (int) m_uuid.uuid.uuid128[4] << + std::setw(2) << (int) m_uuid.uuid.uuid128[3] << + std::setw(2) << (int) m_uuid.uuid.uuid128[2] << + std::setw(2) << (int) m_uuid.uuid.uuid128[1] << + std::setw(2) << (int) m_uuid.uuid.uuid128[0]; return ss.str(); } // toString diff --git a/cpp_utils/BLEUUID.h b/cpp_utils/BLEUUID.h index 5fb7795b..700739be 100644 --- a/cpp_utils/BLEUUID.h +++ b/cpp_utils/BLEUUID.h @@ -24,7 +24,7 @@ class BLEUUID { BLEUUID(uint8_t* pData, size_t size, bool msbFirst); BLEUUID(esp_gatt_id_t gattId); BLEUUID(); - int bitSize(); // Get the number of bits in this uuid. + uint8_t bitSize(); // Get the number of bits in this uuid. bool equals(BLEUUID uuid); esp_bt_uuid_t* getNative(); BLEUUID to128(); @@ -32,8 +32,8 @@ class BLEUUID { static BLEUUID fromString(std::string uuid); // Create a BLEUUID from a string private: - esp_bt_uuid_t m_uuid; // The underlying UUID structure that this class wraps. - bool m_valueSet; // Is there a value set for this instance. + esp_bt_uuid_t m_uuid; // The underlying UUID structure that this class wraps. + bool m_valueSet = false; // Is there a value set for this instance. }; // BLEUUID #endif /* CONFIG_BT_ENABLED */ #endif /* COMPONENTS_CPP_UTILS_BLEUUID_H_ */ diff --git a/cpp_utils/BLEUtils.cpp b/cpp_utils/BLEUtils.cpp index a33ee27a..a9b735df 100644 --- a/cpp_utils/BLEUtils.cpp +++ b/cpp_utils/BLEUtils.cpp @@ -31,8 +31,8 @@ static const char* LOG_TAG = "BLEUtils"; // Tag for logging. /* -static std::map g_addressMap; -static std::map g_connIdMap; +static std::map g_addressMap; +static std::map g_connIdMap; */ typedef struct { @@ -41,6 +41,7 @@ typedef struct { } member_t; static const member_t members_ids[] = { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 {0xFE08, "Microsoft"}, {0xFE09, "Pillsy, Inc."}, {0xFE0A, "ruwido austria gmbh"}, @@ -290,6 +291,7 @@ static const member_t members_ids[] = { {0xFEFE, "GN ReSound A/S"}, {0xFEFF, "GN Netcom"}, {0xFFFF, "Reserved"}, /*for testing purposes only*/ +#endif {0, "" } }; @@ -299,6 +301,7 @@ typedef struct { } gattdescriptor_t; static const gattdescriptor_t g_descriptor_ids[] = { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 {0x2905,"Characteristic Aggregate Format"}, {0x2900,"Characteristic Extended Properties"}, {0x2904,"Characteristic Presentation Format"}, @@ -314,6 +317,7 @@ static const gattdescriptor_t g_descriptor_ids[] = { {0x290E,"Time Trigger Setting"}, {0x2906,"Valid Range"}, {0x290A,"Value Trigger Setting"}, +#endif { 0, "" } }; @@ -323,6 +327,7 @@ typedef struct { } characteristicMap_t; static const characteristicMap_t g_characteristicsMappings[] = { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 {0x2A7E,"Aerobic Heart Rate Lower Limit"}, {0x2A84,"Aerobic Heart Rate Upper Limit"}, {0x2A7F,"Aerobic Threshold"}, @@ -539,6 +544,7 @@ static const characteristicMap_t g_characteristicsMappings[] = { {0x2A9D,"Weight Measurement"}, {0x2A9E,"Weight Scale Feature"}, {0x2A79,"Wind Chill"}, +#endif {0, ""} }; @@ -556,6 +562,7 @@ typedef struct { * Definition of the service ids to names that we know about. */ static const gattService_t g_gattServices[] = { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 {"Alert Notification Service", "org.bluetooth.service.alert_notification", 0x1811}, {"Automation IO", "org.bluetooth.service.automation_io", 0x1815 }, {"Battery Service","org.bluetooth.service.battery_service", 0x180F}, @@ -591,6 +598,7 @@ static const gattService_t g_gattServices[] = { {"Tx Power", "org.bluetooth.service.tx_power", 0x1804}, {"User Data", "org.bluetooth.service.user_data", 0x181C}, {"Weight Scale", "org.bluetooth.service.weight_scale", 0x181D}, +#endif {"", "", 0 } }; @@ -628,7 +636,7 @@ static std::string gattIdToString(esp_gatt_id_t gattId) { * @brief Convert an esp_ble_addr_type_t to a string representation. */ const char* BLEUtils::addressTypeToString(esp_ble_addr_type_t type) { - switch(type) { + switch (type) { case BLE_ADDR_TYPE_PUBLIC: return "BLE_ADDR_TYPE_PUBLIC"; case BLE_ADDR_TYPE_RANDOM: @@ -650,19 +658,19 @@ const char* BLEUtils::addressTypeToString(esp_ble_addr_type_t type) { */ std::string BLEUtils::adFlagsToString(uint8_t adFlags) { std::stringstream ss; - if (adFlags & (1<<0)) { + if (adFlags & (1 << 0)) { ss << "[LE Limited Discoverable Mode] "; } - if (adFlags & (1<<1)) { + if (adFlags & (1 << 1)) { ss << "[LE General Discoverable Mode] "; } - if (adFlags & (1<<2)) { + if (adFlags & (1 << 2)) { ss << "[BR/EDR Not Supported] "; } - if (adFlags & (1<<3)) { + if (adFlags & (1 << 3)) { ss << "[Simultaneous LE and BR/EDR to Same Device Capable (Controller)] "; } - if (adFlags & (1<<4)) { + if (adFlags & (1 << 4)) { ss << "[Simultaneous LE and BR/EDR to Same Device Capable (Host)] "; } return ss.str(); @@ -678,84 +686,59 @@ std::string BLEUtils::adFlagsToString(uint8_t adFlags) { * @return A string representation of the type. */ const char* BLEUtils::advTypeToString(uint8_t advType) { - switch(advType) { - case ESP_BLE_AD_TYPE_FLAG: // 0x01 + switch (advType) { + case ESP_BLE_AD_TYPE_FLAG: // 0x01 return "ESP_BLE_AD_TYPE_FLAG"; - - case ESP_BLE_AD_TYPE_16SRV_PART: // 0x02 + case ESP_BLE_AD_TYPE_16SRV_PART: // 0x02 return "ESP_BLE_AD_TYPE_16SRV_PART"; - - case ESP_BLE_AD_TYPE_16SRV_CMPL: // 0x03 + case ESP_BLE_AD_TYPE_16SRV_CMPL: // 0x03 return "ESP_BLE_AD_TYPE_16SRV_CMPL"; - - case ESP_BLE_AD_TYPE_32SRV_PART: // 0x04 + case ESP_BLE_AD_TYPE_32SRV_PART: // 0x04 return "ESP_BLE_AD_TYPE_32SRV_PART"; - - case ESP_BLE_AD_TYPE_32SRV_CMPL: // 0x05 + case ESP_BLE_AD_TYPE_32SRV_CMPL: // 0x05 return "ESP_BLE_AD_TYPE_32SRV_CMPL"; - - case ESP_BLE_AD_TYPE_128SRV_PART: // 0x06 + case ESP_BLE_AD_TYPE_128SRV_PART: // 0x06 return "ESP_BLE_AD_TYPE_128SRV_PART"; - - case ESP_BLE_AD_TYPE_128SRV_CMPL: // 0x07 + case ESP_BLE_AD_TYPE_128SRV_CMPL: // 0x07 return "ESP_BLE_AD_TYPE_128SRV_CMPL"; - - case ESP_BLE_AD_TYPE_NAME_SHORT: // 0x08 + case ESP_BLE_AD_TYPE_NAME_SHORT: // 0x08 return "ESP_BLE_AD_TYPE_NAME_SHORT"; - - case ESP_BLE_AD_TYPE_NAME_CMPL: // 0x09 + case ESP_BLE_AD_TYPE_NAME_CMPL: // 0x09 return "ESP_BLE_AD_TYPE_NAME_CMPL"; - - case ESP_BLE_AD_TYPE_TX_PWR: // 0x0a + case ESP_BLE_AD_TYPE_TX_PWR: // 0x0a return "ESP_BLE_AD_TYPE_TX_PWR"; - - case ESP_BLE_AD_TYPE_DEV_CLASS: // 0x0b + case ESP_BLE_AD_TYPE_DEV_CLASS: // 0x0b return "ESP_BLE_AD_TYPE_DEV_CLASS"; - - case ESP_BLE_AD_TYPE_SM_TK: // 0x10 + case ESP_BLE_AD_TYPE_SM_TK: // 0x10 return "ESP_BLE_AD_TYPE_SM_TK"; - - case ESP_BLE_AD_TYPE_SM_OOB_FLAG: // 0x11 + case ESP_BLE_AD_TYPE_SM_OOB_FLAG: // 0x11 return "ESP_BLE_AD_TYPE_SM_OOB_FLAG"; - - case ESP_BLE_AD_TYPE_INT_RANGE: // 0x12 + case ESP_BLE_AD_TYPE_INT_RANGE: // 0x12 return "ESP_BLE_AD_TYPE_INT_RANGE"; - - case ESP_BLE_AD_TYPE_SOL_SRV_UUID: // 0x14 + case ESP_BLE_AD_TYPE_SOL_SRV_UUID: // 0x14 return "ESP_BLE_AD_TYPE_SOL_SRV_UUID"; - - case ESP_BLE_AD_TYPE_128SOL_SRV_UUID: // 0x15 + case ESP_BLE_AD_TYPE_128SOL_SRV_UUID: // 0x15 return "ESP_BLE_AD_TYPE_128SOL_SRV_UUID"; - - case ESP_BLE_AD_TYPE_SERVICE_DATA: // 0x16 + case ESP_BLE_AD_TYPE_SERVICE_DATA: // 0x16 return "ESP_BLE_AD_TYPE_SERVICE_DATA"; - - case ESP_BLE_AD_TYPE_PUBLIC_TARGET: // 0x17 + case ESP_BLE_AD_TYPE_PUBLIC_TARGET: // 0x17 return "ESP_BLE_AD_TYPE_PUBLIC_TARGET"; - - case ESP_BLE_AD_TYPE_RANDOM_TARGET: // 0x18 + case ESP_BLE_AD_TYPE_RANDOM_TARGET: // 0x18 return "ESP_BLE_AD_TYPE_RANDOM_TARGET"; - - case ESP_BLE_AD_TYPE_APPEARANCE: // 0x19 + case ESP_BLE_AD_TYPE_APPEARANCE: // 0x19 return "ESP_BLE_AD_TYPE_APPEARANCE"; - - case ESP_BLE_AD_TYPE_ADV_INT: // 0x1a + case ESP_BLE_AD_TYPE_ADV_INT: // 0x1a return "ESP_BLE_AD_TYPE_ADV_INT"; - case ESP_BLE_AD_TYPE_32SOL_SRV_UUID: return "ESP_BLE_AD_TYPE_32SOL_SRV_UUID"; - - case ESP_BLE_AD_TYPE_32SERVICE_DATA: // 0x20 + case ESP_BLE_AD_TYPE_32SERVICE_DATA: // 0x20 return "ESP_BLE_AD_TYPE_32SERVICE_DATA"; - - case ESP_BLE_AD_TYPE_128SERVICE_DATA: // 0x21 + case ESP_BLE_AD_TYPE_128SERVICE_DATA: // 0x21 return "ESP_BLE_AD_TYPE_128SERVICE_DATA"; - case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: // 0xff return "ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE"; - default: - ESP_LOGD(LOG_TAG, " adv data type: 0x%x", advType); + ESP_LOGV(LOG_TAG, " adv data type: 0x%x", advType); return ""; } // End switch } // advTypeToString @@ -768,8 +751,7 @@ esp_gatt_id_t BLEUtils::buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id) { return retGattId; } -esp_gatt_srvc_id_t BLEUtils::buildGattSrvcId(esp_gatt_id_t gattId, - bool is_primary) { +esp_gatt_srvc_id_t BLEUtils::buildGattSrvcId(esp_gatt_id_t gattId, bool is_primary) { esp_gatt_srvc_id_t retSrvcId; retSrvcId.id = gattId; retSrvcId.is_primary = is_primary; @@ -784,29 +766,26 @@ esp_gatt_srvc_id_t BLEUtils::buildGattSrvcId(esp_gatt_id_t gattId, * @param [in] length The length of the data to convert. * @return A pointer to the formatted buffer. */ -char* BLEUtils::buildHexData(uint8_t *target, uint8_t *source, uint8_t length) { -// Guard against too much data. - if (length > 100) { - length = 100; - } +char* BLEUtils::buildHexData(uint8_t* target, uint8_t* source, uint8_t length) { + // Guard against too much data. + if (length > 100) length = 100; if (target == nullptr) { - target = (uint8_t *)malloc(length * 2 + 1); + target = (uint8_t*) malloc(length * 2 + 1); if (target == nullptr) { ESP_LOGE(LOG_TAG, "buildHexData: malloc failed"); return nullptr; } } - char *startOfData = (char *)target; + char* startOfData = (char*) target; - int i; - for (i=0; i 4 // ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT // adv_data_cmpl // - esp_bt_status_t - // case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->adv_data_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->adv_data_cmpl.status); break; } // ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT - - // // ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT // // adv_data_raw_cmpl // - esp_bt_status_t status - // case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->adv_data_raw_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->adv_data_raw_cmpl.status); break; } // ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT - - // // ESP_GAP_BLE_ADV_START_COMPLETE_EVT // // adv_start_cmpl // - esp_bt_status_t status - // case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->adv_start_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->adv_start_cmpl.status); break; } // ESP_GAP_BLE_ADV_START_COMPLETE_EVT - - // // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT // // adv_stop_cmpl // - esp_bt_status_t status - // case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->adv_stop_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->adv_stop_cmpl.status); break; } // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT - - // // ESP_GAP_BLE_AUTH_CMPL_EVT // // auth_cmpl @@ -1148,9 +1081,8 @@ void BLEUtils::dumpGapEvent( // - uint8_t fail_reason // - esp_bd_addr_type_t addr_type // - esp_bt_dev_type_t dev_type - // case ESP_GAP_BLE_AUTH_CMPL_EVT: { - ESP_LOGD(LOG_TAG, "[bd_addr: %s, key_present: %d, key: ***, key_type: %d, success: %d, fail_reason: %d, addr_type: ***, dev_type: %s]", + ESP_LOGV(LOG_TAG, "[bd_addr: %s, key_present: %d, key: ***, key_type: %d, success: %d, fail_reason: %d, addr_type: ***, dev_type: %s]", BLEAddress(param->ble_security.auth_cmpl.bd_addr).toString().c_str(), param->ble_security.auth_cmpl.key_present, param->ble_security.auth_cmpl.key_type, @@ -1161,56 +1093,41 @@ void BLEUtils::dumpGapEvent( break; } // ESP_GAP_BLE_AUTH_CMPL_EVT - - // // ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT // // clear_bond_dev_cmpl // - esp_bt_status_t status - // case ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->clear_bond_dev_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->clear_bond_dev_cmpl.status); break; } // ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT - - // // ESP_GAP_BLE_LOCAL_IR_EVT - // case ESP_GAP_BLE_LOCAL_IR_EVT: { break; } // ESP_GAP_BLE_LOCAL_IR_EVT - - // // ESP_GAP_BLE_LOCAL_ER_EVT - // case ESP_GAP_BLE_LOCAL_ER_EVT: { break; } // ESP_GAP_BLE_LOCAL_ER_EVT - - // // ESP_GAP_BLE_NC_REQ_EVT - // case ESP_GAP_BLE_NC_REQ_EVT: { - ESP_LOGD(LOG_TAG, "[bd_addr: %s, passkey: %d]", + ESP_LOGV(LOG_TAG, "[bd_addr: %s, passkey: %d]", BLEAddress(param->ble_security.key_notif.bd_addr).toString().c_str(), param->ble_security.key_notif.passkey); break; } // ESP_GAP_BLE_NC_REQ_EVT - - // // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT // // read_rssi_cmpl // - esp_bt_status_t status // - int8_t rssi // - esp_bd_addr_t remote_addr - // case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d, rssi: %d, remote_addr: %s]", + ESP_LOGV(LOG_TAG, "[status: %d, rssi: %d, remote_addr: %s]", param->read_rssi_cmpl.status, param->read_rssi_cmpl.rssi, BLEAddress(param->read_rssi_cmpl.remote_addr).toString().c_str() @@ -1218,20 +1135,15 @@ void BLEUtils::dumpGapEvent( break; } // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT - - // // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT // // scan_param_cmpl. // - esp_bt_status_t status - // case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_param_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->scan_param_cmpl.status); break; } // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT - - // // ESP_GAP_BLE_SCAN_RESULT_EVT // // scan_rst: @@ -1246,11 +1158,10 @@ void BLEUtils::dumpGapEvent( // - num_resps // - adv_data_len // - scan_rsp_len - // case ESP_GAP_BLE_SCAN_RESULT_EVT: { - switch(param->scan_rst.search_evt) { + switch (param->scan_rst.search_evt) { case ESP_GAP_SEARCH_INQ_RES_EVT: { - ESP_LOGD(LOG_TAG, "search_evt: %s, bda: %s, dev_type: %s, ble_addr_type: %s, ble_evt_type: %s, rssi: %d, ble_adv: ??, flag: %d (%s), num_resps: %d, adv_data_len: %d, scan_rsp_len: %d", + ESP_LOGV(LOG_TAG, "search_evt: %s, bda: %s, dev_type: %s, ble_addr_type: %s, ble_evt_type: %s, rssi: %d, ble_adv: ??, flag: %d (%s), num_resps: %d, adv_data_len: %d, scan_rsp_len: %d", searchEventTypeToString(param->scan_rst.search_evt), BLEAddress(param->scan_rst.bda).toString().c_str(), devTypeToString(param->scan_rst.dev_type), @@ -1267,59 +1178,46 @@ void BLEUtils::dumpGapEvent( } // ESP_GAP_SEARCH_INQ_RES_EVT default: { - ESP_LOGD(LOG_TAG, "search_evt: %s",searchEventTypeToString(param->scan_rst.search_evt)); + ESP_LOGV(LOG_TAG, "search_evt: %s",searchEventTypeToString(param->scan_rst.search_evt)); break; } } break; } // ESP_GAP_BLE_SCAN_RESULT_EVT - - // // ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT // // scan_rsp_data_cmpl // - esp_bt_status_t status - // case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_rsp_data_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->scan_rsp_data_cmpl.status); break; } // ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT - - // // ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT - // case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_rsp_data_raw_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->scan_rsp_data_raw_cmpl.status); break; } // ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT - - // // ESP_GAP_BLE_SCAN_START_COMPLETE_EVT // // scan_start_cmpl // - esp_bt_status_t status case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_start_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->scan_start_cmpl.status); break; } // ESP_GAP_BLE_SCAN_START_COMPLETE_EVT - - // // ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT // // scan_stop_cmpl // - esp_bt_status_t status - // case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d]", param->scan_stop_cmpl.status); + ESP_LOGV(LOG_TAG, "[status: %d]", param->scan_stop_cmpl.status); break; } // ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT - - // // ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT // // update_conn_params @@ -1330,9 +1228,8 @@ void BLEUtils::dumpGapEvent( // - uint16_t latency // - uint16_t conn_int // - uint16_t timeout - // case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: { - ESP_LOGD(LOG_TAG, "[status: %d, bd_addr: %s, min_int: %d, max_int: %d, latency: %d, conn_int: %d, timeout: %d]", + ESP_LOGV(LOG_TAG, "[status: %d, bd_addr: %s, min_int: %d, max_int: %d, latency: %d, conn_int: %d, timeout: %d]", param->update_conn_params.status, BLEAddress(param->update_conn_params.bda).toString().c_str(), param->update_conn_params.min_int, @@ -1344,18 +1241,14 @@ void BLEUtils::dumpGapEvent( break; } // ESP_GAP_BLE_SCAN_UPDATE_CONN_PARAMS_EVT - - // // ESP_GAP_BLE_SEC_REQ_EVT - // case ESP_GAP_BLE_SEC_REQ_EVT: { - ESP_LOGD(LOG_TAG, "[bd_addr: %s]", BLEAddress(param->ble_security.ble_req.bd_addr).toString().c_str()); + ESP_LOGV(LOG_TAG, "[bd_addr: %s]", BLEAddress(param->ble_security.ble_req.bd_addr).toString().c_str()); break; } // ESP_GAP_BLE_SEC_REQ_EVT - - +#endif default: { - ESP_LOGD(LOG_TAG, "*** dumpGapEvent: Logger not coded ***"); + ESP_LOGV(LOG_TAG, "*** dumpGapEvent: Logger not coded ***"); break; } // default } // switch @@ -1373,10 +1266,10 @@ void BLEUtils::dumpGattClientEvent( esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) { - //esp_ble_gattc_cb_param_t *evtParam = (esp_ble_gattc_cb_param_t *)param; - ESP_LOGD(LOG_TAG, "GATT Event: %s", BLEUtils::gattClientEventTypeToString(event).c_str()); - switch(event) { - // + //esp_ble_gattc_cb_param_t* evtParam = (esp_ble_gattc_cb_param_t*) param; + ESP_LOGV(LOG_TAG, "GATT Event: %s", BLEUtils::gattClientEventTypeToString(event).c_str()); + switch (event) { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 // ESP_GATTC_CLOSE_EVT // // close: @@ -1384,16 +1277,14 @@ void BLEUtils::dumpGattClientEvent( // - uint16_t conn_id // - esp_bd_addr_t remote_bda // - esp_gatt_conn_reason_t reason - // case ESP_GATTC_CLOSE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, reason:%s, conn_id: %d]", + ESP_LOGV(LOG_TAG, "[status: %s, reason:%s, conn_id: %d]", BLEUtils::gattStatusToString(evtParam->close.status).c_str(), BLEUtils::gattCloseReasonToString(evtParam->close.reason).c_str(), evtParam->close.conn_id); break; } - // // ESP_GATTC_CONNECT_EVT // // connect: @@ -1401,14 +1292,13 @@ void BLEUtils::dumpGattClientEvent( // - uint16_t conn_id // - esp_bd_addr_t remote_bda case ESP_GATTC_CONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, remote_bda: %s]", evtParam->connect.conn_id, BLEAddress(evtParam->connect.remote_bda).toString().c_str() ); break; } - // // ESP_GATTC_DISCONNECT_EVT // // disconnect: @@ -1416,7 +1306,7 @@ void BLEUtils::dumpGattClientEvent( // - uint16_t conn_id // - esp_bd_addr_t remote_bda case ESP_GATTC_DISCONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[reason: %s, conn_id: %d, remote_bda: %s]", + ESP_LOGV(LOG_TAG, "[reason: %s, conn_id: %d, remote_bda: %s]", BLEUtils::gattCloseReasonToString(evtParam->disconnect.reason).c_str(), evtParam->disconnect.conn_id, BLEAddress(evtParam->disconnect.remote_bda).toString().c_str() @@ -1424,7 +1314,6 @@ void BLEUtils::dumpGattClientEvent( break; } // ESP_GATTC_DISCONNECT_EVT - // // ESP_GATTC_GET_CHAR_EVT // // get_char: @@ -1433,7 +1322,6 @@ void BLEUtils::dumpGattClientEvent( // - esp_gatt_srvc_id_t srvc_id // - esp_gatt_id_t char_id // - esp_gatt_char_prop_t char_prop - // /* case ESP_GATTC_GET_CHAR_EVT: { @@ -1444,7 +1332,7 @@ void BLEUtils::dumpGattClientEvent( if (evtParam->get_char.char_id.uuid.len == ESP_UUID_LEN_16) { description = BLEUtils::gattCharacteristicUUIDToString(evtParam->get_char.char_id.uuid.uuid.uuid16); } - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s, char_id: %s [description: %s]\nchar_prop: %s]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s, char_id: %s [description: %s]\nchar_prop: %s]", BLEUtils::gattStatusToString(evtParam->get_char.status).c_str(), evtParam->get_char.conn_id, BLEUtils::gattServiceIdToString(evtParam->get_char.srvc_id).c_str(), @@ -1453,7 +1341,7 @@ void BLEUtils::dumpGattClientEvent( BLEUtils::characteristicPropertiesToString(evtParam->get_char.char_prop).c_str() ); } else { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: %d, srvc_id: %s]", BLEUtils::gattStatusToString(evtParam->get_char.status).c_str(), evtParam->get_char.conn_id, BLEUtils::gattServiceIdToString(evtParam->get_char.srvc_id).c_str() @@ -1463,7 +1351,6 @@ void BLEUtils::dumpGattClientEvent( } // ESP_GATTC_GET_CHAR_EVT */ - // // ESP_GATTC_NOTIFY_EVT // // notify @@ -1475,7 +1362,7 @@ void BLEUtils::dumpGattClientEvent( // bool is_notify // case ESP_GATTC_NOTIFY_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s, handle: %d 0x%.2x, value_len: %d, is_notify: %d]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, remote_bda: %s, handle: %d 0x%.2x, value_len: %d, is_notify: %d]", evtParam->notify.conn_id, BLEAddress(evtParam->notify.remote_bda).toString().c_str(), evtParam->notify.handle, @@ -1486,7 +1373,6 @@ void BLEUtils::dumpGattClientEvent( break; } - // // ESP_GATTC_OPEN_EVT // // open: @@ -1496,7 +1382,7 @@ void BLEUtils::dumpGattClientEvent( // - uint16_t mtu // case ESP_GATTC_OPEN_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, remote_bda: %s, mtu: %d]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: %d, remote_bda: %s, mtu: %d]", BLEUtils::gattStatusToString(evtParam->open.status).c_str(), evtParam->open.conn_id, BLEAddress(evtParam->open.remote_bda).toString().c_str(), @@ -1504,8 +1390,6 @@ void BLEUtils::dumpGattClientEvent( break; } // ESP_GATTC_OPEN_EVT - - // // ESP_GATTC_READ_CHAR_EVT // // Callback to indicate that requested data that we wanted to read is now available. @@ -1518,7 +1402,7 @@ void BLEUtils::dumpGattClientEvent( // uint16_t value_type // uint16_t value_len case ESP_GATTC_READ_CHAR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, handle: %d 0x%.2x, value_len: %d]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: %d, handle: %d 0x%.2x, value_len: %d]", BLEUtils::gattStatusToString(evtParam->read.status).c_str(), evtParam->read.conn_id, evtParam->read.handle, @@ -1528,38 +1412,33 @@ void BLEUtils::dumpGattClientEvent( if (evtParam->read.status == ESP_GATT_OK) { GeneralUtils::hexDump(evtParam->read.value, evtParam->read.value_len); /* - char *pHexData = BLEUtils::buildHexData(nullptr, evtParam->read.value, evtParam->read.value_len); - ESP_LOGD(LOG_TAG, "value: %s \"%s\"", pHexData, BLEUtils::buildPrintData(evtParam->read.value, evtParam->read.value_len).c_str()); + char* pHexData = BLEUtils::buildHexData(nullptr, evtParam->read.value, evtParam->read.value_len); + ESP_LOGV(LOG_TAG, "value: %s \"%s\"", pHexData, BLEUtils::buildPrintData(evtParam->read.value, evtParam->read.value_len).c_str()); free(pHexData); */ } break; } // ESP_GATTC_READ_CHAR_EVT - - // // ESP_GATTC_REG_EVT // // reg: // - esp_gatt_status_t status // - uint16_t app_id - // case ESP_GATTC_REG_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, app_id: 0x%x]", + ESP_LOGV(LOG_TAG, "[status: %s, app_id: 0x%x]", BLEUtils::gattStatusToString(evtParam->reg.status).c_str(), evtParam->reg.app_id); break; } // ESP_GATTC_REG_EVT - - // // ESP_GATTC_REG_FOR_NOTIFY_EVT // // reg_for_notify: // - esp_gatt_status_t status // - uint16_t handle case ESP_GATTC_REG_FOR_NOTIFY_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, handle: %d 0x%.2x]", + ESP_LOGV(LOG_TAG, "[status: %s, handle: %d 0x%.2x]", BLEUtils::gattStatusToString(evtParam->reg_for_notify.status).c_str(), evtParam->reg_for_notify.handle, evtParam->reg_for_notify.handle @@ -1567,23 +1446,18 @@ void BLEUtils::dumpGattClientEvent( break; } // ESP_GATTC_REG_FOR_NOTIFY_EVT - - // // ESP_GATTC_SEARCH_CMPL_EVT // // search_cmpl: // - esp_gatt_status_t status // - uint16_t conn_id - // case ESP_GATTC_SEARCH_CMPL_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: %d]", BLEUtils::gattStatusToString(evtParam->search_cmpl.status).c_str(), evtParam->search_cmpl.conn_id); break; } // ESP_GATTC_SEARCH_CMPL_EVT - - // // ESP_GATTC_SEARCH_RES_EVT // // search_res: @@ -1591,9 +1465,8 @@ void BLEUtils::dumpGattClientEvent( // - uint16_t start_handle // - uint16_t end_handle // - esp_gatt_id_t srvc_id - // case ESP_GATTC_SEARCH_RES_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, start_handle: %d 0x%.2x, end_handle: %d 0x%.2x, srvc_id: %s", + ESP_LOGV(LOG_TAG, "[conn_id: %d, start_handle: %d 0x%.2x, end_handle: %d 0x%.2x, srvc_id: %s", evtParam->search_res.conn_id, evtParam->search_res.start_handle, evtParam->search_res.start_handle, @@ -1603,8 +1476,6 @@ void BLEUtils::dumpGattClientEvent( break; } // ESP_GATTC_SEARCH_RES_EVT - - // // ESP_GATTC_WRITE_CHAR_EVT // // write: @@ -1612,9 +1483,8 @@ void BLEUtils::dumpGattClientEvent( // - uint16_t conn_id // - uint16_t handle // - uint16_t offset - // case ESP_GATTC_WRITE_CHAR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: %d, handle: %d 0x%.2x, offset: %d]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: %d, handle: %d 0x%.2x, offset: %d]", BLEUtils::gattStatusToString(evtParam->write.status).c_str(), evtParam->write.conn_id, evtParam->write.handle, @@ -1623,7 +1493,7 @@ void BLEUtils::dumpGattClientEvent( ); break; } // ESP_GATTC_WRITE_CHAR_EVT - +#endif default: break; } @@ -1644,11 +1514,12 @@ void BLEUtils::dumpGattServerEvent( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t* evtParam) { - ESP_LOGD(LOG_TAG, "GATT ServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); - switch(event) { + ESP_LOGV(LOG_TAG, "GATT ServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); + switch (event) { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 case ESP_GATTS_ADD_CHAR_DESCR_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, attr_handle: %d 0x%.2x, service_handle: %d 0x%.2x, char_uuid: %s]", + ESP_LOGV(LOG_TAG, "[status: %s, attr_handle: %d 0x%.2x, service_handle: %d 0x%.2x, char_uuid: %s]", gattStatusToString(evtParam->add_char_descr.status).c_str(), evtParam->add_char_descr.attr_handle, evtParam->add_char_descr.attr_handle, @@ -1660,7 +1531,7 @@ void BLEUtils::dumpGattServerEvent( case ESP_GATTS_ADD_CHAR_EVT: { if (evtParam->add_char.status == ESP_GATT_OK) { - ESP_LOGD(LOG_TAG, "[status: %s, attr_handle: %d 0x%.2x, service_handle: %d 0x%.2x, char_uuid: %s]", + ESP_LOGV(LOG_TAG, "[status: %s, attr_handle: %d 0x%.2x, service_handle: %d 0x%.2x, char_uuid: %s]", gattStatusToString(evtParam->add_char.status).c_str(), evtParam->add_char.attr_handle, evtParam->add_char.attr_handle, @@ -1685,9 +1556,8 @@ void BLEUtils::dumpGattServerEvent( // conf: // - esp_gatt_status_t status – The status code. // - uint16_t conn_id – The connection used. - // case ESP_GATTS_CONF_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, conn_id: 0x%.2x]", + ESP_LOGV(LOG_TAG, "[status: %s, conn_id: 0x%.2x]", gattStatusToString(evtParam->conf.status).c_str(), evtParam->conf.conn_id); break; @@ -1695,21 +1565,21 @@ void BLEUtils::dumpGattServerEvent( case ESP_GATTS_CONGEST_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, congested: %d]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, congested: %d]", evtParam->congest.conn_id, evtParam->congest.congested); break; } // ESP_GATTS_CONGEST_EVT case ESP_GATTS_CONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, remote_bda: %s]", evtParam->connect.conn_id, BLEAddress(evtParam->connect.remote_bda).toString().c_str()); break; } // ESP_GATTS_CONNECT_EVT case ESP_GATTS_CREATE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, service_handle: %d 0x%.2x, service_id: [%s]]", + ESP_LOGV(LOG_TAG, "[status: %s, service_handle: %d 0x%.2x, service_id: [%s]]", gattStatusToString(evtParam->create.status).c_str(), evtParam->create.service_handle, evtParam->create.service_handle, @@ -1718,7 +1588,7 @@ void BLEUtils::dumpGattServerEvent( } // ESP_GATTS_CREATE_EVT case ESP_GATTS_DISCONNECT_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, remote_bda: %s]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, remote_bda: %s]", evtParam->connect.conn_id, BLEAddress(evtParam->connect.remote_bda).toString().c_str()); break; @@ -1731,26 +1601,25 @@ void BLEUtils::dumpGattServerEvent( // - uint32_t trans_id // - esp_bd_addr_t bda // - uint8_t exec_write_flag - // case ESP_GATTS_EXEC_WRITE_EVT: { char* pWriteFlagText; - switch(evtParam->exec_write.exec_write_flag) { + switch (evtParam->exec_write.exec_write_flag) { case ESP_GATT_PREP_WRITE_EXEC: { - pWriteFlagText = (char*)"WRITE"; + pWriteFlagText = (char*) "WRITE"; break; } case ESP_GATT_PREP_WRITE_CANCEL: { - pWriteFlagText = (char*)"CANCEL"; + pWriteFlagText = (char*) "CANCEL"; break; } default: - pWriteFlagText = (char*)""; + pWriteFlagText = (char*) ""; break; } - ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, exec_write_flag: 0x%.2x=%s]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, exec_write_flag: 0x%.2x=%s]", evtParam->exec_write.conn_id, evtParam->exec_write.trans_id, BLEAddress(evtParam->exec_write.bda).toString().c_str(), @@ -1761,14 +1630,14 @@ void BLEUtils::dumpGattServerEvent( case ESP_GATTS_MTU_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, mtu: %d]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, mtu: %d]", evtParam->mtu.conn_id, evtParam->mtu.mtu); break; } // ESP_GATTS_MTU_EVT case ESP_GATTS_READ_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, is_long: %d, need_rsp:%d]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, is_long: %d, need_rsp:%d]", evtParam->read.conn_id, evtParam->read.trans_id, BLEAddress(evtParam->read.bda).toString().c_str(), @@ -1779,14 +1648,14 @@ void BLEUtils::dumpGattServerEvent( } // ESP_GATTS_READ_EVT case ESP_GATTS_RESPONSE_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, handle: 0x%.2x]", + ESP_LOGV(LOG_TAG, "[status: %s, handle: 0x%.2x]", gattStatusToString(evtParam->rsp.status).c_str(), evtParam->rsp.handle); break; } // ESP_GATTS_RESPONSE_EVT case ESP_GATTS_REG_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, app_id: %d]", + ESP_LOGV(LOG_TAG, "[status: %s, app_id: %d]", gattStatusToString(evtParam->reg.status).c_str(), evtParam->reg.app_id); break; @@ -1798,9 +1667,8 @@ void BLEUtils::dumpGattServerEvent( // start: // - esp_gatt_status_t status // - uint16_t service_handle - // case ESP_GATTS_START_EVT: { - ESP_LOGD(LOG_TAG, "[status: %s, service_handle: 0x%.2x]", + ESP_LOGV(LOG_TAG, "[status: %s, service_handle: 0x%.2x]", gattStatusToString(evtParam->start.status).c_str(), evtParam->start.service_handle); break; @@ -1819,9 +1687,8 @@ void BLEUtils::dumpGattServerEvent( // - bool is_prep – Is this a write prepare? If set, then this is to be considered part of the received value and not the whole value. A subsequent ESP_GATTS_EXEC_WRITE will mark the total. // - uint16_t len – The length of the incoming value part. // - uint8_t* value – The data for this value part. - // case ESP_GATTS_WRITE_EVT: { - ESP_LOGD(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, offset: %d, need_rsp: %d, is_prep: %d, len: %d]", + ESP_LOGV(LOG_TAG, "[conn_id: %d, trans_id: %d, bda: %s, handle: 0x%.2x, offset: %d, need_rsp: %d, is_prep: %d, len: %d]", evtParam->write.conn_id, evtParam->write.trans_id, BLEAddress(evtParam->write.bda).toString().c_str(), @@ -1831,13 +1698,13 @@ void BLEUtils::dumpGattServerEvent( evtParam->write.is_prep, evtParam->write.len); char* pHex = buildHexData(nullptr, evtParam->write.value, evtParam->write.len); - ESP_LOGD(LOG_TAG, "[Data: %s]", pHex); + ESP_LOGV(LOG_TAG, "[Data: %s]", pHex); free(pHex); break; } // ESP_GATTS_WRITE_EVT - +#endif default: - ESP_LOGD(LOG_TAG, "dumpGattServerEvent: *** NOT CODED ***"); + ESP_LOGV(LOG_TAG, "dumpGattServerEvent: *** NOT CODED ***"); break; } } // dumpGattServerEvent @@ -1849,7 +1716,7 @@ void BLEUtils::dumpGattServerEvent( * @return The event type as a string. */ const char* BLEUtils::eventTypeToString(esp_ble_evt_type_t eventType) { - switch(eventType) { + switch (eventType) { case ESP_BLE_EVT_CONN_ADV: return "ESP_BLE_EVT_CONN_ADV"; case ESP_BLE_EVT_CONN_DIR_ADV: @@ -1861,7 +1728,7 @@ const char* BLEUtils::eventTypeToString(esp_ble_evt_type_t eventType) { case ESP_BLE_EVT_SCAN_RSP: return "ESP_BLE_EVT_SCAN_RSP"; default: - ESP_LOGD(LOG_TAG, "Unknown esp_ble_evt_type_t: %d (0x%.2x)", eventType, eventType); + ESP_LOGV(LOG_TAG, "Unknown esp_ble_evt_type_t: %d (0x%.2x)", eventType, eventType); return "*** Unknown ***"; } } // eventTypeToString @@ -1874,98 +1741,70 @@ const char* BLEUtils::eventTypeToString(esp_ble_evt_type_t eventType) { * @return A string representation of the event type. */ const char* BLEUtils::gapEventToString(uint32_t eventType) { - switch(eventType) { + switch (eventType) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: return "ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: return "ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: return "ESP_GAP_BLE_ADV_START_COMPLETE_EVT"; - - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: /*!< When stop adv complete, the event comes */ + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: /* !< When stop adv complete, the event comes */ return "ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT"; - - case ESP_GAP_BLE_AUTH_CMPL_EVT: /* Authentication complete indication. */ + case ESP_GAP_BLE_AUTH_CMPL_EVT: /* Authentication complete indication. */ return "ESP_GAP_BLE_AUTH_CMPL_EVT"; - case ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT: return "ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT"; - case ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT: return "ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT"; - - case ESP_GAP_BLE_KEY_EVT: /* BLE key event for peer device keys */ + case ESP_GAP_BLE_KEY_EVT: /* BLE key event for peer device keys */ return "ESP_GAP_BLE_KEY_EVT"; - - case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ return "ESP_GAP_BLE_LOCAL_IR_EVT"; - - case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ return "ESP_GAP_BLE_LOCAL_ER_EVT"; - - case ESP_GAP_BLE_NC_REQ_EVT: /* Numeric Comparison request event */ + case ESP_GAP_BLE_NC_REQ_EVT: /* Numeric Comparison request event */ return "ESP_GAP_BLE_NC_REQ_EVT"; - - case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ + case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ return "ESP_GAP_BLE_OOB_REQ_EVT"; - - case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: /* passkey notification event */ + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: /* passkey notification event */ return "ESP_GAP_BLE_PASSKEY_NOTIF_EVT"; - - case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ return "ESP_GAP_BLE_PASSKEY_REQ_EVT"; - case ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT: return "ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT"; - case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: return "ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: return "ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_RESULT_EVT: return "ESP_GAP_BLE_SCAN_RESULT_EVT"; - case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: return "ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: return "ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: return "ESP_GAP_BLE_SCAN_START_COMPLETE_EVT"; - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: return "ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT"; - - case ESP_GAP_BLE_SEC_REQ_EVT: /* BLE security request */ + case ESP_GAP_BLE_SEC_REQ_EVT: /* BLE security request */ return "ESP_GAP_BLE_SEC_REQ_EVT"; - case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: return "ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT"; - case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT: return "ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT"; - case ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT: return "ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT"; - case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: return "ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT"; - - default: - ESP_LOGD(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType); + ESP_LOGV(LOG_TAG, "gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType); return "Unknown event type"; } } // gapEventToString std::string BLEUtils::gattCharacteristicUUIDToString(uint32_t characteristicUUID) { - const characteristicMap_t *p = g_characteristicsMappings; + const characteristicMap_t* p = g_characteristicsMappings; while (strlen(p->name) > 0) { if (p->assignedNumber == characteristicUUID) { return std::string(p->name); @@ -1982,7 +1821,7 @@ std::string BLEUtils::gattCharacteristicUUIDToString(uint32_t characteristicUUID * @return The string representation of a descriptor UUID. */ std::string BLEUtils::gattDescriptorUUIDToString(uint32_t descriptorUUID) { - gattdescriptor_t* p = (gattdescriptor_t *)g_descriptor_ids; + gattdescriptor_t* p = (gattdescriptor_t*) g_descriptor_ids; while (strlen(p->name) > 0) { if (p->assignedNumber == descriptorUUID) { return std::string(p->name); @@ -2018,7 +1857,7 @@ std::string BLEUtils::gattServiceIdToString(esp_gatt_srvc_id_t srvcId) { std::string BLEUtils::gattServiceToString(uint32_t serviceId) { - gattService_t* p = (gattService_t *)g_gattServices; + gattService_t* p = (gattService_t*) g_gattServices; while (strlen(p->name) > 0) { if (p->assignedNumber == serviceId) { return std::string(p->name); @@ -2036,7 +1875,7 @@ std::string BLEUtils::gattServiceToString(uint32_t serviceId) { * @return A string representation of the status. */ std::string BLEUtils::gattStatusToString(esp_gatt_status_t status) { - switch(status) { + switch (status) { case ESP_GATT_OK: return "ESP_GATT_OK"; case ESP_GATT_INVALID_HANDLE: @@ -2131,11 +1970,11 @@ std::string BLEUtils::gattStatusToString(esp_gatt_status_t status) { std::string BLEUtils::getMember(uint32_t memberId) { - member_t* p = (member_t *)members_ids; + member_t* p = (member_t*) members_ids; while (strlen(p->name) > 0) { if (p->assignedNumber == memberId) { - return std::string(p->name); + return std::string(p->name); } p++; } @@ -2148,7 +1987,7 @@ std::string BLEUtils::getMember(uint32_t memberId) { * @return The search event type as a string. */ const char* BLEUtils::searchEventTypeToString(esp_gap_search_evt_t searchEvt) { - switch(searchEvt) { + switch (searchEvt) { case ESP_GAP_SEARCH_INQ_RES_EVT: return "ESP_GAP_SEARCH_INQ_RES_EVT"; case ESP_GAP_SEARCH_INQ_CMPL_EVT: @@ -2164,7 +2003,7 @@ const char* BLEUtils::searchEventTypeToString(esp_gap_search_evt_t searchEvt) { case ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT: return "ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT"; default: - ESP_LOGD(LOG_TAG, "Unknown event type: 0x%x", searchEvt); + ESP_LOGV(LOG_TAG, "Unknown event type: 0x%x", searchEvt); return "Unknown event type"; } } // searchEventTypeToString diff --git a/cpp_utils/BLEUtils.h b/cpp_utils/BLEUtils.h index b2baee53..7981691c 100644 --- a/cpp_utils/BLEUtils.h +++ b/cpp_utils/BLEUtils.h @@ -23,12 +23,12 @@ class BLEUtils { static const char* addressTypeToString(esp_ble_addr_type_t type); static std::string adFlagsToString(uint8_t adFlags); static const char* advTypeToString(uint8_t advType); - static esp_gatt_id_t buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id=0); - static esp_gatt_srvc_id_t buildGattSrvcId(esp_gatt_id_t gattId, bool is_primary=true); static char* buildHexData(uint8_t* target, uint8_t* source, uint8_t length); static std::string buildPrintData(uint8_t* source, size_t length); static std::string characteristicPropertiesToString(esp_gatt_char_prop_t prop); static const char* devTypeToString(esp_bt_dev_type_t type); + static esp_gatt_id_t buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id = 0); + static esp_gatt_srvc_id_t buildGattSrvcId(esp_gatt_id_t gattId, bool is_primary = true); static void dumpGapEvent( esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param); @@ -47,7 +47,7 @@ class BLEUtils { static std::string gattCharacteristicUUIDToString(uint32_t characteristicUUID); static std::string gattClientEventTypeToString(esp_gattc_cb_event_t eventType); static std::string gattCloseReasonToString(esp_gatt_conn_reason_t reason); - static std::string gattcServiceElementToString(esp_gattc_service_elem_t *pGATTCServiceElement); + static std::string gattcServiceElementToString(esp_gattc_service_elem_t* pGATTCServiceElement); static std::string gattDescriptorUUIDToString(uint32_t descriptorUUID); static std::string gattServerEventTypeToString(esp_gatts_cb_event_t eventType); static std::string gattServiceIdToString(esp_gatt_srvc_id_t srvcId); diff --git a/cpp_utils/BLEValue.cpp b/cpp_utils/BLEValue.cpp index 49818e27..ec1e61f5 100644 --- a/cpp_utils/BLEValue.cpp +++ b/cpp_utils/BLEValue.cpp @@ -6,15 +6,17 @@ */ #include "sdkconfig.h" #if defined(CONFIG_BT_ENABLED) - -#include - #include "BLEValue.h" -#ifdef ARDUINO_ARCH_ESP32 + +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) #include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" +static const char* LOG_TAG="BLEValue"; #endif -static const char* LOG_TAG="BLEValue"; + BLEValue::BLEValue() { m_accumulation = ""; @@ -42,7 +44,7 @@ void BLEValue::addPart(std::string part) { */ void BLEValue::addPart(uint8_t* pData, size_t length) { ESP_LOGD(LOG_TAG, ">> addPart: length=%d", length); - m_accumulation += std::string((char *)pData, length); + m_accumulation += std::string((char*) pData, length); } // addPart @@ -65,9 +67,7 @@ void BLEValue::cancel() { void BLEValue::commit() { ESP_LOGD(LOG_TAG, ">> commit"); // If there is nothing to commit, do nothing. - if (m_accumulation.length() == 0) { - return; - } + if (m_accumulation.length() == 0) return; setValue(m_accumulation); m_accumulation = ""; m_readOffset = 0; @@ -79,7 +79,7 @@ void BLEValue::commit() { * @return A pointer to the data. */ uint8_t* BLEValue::getData() { - return (uint8_t*)m_value.data(); + return (uint8_t*) m_value.data(); } @@ -132,11 +132,8 @@ void BLEValue::setValue(std::string value) { * @param [in] The length of the new current value. */ void BLEValue::setValue(uint8_t* pData, size_t length) { - m_value = std::string((char*)pData, length); + m_value = std::string((char*) pData, length); } // setValue - - - #endif // CONFIG_BT_ENABLED diff --git a/cpp_utils/BLEValue.h b/cpp_utils/BLEValue.h index 92a7f9a4..5df904c1 100644 --- a/cpp_utils/BLEValue.h +++ b/cpp_utils/BLEValue.h @@ -17,13 +17,13 @@ class BLEValue { public: BLEValue(); - void addPart(std::string part); - void addPart(uint8_t* pData, size_t length); - void cancel(); - void commit(); - uint8_t* getData(); - size_t getLength(); - uint16_t getReadOffset(); + void addPart(std::string part); + void addPart(uint8_t* pData, size_t length); + void cancel(); + void commit(); + uint8_t* getData(); + size_t getLength(); + uint16_t getReadOffset(); std::string getValue(); void setReadOffset(uint16_t readOffset); void setValue(std::string value); @@ -33,6 +33,7 @@ class BLEValue { std::string m_accumulation; uint16_t m_readOffset; std::string m_value; + }; #endif // CONFIG_BT_ENABLED #endif /* COMPONENTS_CPP_UTILS_BLEVALUE_H_ */ diff --git a/cpp_utils/BLEXML/Characteristics/code/run.sh b/cpp_utils/BLEXML/Characteristics/code/run.sh index 77f193fe..f0c7930a 100755 --- a/cpp_utils/BLEXML/Characteristics/code/run.sh +++ b/cpp_utils/BLEXML/Characteristics/code/run.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash BASE_URL="https://www.bluetooth.com/api/gatt/XmlFile?xmlFileName=" RESULT=characteristics.json COUNT=0 @@ -17,4 +17,4 @@ do COUNT=$(expr ${COUNT} + 1) done echo -e "\n]\n" >> ${RESULT} -echo "done" \ No newline at end of file +echo "done" diff --git a/cpp_utils/BLEXML/Services/code/run.sh b/cpp_utils/BLEXML/Services/code/run.sh index bfa084d0..6716a53a 100755 --- a/cpp_utils/BLEXML/Services/code/run.sh +++ b/cpp_utils/BLEXML/Services/code/run.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash BASE_URL="https://www.bluetooth.com/api/gatt/XmlFile?xmlFileName=" RESULT=services.json COUNT=0 @@ -17,4 +17,4 @@ do COUNT=$(expr ${COUNT} + 1) done echo -e "\n]\n" >> ${RESULT} -echo "done" \ No newline at end of file +echo "done" diff --git a/cpp_utils/CMakeLists.txt b/cpp_utils/CMakeLists.txt new file mode 100644 index 00000000..cb9b7267 --- /dev/null +++ b/cpp_utils/CMakeLists.txt @@ -0,0 +1,20 @@ +# Edit following two lines to set component requirements (see docs) +set(COMPONENT_REQUIRES + "console" + "fatfs" + "json" + "mdns" + "nvs_flash" +) +set(COMPONENT_PRIV_REQUIRES ) + +file(GLOB COMPONENT_SRCS + LIST_DIRECTORIES false + "*.h" + "*.cpp" + "*.c" + "*.S" +) +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/cpp_utils/CPPNVS.cpp b/cpp_utils/CPPNVS.cpp index b204045b..18914ab5 100644 --- a/cpp_utils/CPPNVS.cpp +++ b/cpp_utils/CPPNVS.cpp @@ -85,7 +85,7 @@ int NVS::get(std::string key, std::string* result, bool isBlob) { return rc; } } - char *data = (char *)malloc(length); + char* data = (char*) malloc(length); if (isBlob) { ::nvs_get_blob(m_handle, key.c_str(), data, &length); } else { diff --git a/cpp_utils/CPPNVS.h b/cpp_utils/CPPNVS.h index 6afbc166..9155891b 100644 --- a/cpp_utils/CPPNVS.h +++ b/cpp_utils/CPPNVS.h @@ -21,15 +21,17 @@ class NVS { void erase(); void erase(std::string key); - int get(std::string key, std::string* result, bool isBlob=false); - int get(std::string key, uint8_t* result, size_t &length); + int get(std::string key, std::string* result, bool isBlob = false); + int get(std::string key, uint8_t* result, size_t& length); int get(std::string key, uint32_t& value); - void set(std::string key, std::string data, bool isBlob=false); + void set(std::string key, std::string data, bool isBlob = false); void set(std::string key, uint32_t value); void set(std::string key, uint8_t* data, size_t length); + private: std::string m_name; nvs_handle m_handle; + }; #endif /* COMPONENTS_CPP_UTILS_CPPNVS_H_ */ diff --git a/cpp_utils/Console.cpp b/cpp_utils/Console.cpp new file mode 100644 index 00000000..c0f5655f --- /dev/null +++ b/cpp_utils/Console.cpp @@ -0,0 +1,211 @@ +/* + * Console.cpp + * + * Created on: Jun 15, 2018 + * Author: kolban + */ + +/** + * Example: + * Argtable argtable; + * argtable.addString("myparam", "l", "list", "Get Listings"); + * argtable.parse(argc, argv); + * ArgTableEntry_String* pStr = (ArgTableEntry_String*)argTable.get("myparam"); + * pStr->getValue(); + */ +#include "Console.h" + +/** + * Argtable instance constructor. + */ +ArgTable::ArgTable() { + m_argtable = nullptr; + m_argEnd = nullptr; +} // ArgTable#ArgTable + + +/** + * Argtable instance destructor. + */ +ArgTable::~ArgTable() { + freeArgtable(); // Release any resources associated with the argtable. +} // ArgTable#~ArgTable + + +/** + * Build the ArgTable that will be used for parsing. + */ +/* private */ void ArgTable::build() { + /* + * The m_argTableEntries is a std::list that contains the argtable entries in the form of a std::pair. We + * allocate storage for the ArgTable and then populate it. The last entry of the argtable must be an end marker. + */ + int size = m_argTableEntries.size(); + m_argtable = new void*[size + 1]; + int i = 0; + for (auto it = m_argTableEntries.begin(); it != m_argTableEntries.end(); ++it) { + m_argtable[i] = it->second->getEntry(); + i++; + } + m_argEnd = arg_end(10); + m_argtable[i] = m_argEnd; +} // ArgTable#build + + +ArgTableEntry_Date ArgTable::addDate(std::string name, std::string shortopts, std::string longopts, std::string glossary) { + ArgTableEntry_Date* pDate = new ArgTableEntry_Date(shortopts, longopts, glossary); + m_argTableEntries.push_back(std::make_pair(name, pDate)); + return *pDate; +} // ArgTable#addDate + + +ArgTableEntry_Double ArgTable::addDouble(std::string name, std::string shortopts, std::string longopts, std::string glossary) { + ArgTableEntry_Double* pDouble = new ArgTableEntry_Double(shortopts, longopts, glossary); + m_argTableEntries.push_back(std::make_pair(name, pDouble)); + return *pDouble; +} // ArgTable#addDouble + + +ArgTableEntry_File ArgTable::addFile(std::string name, std::string shortopts, std::string longopts, std::string glossary) { + ArgTableEntry_File* pFile = new ArgTableEntry_File(shortopts, longopts, glossary); + m_argTableEntries.push_back(std::make_pair(name, pFile)); + return *pFile; +} // ArgTable#addFile + + +ArgTableEntry_Int ArgTable::addInt(std::string name, std::string shortopts, std::string longopts, std::string glossary) { + ArgTableEntry_Int* pInt = new ArgTableEntry_Int(shortopts, longopts, glossary); + m_argTableEntries.push_back(std::make_pair(name, pInt)); + return *pInt; +} // ArgTable#addInt + + +ArgTableEntry_Lit ArgTable::addLit(std::string name, std::string shortopts, std::string longopts, std::string glossary) { + ArgTableEntry_Lit* pLit = new ArgTableEntry_Lit(shortopts, longopts, glossary); + m_argTableEntries.push_back(std::make_pair(name, pLit)); + return *pLit; +} // ArgTable#addLit + + +ArgTableEntry_String ArgTable::addString(std::string name, std::string shortopts, std::string longopts, std::string glossary, int min, int max) { + ArgTableEntry_String* pStr = new ArgTableEntry_String(shortopts, longopts, glossary, min, max); + m_argTableEntries.push_back(std::make_pair(name, pStr)); + return *pStr; +} // ArgTable#addString + + +/** + * Parse the input and output parameters against this argtable. + * @param argc A count of the number of parameters. + * @param argv An array of string parameters. + * @return The number of errors detected. + */ +int ArgTable::parse(int argc, char* argv[]) { + if (m_argtable == nullptr) { // If we don't have an argtable, build it. + build(); + } + int nErrors = arg_parse(argc, argv, m_argtable); + return nErrors; +} // ArgTable#parse + + +/** + * Print any errors associated with the parsing. + */ +void ArgTable::printErrors(FILE* fp, std::string progName) { + if (m_argEnd != nullptr) { + arg_print_errors(fp, m_argEnd, progName.c_str()); + } +} // ArgTable#printErrors + + +/** + * Release the argtable data. + */ +/* private */void ArgTable::freeArgtable() { + if (m_argtable != nullptr) { + arg_free(m_argtable); + m_argtable = nullptr; + m_argEnd = nullptr; + } +} // ArgTable#freeArgtable + + +ArgTableEntry_Date::ArgTableEntry_Date(std::string shortopts, std::string longopts, std::string glossary) { + m_argDate = arg_daten(shortopts.c_str(), longopts.c_str(), "", "", 0, 1, glossary.c_str()); + m_type = ArgType_t::DATE; +} // ArgTableEntry_Date#ArgTableEntry_Date + + +int ArgTableEntry_Date::getCount() { + return m_argDate->count; +} // ArgTableEntry_Date#getCount + + +ArgTableEntry_Double::ArgTableEntry_Double(std::string shortopts, std::string longopts, std::string glossary) { + m_argDbl = arg_dbln(shortopts.c_str(), longopts.c_str(), "", 0, 1, glossary.c_str()); + m_type = ArgType_t::DBL; +} + + +int ArgTableEntry_Double::getCount() { + return m_argDbl->count; +} + + +ArgTableEntry_File::ArgTableEntry_File(std::string shortopts, std::string longopts, std::string glossary) { + m_argFile = arg_filen(shortopts.c_str(), longopts.c_str(), "", 0, 1, glossary.c_str()); + m_type = ArgType_t::FILE; +} + + +int ArgTableEntry_File::getCount() { + return m_argFile->count; +} + + +ArgTableEntry_Int::ArgTableEntry_Int(std::string shortopts, std::string longopts, std::string glossary) { + m_argInt = arg_intn(shortopts.c_str(), longopts.c_str(), "", 0, 1, glossary.c_str()); + m_type = ArgType_t::INT; +} + + +int ArgTableEntry_Int::getCount() { + return m_argInt->count; +} + + +ArgTableEntry_Lit::ArgTableEntry_Lit(std::string shortopts, std::string longopts, std::string glossary) { + m_argLit = arg_litn(shortopts.c_str(), longopts.c_str(), 0, 1, glossary.c_str()); + m_type = ArgType_t::LIT; +} + + +int ArgTableEntry_Lit::getCount() { + return m_argLit->count; +} + + +int ArgTableEntry_Regex::getCount() { + return m_argRex->count; +} + + +ArgTableEntry_String::ArgTableEntry_String(std::string shortopts, std::string longopts, std::string glossary, int min, int max) { + m_argStr = arg_strn(shortopts.c_str(), longopts.c_str(), "", min, max, glossary.c_str()); + m_type = ArgType_t::STR; +} + + +int ArgTableEntry_String::getCount() { + return m_argStr->count; +} + + +Console::Console() { +} + + +Console::~Console() { +} + diff --git a/cpp_utils/Console.h b/cpp_utils/Console.h new file mode 100644 index 00000000..a94f63a1 --- /dev/null +++ b/cpp_utils/Console.h @@ -0,0 +1,149 @@ +/* + * Console.h + * + * Created on: Jun 15, 2018 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_CONSOLE_H_ +#define COMPONENTS_CPP_UTILS_CONSOLE_H_ + +#include +#include +#include +#include + +class Console { +public: + Console(); + virtual ~Console(); +}; + + +enum class ArgType_t { LIT, INT, DBL, STR, REX, FILE, DATE }; + + +class ArgTableEntry_Generic { +protected: + ArgType_t m_type; +public: + virtual int getCount(); + bool hasValue() { + return getCount() > 0; + } + virtual void* getEntry() = 0; +}; + + +class ArgTableEntry_Lit : public ArgTableEntry_Generic { +private: + struct arg_lit* m_argLit; +public: + int getCount(); + ArgTableEntry_Lit(std::string shortopts, std::string longopts, std::string glossary); + void* getEntry() { + return m_argLit; + } +}; + +class ArgTableEntry_Int : public ArgTableEntry_Generic { +private: + struct arg_int* m_argInt; +public: + ArgTableEntry_Int(std::string shortopts, std::string longopts, std::string glossary); + int getCount(); + int getValue(int index = 0); + void* getEntry() { + return m_argInt; + } +}; + + +class ArgTableEntry_Double : public ArgTableEntry_Generic { +private: + struct arg_dbl* m_argDbl; +public: + ArgTableEntry_Double(std::string shortopts, std::string longopts, std::string glossary); + int getCount(); + double getValue(int index = 0); + void* getEntry() { + return m_argDbl; + } +}; + + +class ArgTableEntry_String : public ArgTableEntry_Generic { +private: + struct arg_str* m_argStr; +public: + ArgTableEntry_String(std::string shortopts, std::string longopts, std::string glossary, int min, int max); + int getCount(); + std::string getValue(int index = 0); + void* getEntry() { + return m_argStr; + } +}; + + +class ArgTableEntry_Regex : public ArgTableEntry_Generic { +private: + struct arg_rex* m_argRex; +public: + int getCount(); + std::string getValue(int index = 0); + void* getEntry() { + return m_argRex; + } +}; + + +class ArgTableEntry_File : public ArgTableEntry_Generic { +private: + struct arg_file* m_argFile; +public: + ArgTableEntry_File(std::string shortopts, std::string longopts, std::string glossary); + int getCount(); + std::string getFilename(int index = 0); + std::string getBasename(int index = 0); + std::string getExtension(int index = 0); + void* getEntry() { + return m_argFile; + } +}; + + +class ArgTableEntry_Date : public ArgTableEntry_Generic { +private: + struct arg_date* m_argDate; +public: + ArgTableEntry_Date(std::string shortopts, std::string longopts, std::string glossary); + int getCount(); + struct tm* getValue(int index = 0); + void* getEntry() { + return m_argDate; + } +}; + + +class ArgTable { +private: + void** m_argtable; + struct arg_end* m_argEnd; + std::list> m_argTableEntries; + void build(); + void freeArgtable(); + +public: + ArgTable(); + ~ArgTable(); + ArgTableEntry_Date addDate(std::string name, std::string shortopts, std::string longopts, std::string glossary); + ArgTableEntry_Double addDouble(std::string name, std::string shortopts, std::string longopts, std::string glossary); + ArgTableEntry_File addFile(std::string name, std::string shortopts, std::string longopts, std::string glossary); + ArgTableEntry_Int addInt(std::string name, std::string shortopts, std::string longopts, std::string glossary); + ArgTableEntry_Lit addLit(std::string name, std::string shortopts, std::string longopts, std::string glossary); + ArgTableEntry_String addString(std::string name, std::string shortopts, std::string longopts, std::string glossary, int min, int max); + int parse(int argc, char* argv[]); + void printErrors(FILE* fp, std::string progName=""); +}; + +#endif /* COMPONENTS_CPP_UTILS_CONSOLE_H_ */ diff --git a/cpp_utils/FTPCallbacks.cpp b/cpp_utils/FTPCallbacks.cpp index d88c2300..69e462c9 100644 --- a/cpp_utils/FTPCallbacks.cpp +++ b/cpp_utils/FTPCallbacks.cpp @@ -24,7 +24,7 @@ void FTPFileCallbacks::onStoreStart(std::string fileName) { */ size_t FTPFileCallbacks::onStoreData(uint8_t* data, size_t size) { ESP_LOGD(LOG_TAG,">> FTPFileCallbacks::onStoreData: size=%d", size); - m_storeFile.write((char *)data, size); // Store data received. + m_storeFile.write((char*) data, size); // Store data received. ESP_LOGD(LOG_TAG,"<< FTPFileCallbacks::onStoreData: size=%d", size); return size; } // FTPFileCallbacks#onStoreData @@ -65,7 +65,7 @@ void FTPFileCallbacks::onRetrieveStart(std::string fileName) { */ size_t FTPFileCallbacks::onRetrieveData(uint8_t* data, size_t size) { ESP_LOGD(LOG_TAG,">> FTPFileCallbacks::onRetrieveData"); - m_retrieveFile.read((char *)data, size); + m_retrieveFile.read((char*) data, size); size_t readSize = m_retrieveFile.gcount(); m_byteCount += readSize; ESP_LOGD(LOG_TAG,"<< FTPFileCallbacks::onRetrieveData: sizeRead=%d", readSize); @@ -88,14 +88,11 @@ void FTPFileCallbacks::onRetrieveEnd() { * @return a list of files in the file system. */ std::string FTPFileCallbacks::onDir() { - DIR* dir = opendir(FTPServer::getCurrentDirectory().c_str()); std::stringstream ss; - while(1) { + while (true) { struct dirent* pDirentry = readdir(dir); - if (pDirentry == nullptr) { - break; - } + if (pDirentry == nullptr) break; ss << pDirentry->d_name << "\r\n"; } closedir(dir); @@ -131,7 +128,7 @@ void FTPCallbacks::onRetrieveStart(std::string fileName) { } // FTPCallbacks#onRetrieveStart -size_t FTPCallbacks::onRetrieveData(uint8_t *data, size_t size) { +size_t FTPCallbacks::onRetrieveData(uint8_t* data, size_t size) { ESP_LOGD(LOG_TAG,">> FTPCallbacks::onRetrieveData"); ESP_LOGD(LOG_TAG,"<< FTPCallbacks::onRetrieveData: 0"); return 0; diff --git a/cpp_utils/FTPServer.cpp b/cpp_utils/FTPServer.cpp index f8d006fd..63cf6a9c 100644 --- a/cpp_utils/FTPServer.cpp +++ b/cpp_utils/FTPServer.cpp @@ -22,24 +22,24 @@ static const char* LOG_TAG = "FTPServer"; // trim from start (in place) static void ltrim(std::string &s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { - return !std::isspace(ch); - })); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { + return !std::isspace(ch); + })); } // ltrim // trim from end (in place) static void rtrim(std::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { - return !std::isspace(ch); - }).base(), s.end()); + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { + return !std::isspace(ch); + }).base(), s.end()); } // rtrim // trim from both ends (in place) static void trim(std::string &s) { - ltrim(s); - rtrim(s); + ltrim(s); + rtrim(s); } // trim @@ -128,13 +128,13 @@ std::string FTPServer::listenPassive() { struct sockaddr_in clientAddrInfo; unsigned int addrInfoSize = sizeof(clientAddrInfo); - getsockname(m_clientSocket, (struct sockaddr*)&clientAddrInfo, &addrInfoSize); + getsockname(m_clientSocket, (struct sockaddr*) &clientAddrInfo, &addrInfoSize); struct sockaddr_in serverAddress; serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(0); - int rc = bind(m_passiveSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)); + int rc = bind(m_passiveSocket, (struct sockaddr*) &serverAddress, sizeof(serverAddress)); if (rc == -1) { ESP_LOGD(LOG_TAG, "bind: %s", strerror(errno)); } @@ -150,10 +150,9 @@ std::string FTPServer::listenPassive() { ESP_LOGD(LOG_TAG, "getsockname: %s", strerror(errno)); } - std::stringstream ss; - ss << ((clientAddrInfo.sin_addr.s_addr >> 0) & 0xff) << - "," << ((clientAddrInfo.sin_addr.s_addr >> 8) & 0xff) << + ss << ((clientAddrInfo.sin_addr.s_addr >> 0) & 0xff) << + "," << ((clientAddrInfo.sin_addr.s_addr >> 8) & 0xff) << "," << ((clientAddrInfo.sin_addr.s_addr >> 16) & 0xff) << "," << ((clientAddrInfo.sin_addr.s_addr >> 24) & 0xff) << "," << ((serverAddress.sin_port >> 0) & 0xff) << @@ -203,7 +202,7 @@ void FTPServer::onList(std::istringstream& ss) { sendResponse(FTPServer::RESPONSE_150_ABOUT_TO_OPEN_DATA_CONNECTION); // File status okay; about to open data connection. if (m_callbacks != nullptr) { std::string dirString = m_callbacks->onDir(); - sendData((uint8_t *)dirString.data(), dirString.length()); + sendData((uint8_t*) dirString.data(), dirString.length()); } closeData(); sendResponse(FTPServer::RESPONSE_226_CLOSING_DATA_CONNECTION); // Closing data connection. @@ -211,7 +210,7 @@ void FTPServer::onList(std::istringstream& ss) { } // FTPServer#onList -void FTPServer::onMkd(std::istringstream &ss) { +void FTPServer::onMkd(std::istringstream& ss) { std::string path; ss >> path; ESP_LOGD(LOG_TAG, ">> onMkd: path=%s", path.c_str()); @@ -247,9 +246,9 @@ void FTPServer::onPort(std::istringstream& ss) { char c; uint16_t h1, h2, h3, h4, p1, p2; ss >> h1 >> c >> h2 >> c >> h3 >> c >> h4 >> c >> p1 >> c >> p2; - m_dataPort = p1*256 + p2; + m_dataPort = p1 * 256 + p2; ESP_LOGD(LOG_TAG, "%d.%d.%d.%d %d", h1, h2, h3, h4, m_dataPort); - m_dataIp = h1<<24 | h2<<16 | h3<<8 | h4; + m_dataIp = h1 << 24 | h2 << 16 | h3 << 8 | h4; sendResponse(RESPONSE_200_COMMAND_OK); // Command okay. m_isPassive = false; @@ -351,7 +350,6 @@ void FTPServer::onQuit(std::istringstream& ss) { * @param ss The parameter stream. */ void FTPServer::onRetr(std::istringstream& ss) { - // We open a data connection back to the client. We then invoke the callback to indicate that we have // started a retrieve operation. We call the retrieve callback to request the next chunk of data and // transmit this down the data connection. We repeat this until there is no more data to send at which @@ -362,12 +360,11 @@ void FTPServer::onRetr(std::istringstream& ss) { ss >> fileName; uint8_t data[m_chunkSize]; - if (m_callbacks != nullptr) { try { m_callbacks->onRetrieveStart(fileName); - } catch(FTPServer::FileException& e) { - sendResponse(FTPServer::RESPONSE_550_ACTION_NOT_TAKEN); // Requested action not taken. + } catch (FTPServer::FileException& e) { + sendResponse(FTPServer::RESPONSE_550_ACTION_NOT_TAKEN); // Requested action not taken. ESP_LOGD(LOG_TAG, "<< onRetr: Returned 550 to client."); return; } @@ -377,7 +374,7 @@ void FTPServer::onRetr(std::istringstream& ss) { openData(); if (m_callbacks != nullptr) { int readSize = m_callbacks->onRetrieveData(data, m_chunkSize); - while(readSize > 0) { + while (readSize > 0) { sendData(data, readSize); readSize = m_callbacks->onRetrieveData(data, m_chunkSize); } @@ -432,11 +429,7 @@ void FTPServer::onType(std::istringstream& ss) { ESP_LOGD(LOG_TAG, ">> onType"); std::string type; ss >> type; - if (type.compare("I") == 0) { - m_isImage = true; - } else { - m_isImage = false; - } + m_isImage = (type.compare("I") == 0); sendResponse(FTPServer::RESPONSE_200_COMMAND_OK); // Command okay. ESP_LOGD(LOG_TAG, "<< onType: isImage=%d", m_isImage); } // FTPServer#onType @@ -455,15 +448,10 @@ void FTPServer::onType(std::istringstream& ss) { void FTPServer::onUser(std::istringstream& ss) { // When we receive a user command, we next want to know if we should ask for a password. If the m_loginRequired // flag is set then we do indeed want a password and will send the response that we wish one. - std::string userName; ss >> userName; ESP_LOGD(LOG_TAG, ">> onUser: userName=%s", userName.c_str()); - if (m_loginRequired) { - sendResponse(FTPServer::RESPONSE_331_PASSWORD_REQUIRED); - } else { - sendResponse(FTPServer::RESPONSE_200_COMMAND_OK); // Command okay. - } + sendResponse(m_loginRequired ? FTPServer::RESPONSE_331_PASSWORD_REQUIRED : FTPServer::RESPONSE_200_COMMAND_OK); m_suppliedUserid = userName; // Save the username that was supplied. ESP_LOGD(LOG_TAG, "<< onUser"); } // FTPServer#onUser @@ -500,7 +488,7 @@ bool FTPServer::openData() { return false; } closePassive(); - } else { + } else { // Handle an active connection ... here we connect to the client. m_dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -526,24 +514,20 @@ void FTPServer::processCommand() { sendResponse(FTPServer::RESPONSE_220_SERVICE_READY); // Service ready. ESP_LOGD(LOG_TAG, ">> FTPServer::processCommand"); m_lastCommand = ""; - while(1) { + while (true) { std::string line = ""; char currentChar; char lastChar = '\0'; int rc = recv(m_clientSocket, ¤tChar, 1, 0); - while(rc != -1 && rc!=0) { + while (rc != -1 && rc != 0) { line += currentChar; - if (lastChar == '\r' && currentChar == '\n') { - break; - } - //printf("%c\n", currentChar); + if (lastChar == '\r' && currentChar == '\n') break; +// printf("%c\n", currentChar); lastChar = currentChar; rc = recv(m_clientSocket, ¤tChar, 1, 0); } // End while we are waiting for a line. - if (rc == 0 || rc == -1) { // If we didn't get a line or an error, then we have finished processing commands. - break; - } + if (rc == 0 || rc == -1) break; // If we didn't get a line or an error, then we have finished processing commands. std::string command; std::istringstream ss(line); @@ -553,58 +537,58 @@ void FTPServer::processCommand() { // We now have a command to process. ESP_LOGD(LOG_TAG, "Command: \"%s\"", command.c_str()); - if (command.compare("USER")==0) { + if (command.compare("USER") == 0) { onUser(ss); } - else if (command.compare("PASS")==0) { + else if (command.compare("PASS") == 0) { onPass(ss); } else if (m_loginRequired && !m_isAuthenticated) { sendResponse(RESPONSE_530_NOT_LOGGED_IN); } - else if (command.compare("PASV")==0) { + else if (command.compare("PASV") == 0) { onPasv(ss); } - else if (command.compare("SYST")==0) { + else if (command.compare("SYST") == 0) { onSyst(ss); } - else if (command.compare("PORT")==0) { + else if (command.compare("PORT") == 0) { onPort(ss); } - else if (command.compare("LIST")==0) { + else if (command.compare("LIST") == 0) { onList(ss); } - else if (command.compare("TYPE")==0) { + else if (command.compare("TYPE") == 0) { onType(ss); } - else if (command.compare("RETR")==0) { + else if (command.compare("RETR") == 0) { onRetr(ss); } - else if (command.compare("QUIT")==0) { + else if (command.compare("QUIT") == 0) { onQuit(ss); } - else if (command.compare("AUTH")==0) { + else if (command.compare("AUTH") == 0) { onAuth(ss); } - else if (command.compare("STOR")==0) { + else if (command.compare("STOR") == 0) { onStor(ss); } - else if (command.compare("PWD")==0) { + else if (command.compare("PWD") == 0) { onPWD(ss); } - else if (command.compare("MKD")==0) { + else if (command.compare("MKD") == 0) { onMkd(ss); } - else if (command.compare("XMKD")==0) { + else if (command.compare("XMKD") == 0) { onXmkd(ss); } - else if (command.compare("RMD")==0) { + else if (command.compare("RMD") == 0) { onRmd(ss); } - else if (command.compare("XRMD")==0) { + else if (command.compare("XRMD") == 0) { onXrmd(ss); } - else if (command.compare("CWD")==0) { + else if (command.compare("CWD") == 0) { onCwd(ss); } else { @@ -637,11 +621,9 @@ void FTPServer::receiveFile(std::string fileName) { sendResponse(FTPServer::RESPONSE_150_ABOUT_TO_OPEN_DATA_CONNECTION); // File status okay; about to open data connection. uint8_t buf[m_chunkSize]; uint32_t totalSizeRead = 0; - while(1) { + while (true) { int rc = recv(m_dataSocket, &buf, m_chunkSize, 0); - if (rc <= 0) { - break; - } + if (rc <= 0) break; if (m_callbacks != nullptr) { m_callbacks->onRetrieveData(buf, rc); } @@ -789,7 +771,7 @@ void FTPServer::start() { if (rc == -1) { ESP_LOGD(LOG_TAG, "listen: %s", strerror(errno)); } - while(1) { + while (true) { waitForFTPClient(); processCommand(); } @@ -804,7 +786,7 @@ int FTPServer::waitForFTPClient() { struct sockaddr_in clientAddress; socklen_t clientAddressLength = sizeof(clientAddress); - m_clientSocket = accept(m_serverSocket, (struct sockaddr *)&clientAddress, &clientAddressLength); + m_clientSocket = accept(m_serverSocket, (struct sockaddr*) &clientAddress, &clientAddressLength); char ipAddr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &clientAddress.sin_addr, ipAddr, sizeof(ipAddr)); @@ -812,7 +794,7 @@ int FTPServer::waitForFTPClient() { struct sockaddr_in socketAddressInfo; unsigned int socketAddressInfoSize = sizeof(socketAddressInfo); - getsockname(m_clientSocket, (struct sockaddr*)&socketAddressInfo, &socketAddressInfoSize); + getsockname(m_clientSocket, (struct sockaddr*) &socketAddressInfo, &socketAddressInfoSize); inet_ntop(AF_INET, &socketAddressInfo.sin_addr, ipAddr, sizeof(ipAddr)); ESP_LOGD(LOG_TAG, "Connected at %s [%d]", ipAddr, socketAddressInfo.sin_port); diff --git a/cpp_utils/FTPServer.h b/cpp_utils/FTPServer.h index 7dc56f13..5736201d 100644 --- a/cpp_utils/FTPServer.h +++ b/cpp_utils/FTPServer.h @@ -24,28 +24,63 @@ class FTPCallbacks { virtual void onRetrieveEnd(); virtual std::string onDir(); virtual ~FTPCallbacks(); + }; /** * An implementation of FTPCallbacks that uses Posix File I/O to perform file access. */ class FTPFileCallbacks : public FTPCallbacks { +public: + void onStoreStart(std::string fileName) override; // Called for a STOR request. + size_t onStoreData(uint8_t* data, size_t size) override; // Called when a chunk of STOR data becomes available. + void onStoreEnd() override; // Called at the end of a STOR request. + void onRetrieveStart(std::string fileName) override; // Called at the start of a RETR request. + size_t onRetrieveData(uint8_t* data, size_t size) override; // Called to retrieve a chunk of RETR data. + void onRetrieveEnd() override; // Called when we have retrieved all the data. + std::string onDir() override; // Called to retrieve all the directory entries. + private: - std::ofstream m_storeFile; // File used to store data from the client. + std::ofstream m_storeFile; // File used to store data from the client. std::ifstream m_retrieveFile; // File used to retrieve data for the client. - uint32_t m_byteCount; // Count of bytes sent over wire. -public: - void onStoreStart(std::string fileName) override; // Called for a STOR request. - size_t onStoreData(uint8_t* data, size_t size) override; // Called when a chunk of STOR data becomes available. - void onStoreEnd() override; // Called at the end of a STOR request. - void onRetrieveStart(std::string fileName) override; // Called at the start of a RETR request. - size_t onRetrieveData(uint8_t* data, size_t size) override; // Called to retrieve a chunk of RETR data. - void onRetrieveEnd() override; // Called when we have retrieved all the data. - std::string onDir() override; // Called to retrieve all the directory entries. + uint32_t m_byteCount; // Count of bytes sent over wire. + }; class FTPServer { +public: + FTPServer(); + virtual ~FTPServer(); + void setCredentials(std::string userid, std::string password); + void start(); + void setPort(uint16_t port); + void setCallbacks(FTPCallbacks* pFTPCallbacks); + static std::string getCurrentDirectory(); + class FileException: public std::exception { + }; + + // Response codes. + static const int RESPONSE_150_ABOUT_TO_OPEN_DATA_CONNECTION = 150; + static const int RESPONSE_200_COMMAND_OK = 200; + static const int RESPONSE_202_COMMAND_NOT_IMPLEMENTED = 202; + static const int RESPONSE_212_DIRECTORY_STATUS = 212; + static const int RESPONSE_213_FILE_STATUS = 213; + static const int RESPONSE_214_HELP_MESSAGE = 214; + static const int RESPONSE_220_SERVICE_READY = 220; + static const int RESPONSE_221_CLOSING_CONTROL_CONNECTION = 221; + static const int RESPONSE_230_USER_LOGGED_IN = 230; + static const int RESPONSE_226_CLOSING_DATA_CONNECTION = 226; + static const int RESPONSE_227_ENTERING_PASSIVE_MODE = 227; + static const int RESPONSE_331_PASSWORD_REQUIRED = 331; + static const int RESPONSE_332_NEED_ACCOUNT = 332; + static const int RESPONSE_500_COMMAND_UNRECOGNIZED = 500; + static const int RESPONSE_502_COMMAND_NOT_IMPLEMENTED = 502; + static const int RESPONSE_503_BAD_SEQUENCE = 503; + static const int RESPONSE_530_NOT_LOGGED_IN = 530; + static const int RESPONSE_550_ACTION_NOT_TAKEN = 550; + static const int RESPONSE_553_FILE_NAME_NOT_ALLOWED = 553; + private: int m_serverSocket; // The socket the FTP server is listening on. int m_clientSocket; // The current client socket. @@ -98,40 +133,6 @@ class FTPServer { int waitForFTPClient(); void processCommand(); -public: - FTPServer(); - virtual ~FTPServer(); - void setCredentials(std::string userid, std::string password); - void start(); - void setPort(uint16_t port); - void setCallbacks(FTPCallbacks* pFTPCallbacks); - static std::string getCurrentDirectory(); - class FileException: public std::exception { - - }; - - // Response codes. - static const int RESPONSE_150_ABOUT_TO_OPEN_DATA_CONNECTION = 150; - static const int RESPONSE_200_COMMAND_OK = 200; - static const int RESPONSE_202_COMMAND_NOT_IMPLEMENTED = 202; - static const int RESPONSE_212_DIRECTORY_STATUS = 212; - static const int RESPONSE_213_FILE_STATUS = 213; - static const int RESPONSE_214_HELP_MESSAGE = 214; - static const int RESPONSE_220_SERVICE_READY = 220; - static const int RESPONSE_221_CLOSING_CONTROL_CONNECTION = 221; - static const int RESPONSE_230_USER_LOGGED_IN = 230; - static const int RESPONSE_226_CLOSING_DATA_CONNECTION = 226; - static const int RESPONSE_227_ENTERING_PASSIVE_MODE = 227; - static const int RESPONSE_331_PASSWORD_REQUIRED = 331; - static const int RESPONSE_332_NEED_ACCOUNT = 332; - static const int RESPONSE_500_COMMAND_UNRECOGNIZED = 500; - static const int RESPONSE_502_COMMAND_NOT_IMPLEMENTED = 502; - static const int RESPONSE_503_BAD_SEQUENCE = 503; - static const int RESPONSE_530_NOT_LOGGED_IN = 530; - static const int RESPONSE_550_ACTION_NOT_TAKEN = 550; - static const int RESPONSE_553_FILE_NAME_NOT_ALLOWED = 553; }; - - #endif /* NETWORKING_FTPSERVER_FTPSERVER_H_ */ diff --git a/cpp_utils/File.cpp b/cpp_utils/File.cpp index 670936aa..3ac4672f 100644 --- a/cpp_utils/File.cpp +++ b/cpp_utils/File.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include "GeneralUtils.h" static const char* LOG_TAG = "File"; /** @@ -33,15 +33,13 @@ File::File(std::string path, uint8_t type) { std::string File::getContent(bool base64Encode) { uint32_t size = length(); ESP_LOGD(LOG_TAG, "File:: getContent(), path=%s, length=%d", m_path.c_str(), size); - if (size == 0) { - return ""; - } - uint8_t *pData = (uint8_t *)malloc(size); + if (size == 0) return ""; + uint8_t* pData = (uint8_t*) malloc(size); if (pData == nullptr) { ESP_LOGE(LOG_TAG, "getContent: Failed to allocate memory"); return ""; } - FILE *file = fopen(m_path.c_str(), "r"); + FILE* file = fopen(m_path.c_str(), "r"); fread(pData, size, 1, file); fclose(file); std::string ret((char *)pData, size); @@ -65,19 +63,17 @@ std::string File::getContent(uint32_t offset, uint32_t readSize) { uint32_t fileSize = length(); ESP_LOGD(LOG_TAG, "File:: getContent(), name=%s, fileSize=%d, offset=%d, readSize=%d", m_path.c_str(), fileSize, offset, readSize); - if (fileSize == 0 || offset > fileSize) { - return ""; - } - uint8_t *pData = (uint8_t *)malloc(readSize); + if (fileSize == 0 || offset > fileSize) return ""; + uint8_t* pData = (uint8_t*) malloc(readSize); if (pData == nullptr) { ESP_LOGE(LOG_TAG, "getContent: Failed to allocate memory"); return ""; } - FILE *file = fopen(m_path.c_str(), "r"); + FILE* file = fopen(m_path.c_str(), "r"); fseek(file, offset, SEEK_SET); size_t bytesRead = fread(pData, 1, readSize, file); fclose(file); - std::string ret((char *)pData, bytesRead); + std::string ret((char*) pData, bytesRead); free(pData); return ret; } // getContent @@ -92,10 +88,8 @@ std::string File::getPath() { */ std::string File::getName() { size_t pos = m_path.find_last_of('/'); - if (pos == std::string::npos) { - return m_path; - } - return m_path.substr(pos+1); + if (pos == std::string::npos) return m_path; + return m_path.substr(pos + 1); } // getName @@ -116,10 +110,8 @@ uint8_t File::getType() { uint32_t File::length() { struct stat buf; int rc = stat(m_path.c_str(), &buf); - if (rc != 0 || S_ISDIR(buf.st_mode)) { - return 0; - } - return buf.st_size; + if (rc != 0 || S_ISDIR(buf.st_mode)) return 0; + return (uint32_t) buf.st_size; } // length @@ -130,8 +122,6 @@ uint32_t File::length() { bool File::isDirectory() { struct stat buf; int rc = stat(m_path.c_str(), &buf); - if (rc != 0) { - return false; - } + if (rc != 0) return false; return S_ISDIR(buf.st_mode); } // isDirectory diff --git a/cpp_utils/File.h b/cpp_utils/File.h index 19ef7c34..c1c18014 100644 --- a/cpp_utils/File.h +++ b/cpp_utils/File.h @@ -17,7 +17,7 @@ class File { public: File(std::string name, uint8_t type = DT_UNKNOWN); - std::string getContent(bool base64Encode=false); + std::string getContent(bool base64Encode = false); std::string getContent(uint32_t offset, uint32_t size); std::string getName(); std::string getPath(); diff --git a/cpp_utils/FileSystem.cpp b/cpp_utils/FileSystem.cpp index 564c68b4..1920235c 100644 --- a/cpp_utils/FileSystem.cpp +++ b/cpp_utils/FileSystem.cpp @@ -26,25 +26,28 @@ static const char* LOG_TAG = "FileSystem"; * @return N/A. */ void FileSystem::dumpDirectory(std::string path) { - DIR *pDir = ::opendir(path.c_str()); + DIR* pDir = ::opendir(path.c_str()); if (pDir == nullptr) { ESP_LOGD(LOG_TAG, "Unable to open directory: %s [errno=%d]", path.c_str(), errno); return; } - struct dirent *pDirent; + struct dirent* pDirent; ESP_LOGD(LOG_TAG, "Directory dump of %s", path.c_str()); - while((pDirent = readdir(pDir)) != nullptr) { + while ((pDirent = readdir(pDir)) != nullptr) { std::string type; - switch(pDirent->d_type) { - case DT_UNKNOWN: - type = "Unknown"; - break; - case DT_REG: - type = "Regular"; - break; - case DT_DIR: - type = "Directory"; - break; + switch (pDirent->d_type) { + case DT_UNKNOWN: + type = "Unknown"; + break; + case DT_REG: + type = "Regular"; + break; + case DT_DIR: + type = "Directory"; + break; + default: + type = "Unknown"; + break; } ESP_LOGD(LOG_TAG, "Entry: d_ino: %d, d_name: %s, d_type: %s", pDirent->d_ino, pDirent->d_name, type.c_str()); } @@ -59,14 +62,14 @@ void FileSystem::dumpDirectory(std::string path) { */ std::vector FileSystem::getDirectoryContents(std::string path) { std::vector ret; - DIR *pDir = ::opendir(path.c_str()); + DIR* pDir = ::opendir(path.c_str()); if (pDir == nullptr) { ESP_LOGE(LOG_TAG, "getDirectoryContents:: Unable to open directory: %s [errno=%d]", path.c_str(), errno); return ret; } - struct dirent *pDirent; + struct dirent* pDirent; ESP_LOGD(LOG_TAG, "Directory dump of %s", path.c_str()); - while((pDirent = readdir(pDir)) != nullptr) { + while ((pDirent = readdir(pDir)) != nullptr) { File file(path +"/" + std::string(pDirent->d_name), pDirent->d_type); ret.push_back(file); } @@ -82,9 +85,7 @@ std::vector FileSystem::getDirectoryContents(std::string path) { bool FileSystem::isDirectory(std::string path) { struct stat statBuf; int rc = stat(path.c_str(), &statBuf); - if (rc != 0) { - return false; - } + if (rc != 0) return false; return S_ISDIR(statBuf.st_mode); } // isDirectory @@ -129,11 +130,11 @@ std::vector FileSystem::pathSplit(std::string path) { std::istringstream stream(path); std::vector ret; std::string pathPart; - while(std::getline(stream, pathPart, '/')) { + while (std::getline(stream, pathPart, '/')) { ret.push_back(pathPart); } // Debug - for (int i=0; i #include #include "FreeRTOS.h" -#include #include "sdkconfig.h" - +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) +#include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" static const char* LOG_TAG = "FreeRTOS"; +#endif /** * Sleep for the specified number of milliseconds. * @param[in] ms The period in milliseconds for which to sleep. */ void FreeRTOS::sleep(uint32_t ms) { - ::vTaskDelay(ms/portTICK_PERIOD_MS); + ::vTaskDelay(ms / portTICK_PERIOD_MS); } // sleep @@ -32,7 +36,7 @@ void FreeRTOS::sleep(uint32_t ms) { * @param[in] param An optional parameter to be passed to the started task. * @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task. */ -void FreeRTOS::startTask(void task(void*), std::string taskName, void *param, int stackSize) { +void FreeRTOS::startTask(void task(void*), std::string taskName, void* param, uint32_t stackSize) { ::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL); } // startTask @@ -51,23 +55,9 @@ void FreeRTOS::deleteTask(TaskHandle_t pTask) { * @return The time in milliseconds since the %FreeRTOS scheduler started. */ uint32_t FreeRTOS::getTimeSinceStart() { - return (uint32_t)(xTaskGetTickCount()*portTICK_PERIOD_MS); + return (uint32_t) (xTaskGetTickCount() * portTICK_PERIOD_MS); } // getTimeSinceStart -/* - * public: - Semaphore(std::string = ""); - ~Semaphore(); - void give(); - void take(std::string owner=""); - void take(uint32_t timeoutMs, std::string owner=""); - private: - SemaphoreHandle_t m_semaphore; - std::string m_name; - std::string m_owner; - }; - * - */ /** * @brief Wait for a semaphore to be released by trying to take it and @@ -77,7 +67,8 @@ uint32_t FreeRTOS::getTimeSinceStart() { */ uint32_t FreeRTOS::Semaphore::wait(std::string owner) { ESP_LOGV(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str()); - + + m_owner = owner; if (m_usePthreads) { pthread_mutex_lock(&m_pthread_mutex); @@ -85,8 +76,6 @@ uint32_t FreeRTOS::Semaphore::wait(std::string owner) { xSemaphoreTake(m_semaphore, portMAX_DELAY); } - m_owner = owner; - if (m_usePthreads) { pthread_mutex_unlock(&m_pthread_mutex); } else { @@ -94,7 +83,6 @@ uint32_t FreeRTOS::Semaphore::wait(std::string owner) { } ESP_LOGV(LOG_TAG, "<< wait: Semaphore released: %s", toString().c_str()); - m_owner = std::string(""); return m_value; } // wait @@ -104,7 +92,8 @@ FreeRTOS::Semaphore::Semaphore(std::string name) { if (m_usePthreads) { pthread_mutex_init(&m_pthread_mutex, nullptr); } else { - m_semaphore = xSemaphoreCreateMutex(); + m_semaphore = xSemaphoreCreateBinary(); + xSemaphoreGive(m_semaphore); } m_name = name; @@ -134,7 +123,7 @@ void FreeRTOS::Semaphore::give() { xSemaphoreGive(m_semaphore); } // #ifdef ARDUINO_ARCH_ESP32 -// FreeRTOS::sleep(10); +// FreeRTOS::sleep(10); // #endif m_owner = std::string(""); @@ -171,14 +160,13 @@ void FreeRTOS::Semaphore::giveFromISR() { * @param [in] owner The new owner (for debugging) * @return True if we took the semaphore. */ -bool FreeRTOS::Semaphore::take(std::string owner) -{ +bool FreeRTOS::Semaphore::take(std::string owner) { ESP_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); bool rc = false; if (m_usePthreads) { pthread_mutex_lock(&m_pthread_mutex); } else { - rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY); + rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE; } m_owner = owner; if (rc) { @@ -198,13 +186,12 @@ bool FreeRTOS::Semaphore::take(std::string owner) * @return True if we took the semaphore. */ bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) { - ESP_LOGV(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str()); bool rc = false; if (m_usePthreads) { assert(false); // We apparently don't have a timed wait for pthreads. } else { - rc = ::xSemaphoreTake(m_semaphore, timeoutMs/portTICK_PERIOD_MS); + rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE; } m_owner = owner; if (rc) { @@ -279,8 +266,8 @@ void Ringbuffer::returnItem(void* item) { * @param [in] wait How long to wait before giving up. The default is to wait indefinitely. * @return */ -uint32_t Ringbuffer::send(void* data, size_t length, TickType_t wait) { - return ::xRingbufferSend(m_handle, data, length, wait); +bool Ringbuffer::send(void* data, size_t length, TickType_t wait) { + return ::xRingbufferSend(m_handle, data, length, wait) == pdTRUE; } // send diff --git a/cpp_utils/FreeRTOS.h b/cpp_utils/FreeRTOS.h index ab0e83d8..b861c875 100644 --- a/cpp_utils/FreeRTOS.h +++ b/cpp_utils/FreeRTOS.h @@ -23,7 +23,7 @@ class FreeRTOS { public: static void sleep(uint32_t ms); - static void startTask(void task(void *), std::string taskName, void *param=nullptr, int stackSize = 2048); + static void startTask(void task(void*), std::string taskName, void* param = nullptr, uint32_t stackSize = 2048); static void deleteTask(TaskHandle_t pTask = nullptr); static uint32_t getTimeSinceStart(); @@ -36,10 +36,10 @@ class FreeRTOS { void give(uint32_t value); void giveFromISR(); void setName(std::string name); - bool take(std::string owner=""); - bool take(uint32_t timeoutMs, std::string owner=""); + bool take(std::string owner = ""); + bool take(uint32_t timeoutMs, std::string owner = ""); std::string toString(); - uint32_t wait(std::string owner=""); + uint32_t wait(std::string owner = ""); private: SemaphoreHandle_t m_semaphore; @@ -48,6 +48,7 @@ class FreeRTOS { std::string m_owner; uint32_t m_value; bool m_usePthreads; + }; }; @@ -62,7 +63,7 @@ class Ringbuffer { void* receive(size_t* size, TickType_t wait = portMAX_DELAY); void returnItem(void* item); - uint32_t send(void* data, size_t length, TickType_t wait = portMAX_DELAY); + bool send(void* data, size_t length, TickType_t wait = portMAX_DELAY); private: RingbufHandle_t m_handle; }; diff --git a/cpp_utils/FreeRTOSTimer.cpp b/cpp_utils/FreeRTOSTimer.cpp index 4baec3e2..4b096000 100644 --- a/cpp_utils/FreeRTOSTimer.cpp +++ b/cpp_utils/FreeRTOSTimer.cpp @@ -11,10 +11,10 @@ #include "FreeRTOSTimer.h" -static std::map timersMap; +static std::map timersMap; void FreeRTOSTimer::internalCallback(TimerHandle_t xTimer) { - FreeRTOSTimer *timer = timersMap.at(xTimer); + FreeRTOSTimer* timer = timersMap.at(xTimer); timer->callback(timer); } @@ -33,7 +33,7 @@ void FreeRTOSTimer::internalCallback(TimerHandle_t xTimer) { * * @code{.cpp} * void callback(FreeRTOSTimer *pTimer) { - * // Callback code here ... + * // Callback code here ... * } * @endcode * @@ -43,12 +43,7 @@ void FreeRTOSTimer::internalCallback(TimerHandle_t xTimer) { * @param [in] data Data to be passed to the callback. * @param [in] callback Callback function to be fired when the timer expires. */ -FreeRTOSTimer::FreeRTOSTimer( - char *name, - TickType_t period, - UBaseType_t reload, - void *data, - void (*callback)(FreeRTOSTimer *pTimer)) { +FreeRTOSTimer::FreeRTOSTimer(char* name, TickType_t period, UBaseType_t reload, void* data, void (*callback)(FreeRTOSTimer* pTimer)) { /* * The callback function to actually be called is saved as member data in the object and * a static callback function is called. This will be passed the FreeRTOS timer handle @@ -124,7 +119,7 @@ void FreeRTOSTimer::changePeriod(TickType_t newPeriod, TickType_t blockTime) { * * @return The name of the timer. */ -const char *FreeRTOSTimer::getName() { +const char* FreeRTOSTimer::getName() { return ::pcTimerGetTimerName(timerHandle); } // getName @@ -134,6 +129,6 @@ const char *FreeRTOSTimer::getName() { * * @return The user supplied data associated with the timer. */ -void *FreeRTOSTimer::getData() { +void* FreeRTOSTimer::getData() { return ::pvTimerGetTimerID(timerHandle); } // getData diff --git a/cpp_utils/FreeRTOSTimer.h b/cpp_utils/FreeRTOSTimer.h index 8556ea3f..5c71a0e7 100644 --- a/cpp_utils/FreeRTOSTimer.h +++ b/cpp_utils/FreeRTOSTimer.h @@ -15,21 +15,22 @@ */ class FreeRTOSTimer { public: - FreeRTOSTimer(char *name, TickType_t period, UBaseType_t reload, void *data, void (*callback)(FreeRTOSTimer *pTimer)); + FreeRTOSTimer(char* name, TickType_t period, UBaseType_t reload, void* data, void (*callback)(FreeRTOSTimer* pTimer)); virtual ~FreeRTOSTimer(); - void changePeriod(TickType_t newPeriod, TickType_t blockTime=portMAX_DELAY); - void *getData(); - const char *getName(); + void changePeriod(TickType_t newPeriod, TickType_t blockTime = portMAX_DELAY); + void* getData(); + const char* getName(); TickType_t getPeriod(); - void reset(TickType_t blockTime=portMAX_DELAY); - void start(TickType_t blockTime=portMAX_DELAY); - void stop(TickType_t blockTime=portMAX_DELAY); + void reset(TickType_t blockTime = portMAX_DELAY); + void start(TickType_t blockTime = portMAX_DELAY); + void stop(TickType_t blockTime = portMAX_DELAY); private: TimerHandle_t timerHandle; TickType_t period; - void (*callback)(FreeRTOSTimer *pTimer); + void (*callback)(FreeRTOSTimer* pTimer); static void internalCallback(TimerHandle_t xTimer); + }; #endif /* COMPONENTS_CPP_UTILS_FREERTOSTIMER_H_ */ diff --git a/cpp_utils/GPIO.cpp b/cpp_utils/GPIO.cpp index 23cf6fb7..63941306 100644 --- a/cpp_utils/GPIO.cpp +++ b/cpp_utils/GPIO.cpp @@ -22,15 +22,11 @@ static bool g_isrServiceInstalled = false; * @param [in] handler The function to be invoked when the interrupt is detected. * @param [in] pArgs Optional arguments to pass to the handler. */ -void ESP32CPP::GPIO::addISRHandler( - gpio_num_t pin, - gpio_isr_t handler, - void* pArgs) { - +void ESP32CPP::GPIO::addISRHandler(gpio_num_t pin, gpio_isr_t handler, void* pArgs) { ESP_LOGD(LOG_TAG, ">> addISRHandler: pin=%d", pin); // If we have not yet installed the ISR service handler, install it now. - if (g_isrServiceInstalled == false) { + if (!g_isrServiceInstalled) { ESP_LOGD(LOG_TAG, "Installing the global ISR service"); esp_err_t errRc = ::gpio_install_isr_service(0); if (errRc != ESP_OK) { @@ -70,10 +66,7 @@ void ESP32CPP::GPIO::high(gpio_num_t pin) { * @return The value of true if the pin is valid and false otherwise. */ bool ESP32CPP::GPIO::inRange(gpio_num_t pin) { - if (pin>=0 && pin<=39) { - return true; - } - return false; + return (pin >= 0 && pin <= 39); } // inRange @@ -124,7 +117,7 @@ void ESP32CPP::GPIO::low(gpio_num_t pin) { * @return True if the pin is high, false if the pin is low. */ bool ESP32CPP::GPIO::read(gpio_num_t pin) { - return ::gpio_get_level(pin); + return ::gpio_get_level(pin) == 1; } // read @@ -155,14 +148,11 @@ void ESP32CPP::GPIO::setInput(gpio_num_t pin) { * @param [in] intrType The type of interrupt. * @return N/A. */ -void ESP32CPP::GPIO::setInterruptType( - gpio_num_t pin, - gpio_int_type_t intrType) { +void ESP32CPP::GPIO::setInterruptType(gpio_num_t pin, gpio_int_type_t intrType) { esp_err_t rc = ::gpio_set_intr_type(pin, intrType); if (rc != ESP_OK) { ESP_LOGE(LOG_TAG, "setInterruptType: %d", rc); } - } // setInterruptType @@ -189,7 +179,7 @@ void ESP32CPP::GPIO::setOutput(gpio_num_t pin) { */ void ESP32CPP::GPIO::write(gpio_num_t pin, bool value) { //ESP_LOGD(LOG_TAG, ">> write: pin: %d, value: %d", pin, value); - esp_err_t errRc = ::gpio_set_level(pin, value); + esp_err_t errRc = ::gpio_set_level(pin, value ? 1 : 0); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "<< gpio_set_level: pin=%d, rc=%d %s", pin, errRc, GeneralUtils::errorToString(errRc)); } @@ -204,9 +194,9 @@ void ESP32CPP::GPIO::write(gpio_num_t pin, bool value) { */ void ESP32CPP::GPIO::writeByte(gpio_num_t pins[], uint8_t value, int bits) { ESP_LOGD(LOG_TAG, ">> writeByte: value: %.2x, bits: %d", value, bits); - for (int i=0; i -namespace ESP32CPP -{ +namespace ESP32CPP { /** * @brief Interface to %GPIO functions. * diff --git a/cpp_utils/GeneralUtils.cpp b/cpp_utils/GeneralUtils.cpp index 960f3172..019c81bd 100644 --- a/cpp_utils/GeneralUtils.cpp +++ b/cpp_utils/GeneralUtils.cpp @@ -6,37 +6,43 @@ */ #include "GeneralUtils.h" -#include #include #include #include #include #include #include -#include +#include "FreeRTOS.h" #include #include #include #include #include +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) +#include "esp32-hal-log.h" +#define LOG_TAG "" +#else +#include "esp_log.h" static const char* LOG_TAG = "GeneralUtils"; +#endif + static const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; static int base64EncodedLength(size_t length) { return (length + 2 - ((length + 2) % 3)) / 3 * 4; } // base64EncodedLength -static int base64EncodedLength(const std::string &in) { +static int base64EncodedLength(const std::string& in) { return base64EncodedLength(in.length()); } // base64EncodedLength -static void a3_to_a4(unsigned char * a4, unsigned char * a3) { +static void a3_to_a4(unsigned char* a4, unsigned char* a3) { a4[0] = (a3[0] & 0xfc) >> 2; a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); @@ -44,7 +50,7 @@ static void a3_to_a4(unsigned char * a4, unsigned char * a3) { } // a3_to_a4 -static void a4_to_a3(unsigned char * a3, unsigned char * a4) { +static void a4_to_a3(unsigned char* a3, unsigned char* a4) { a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; @@ -56,7 +62,7 @@ static void a4_to_a3(unsigned char * a3, unsigned char * a4) { * @param [in] in * @param [out] out */ -bool GeneralUtils::base64Encode(const std::string &in, std::string *out) { +bool GeneralUtils::base64Encode(const std::string& in, std::string* out) { int i = 0, j = 0; size_t enc_len = 0; unsigned char a3[3]; @@ -109,11 +115,11 @@ void GeneralUtils::dumpInfo() { size_t freeHeap = heap_caps_get_free_size(MALLOC_CAP_8BIT); esp_chip_info_t chipInfo; esp_chip_info(&chipInfo); - ESP_LOGD(LOG_TAG, "--- dumpInfo ---"); - ESP_LOGD(LOG_TAG, "Free heap: %d", freeHeap); - ESP_LOGD(LOG_TAG, "Chip Info: Model: %d, cores: %d, revision: %d", chipInfo.model, chipInfo.cores, chipInfo.revision); - ESP_LOGD(LOG_TAG, "ESP-IDF version: %s", esp_get_idf_version()); - ESP_LOGD(LOG_TAG, "---"); + ESP_LOGV(LOG_TAG, "--- dumpInfo ---"); + ESP_LOGV(LOG_TAG, "Free heap: %d", freeHeap); + ESP_LOGV(LOG_TAG, "Chip Info: Model: %d, cores: %d, revision: %d", chipInfo.model, chipInfo.cores, chipInfo.revision); + ESP_LOGV(LOG_TAG, "ESP-IDF version: %s", esp_get_idf_version()); + ESP_LOGV(LOG_TAG, "---"); } // dumpInfo @@ -127,16 +133,16 @@ bool GeneralUtils::endsWith(std::string str, char c) { if (str.empty()) { return false; } - if (str.at(str.length()-1) == c) { + if (str.at(str.length() - 1) == c) { return true; } return false; } // endsWidth -static int DecodedLength(const std::string &in) { +static int DecodedLength(const std::string& in) { int numEq = 0; - int n = in.size(); + int n = (int) in.size(); for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { ++numEq; @@ -160,7 +166,7 @@ static unsigned char b64_lookup(unsigned char c) { * @param [in] in The string to be decoded. * @param [out] out The resulting data. */ -bool GeneralUtils::base64Decode(const std::string &in, std::string *out) { +bool GeneralUtils::base64Decode(const std::string& in, std::string* out) { int i = 0, j = 0; size_t dec_len = 0; unsigned char a3[3]; @@ -231,7 +237,7 @@ void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { if (index % 16 == 0) { strcpy(hexBuf, hex.str().c_str()); strcpy(asciiBuf, ascii.str().c_str()); - ESP_LOGD(tag, "%s %s", hexBuf, asciiBuf); + ESP_LOGV(tag, "%s %s", hexBuf, asciiBuf); hex.str(""); ascii.str(""); } @@ -243,8 +249,8 @@ void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { } strcpy(hexBuf, hex.str().c_str()); strcpy(asciiBuf, ascii.str().c_str()); - ESP_LOGD(tag, "%s %s", hexBuf, asciiBuf); - //ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); + ESP_LOGV(tag, "%s %s", hexBuf, asciiBuf); + //ESP_LOGV(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); } FreeRTOS::sleep(1000); } @@ -266,7 +272,7 @@ void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { } index++; if (index % 16 == 0) { - ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); + ESP_LOGV(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); hex.str(""); ascii.str(""); } @@ -276,7 +282,7 @@ void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { hex << " "; index++; } - ESP_LOGD(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); + ESP_LOGV(tag, "%s %s", hex.str().c_str(), ascii.str().c_str()); } FreeRTOS::sleep(1000); } @@ -296,11 +302,12 @@ void GeneralUtils::hexDump(const uint8_t* pData, uint32_t length) { char tempBuf[80]; uint32_t lineNumber = 0; - ESP_LOGD(LOG_TAG, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ----------------"); + ESP_LOGV(LOG_TAG, " 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"); + ESP_LOGV(LOG_TAG, " -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); strcpy(ascii, ""); strcpy(hex, ""); - uint32_t index=0; - while(index < length) { + uint32_t index = 0; + while (index < length) { sprintf(tempBuf, "%.2x ", pData[index]); strcat(hex, tempBuf); if (isprint(pData[index])) { @@ -311,18 +318,18 @@ void GeneralUtils::hexDump(const uint8_t* pData, uint32_t length) { strcat(ascii, tempBuf); index++; if (index % 16 == 0) { - ESP_LOGD(LOG_TAG, "%.4x %s %s", lineNumber*16, hex, ascii); + ESP_LOGV(LOG_TAG, "%.4x %s %s", lineNumber * 16, hex, ascii); strcpy(ascii, ""); strcpy(hex, ""); lineNumber++; } } if (index %16 != 0) { - while(index % 16 != 0) { + while (index % 16 != 0) { strcat(hex, " "); index++; } - ESP_LOGD(LOG_TAG, "%.4x %s %s", lineNumber*16, hex, ascii); + ESP_LOGV(LOG_TAG, "%.4x %s %s", lineNumber * 16, hex, ascii); } } // hexDump @@ -334,7 +341,7 @@ void GeneralUtils::hexDump(const uint8_t* pData, uint32_t length) { */ std::string GeneralUtils::ipToString(uint8_t *ip) { std::stringstream s; - s << (int)ip[0] << '.' << (int)ip[1] << '.' << (int)ip[2] << '.' << (int)ip[3]; + s << (int) ip[0] << '.' << (int) ip[1] << '.' << (int) ip[2] << '.' << (int) ip[3]; return s.str(); } // ipToString @@ -350,7 +357,7 @@ std::vector GeneralUtils::split(std::string source, char delimiter) std::vector strings; std::istringstream iss(source); std::string s; - while(std::getline(iss, s, delimiter)) { + while (std::getline(iss, s, delimiter)) { strings.push_back(trim(s)); } return strings; @@ -363,25 +370,26 @@ std::vector GeneralUtils::split(std::string source, char delimiter) * @return A string representation of the error code. */ const char* GeneralUtils::errorToString(esp_err_t errCode) { - switch(errCode) { + switch (errCode) { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 case ESP_OK: - return "OK"; + return "ESP_OK"; case ESP_FAIL: - return "Fail"; + return "ESP_FAIL"; case ESP_ERR_NO_MEM: - return "No memory"; + return "ESP_ERR_NO_MEM"; case ESP_ERR_INVALID_ARG: - return "Invalid argument"; + return "ESP_ERR_INVALID_ARG"; case ESP_ERR_INVALID_SIZE: - return "Invalid state"; + return "ESP_ERR_INVALID_SIZE"; case ESP_ERR_INVALID_STATE: - return "Invalid state"; + return "ESP_ERR_INVALID_STATE"; case ESP_ERR_NOT_FOUND: - return "Not found"; + return "ESP_ERR_NOT_FOUND"; case ESP_ERR_NOT_SUPPORTED: - return "Not supported"; + return "ESP_ERR_NOT_SUPPORTED"; case ESP_ERR_TIMEOUT: - return "Timeout"; + return "ESP_ERR_TIMEOUT"; case ESP_ERR_NVS_NOT_INITIALIZED: return "ESP_ERR_NVS_NOT_INITIALIZED"; case ESP_ERR_NVS_NOT_FOUND: @@ -430,87 +438,88 @@ const char* GeneralUtils::errorToString(esp_err_t errCode) { return "ESP_ERR_WIFI_TIMEOUT"; case ESP_ERR_WIFI_WAKE_FAIL: return "ESP_ERR_WIFI_WAKE_FAIL"; +#endif + default: + return "Unknown ESP_ERR error"; } - return "Unknown ESP_ERR error"; } // errorToString /** * @brief Convert a wifi_err_reason_t code to a string. * @param [in] errCode The errCode to be converted. * @return A string representation of the error code. - * + * * @note: wifi_err_reason_t values as of April 2018 are: (1-24, 200-204) and are defined in ~/esp-idf/components/esp32/include/esp_wifi_types.h. */ const char* GeneralUtils::wifiErrorToString(uint8_t errCode) { - if (errCode == ESP_OK) - return "ESP_OK (received SYSTEM_EVENT_STA_GOT_IP event)"; - if (errCode == UINT8_MAX) - return "Not Connected (default value)"; - - switch((wifi_err_reason_t) errCode) { - case WIFI_REASON_UNSPECIFIED: - return "WIFI_REASON_UNSPECIFIED"; - case WIFI_REASON_AUTH_EXPIRE: - return "WIFI_REASON_AUTH_EXPIRE"; - case WIFI_REASON_AUTH_LEAVE: - return "WIFI_REASON_AUTH_LEAVE"; - case WIFI_REASON_ASSOC_EXPIRE: - return "WIFI_REASON_ASSOC_EXPIRE"; - case WIFI_REASON_ASSOC_TOOMANY: - return "WIFI_REASON_ASSOC_TOOMANY"; - case WIFI_REASON_NOT_AUTHED: - return "WIFI_REASON_NOT_AUTHED"; - case WIFI_REASON_NOT_ASSOCED: - return "WIFI_REASON_NOT_ASSOCED"; - case WIFI_REASON_ASSOC_LEAVE: - return "WIFI_REASON_ASSOC_LEAVE"; - case WIFI_REASON_ASSOC_NOT_AUTHED: - return "WIFI_REASON_ASSOC_NOT_AUTHED"; - case WIFI_REASON_DISASSOC_PWRCAP_BAD: - return "WIFI_REASON_DISASSOC_PWRCAP_BAD"; - case WIFI_REASON_DISASSOC_SUPCHAN_BAD: - return "WIFI_REASON_DISASSOC_SUPCHAN_BAD"; - case WIFI_REASON_IE_INVALID: - return "WIFI_REASON_IE_INVALID"; - case WIFI_REASON_MIC_FAILURE: - return "WIFI_REASON_MIC_FAILURE"; - case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: - return "WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT"; - case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: - return "WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT"; - case WIFI_REASON_IE_IN_4WAY_DIFFERS: - return "WIFI_REASON_IE_IN_4WAY_DIFFERS"; - case WIFI_REASON_GROUP_CIPHER_INVALID: - return "WIFI_REASON_GROUP_CIPHER_INVALID"; - case WIFI_REASON_PAIRWISE_CIPHER_INVALID: - return "WIFI_REASON_PAIRWISE_CIPHER_INVALID"; - case WIFI_REASON_AKMP_INVALID: - return "WIFI_REASON_AKMP_INVALID"; - case WIFI_REASON_UNSUPP_RSN_IE_VERSION: - return "WIFI_REASON_UNSUPP_RSN_IE_VERSION"; - case WIFI_REASON_INVALID_RSN_IE_CAP: - return "WIFI_REASON_INVALID_RSN_IE_CAP"; - case WIFI_REASON_802_1X_AUTH_FAILED: - return "WIFI_REASON_802_1X_AUTH_FAILED"; - case WIFI_REASON_CIPHER_SUITE_REJECTED: - return "WIFI_REASON_CIPHER_SUITE_REJECTED"; - - case WIFI_REASON_BEACON_TIMEOUT: - return "WIFI_REASON_BEACON_TIMEOUT"; - case WIFI_REASON_NO_AP_FOUND: - return "WIFI_REASON_NO_AP_FOUND"; - case WIFI_REASON_AUTH_FAIL: - return "WIFI_REASON_AUTH_FAIL"; - case WIFI_REASON_ASSOC_FAIL: - return "WIFI_REASON_ASSOC_FAIL"; - case WIFI_REASON_HANDSHAKE_TIMEOUT: - return "WIFI_REASON_HANDSHAKE_TIMEOUT"; + if (errCode == ESP_OK) return "ESP_OK (received SYSTEM_EVENT_STA_GOT_IP event)"; + if (errCode == UINT8_MAX) return "Not Connected (default value)"; + + switch ((wifi_err_reason_t) errCode) { +#if CONFIG_LOG_DEFAULT_LEVEL > 4 + case WIFI_REASON_UNSPECIFIED: + return "WIFI_REASON_UNSPECIFIED"; + case WIFI_REASON_AUTH_EXPIRE: + return "WIFI_REASON_AUTH_EXPIRE"; + case WIFI_REASON_AUTH_LEAVE: + return "WIFI_REASON_AUTH_LEAVE"; + case WIFI_REASON_ASSOC_EXPIRE: + return "WIFI_REASON_ASSOC_EXPIRE"; + case WIFI_REASON_ASSOC_TOOMANY: + return "WIFI_REASON_ASSOC_TOOMANY"; + case WIFI_REASON_NOT_AUTHED: + return "WIFI_REASON_NOT_AUTHED"; + case WIFI_REASON_NOT_ASSOCED: + return "WIFI_REASON_NOT_ASSOCED"; + case WIFI_REASON_ASSOC_LEAVE: + return "WIFI_REASON_ASSOC_LEAVE"; + case WIFI_REASON_ASSOC_NOT_AUTHED: + return "WIFI_REASON_ASSOC_NOT_AUTHED"; + case WIFI_REASON_DISASSOC_PWRCAP_BAD: + return "WIFI_REASON_DISASSOC_PWRCAP_BAD"; + case WIFI_REASON_DISASSOC_SUPCHAN_BAD: + return "WIFI_REASON_DISASSOC_SUPCHAN_BAD"; + case WIFI_REASON_IE_INVALID: + return "WIFI_REASON_IE_INVALID"; + case WIFI_REASON_MIC_FAILURE: + return "WIFI_REASON_MIC_FAILURE"; + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + return "WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT"; + case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: + return "WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT"; + case WIFI_REASON_IE_IN_4WAY_DIFFERS: + return "WIFI_REASON_IE_IN_4WAY_DIFFERS"; + case WIFI_REASON_GROUP_CIPHER_INVALID: + return "WIFI_REASON_GROUP_CIPHER_INVALID"; + case WIFI_REASON_PAIRWISE_CIPHER_INVALID: + return "WIFI_REASON_PAIRWISE_CIPHER_INVALID"; + case WIFI_REASON_AKMP_INVALID: + return "WIFI_REASON_AKMP_INVALID"; + case WIFI_REASON_UNSUPP_RSN_IE_VERSION: + return "WIFI_REASON_UNSUPP_RSN_IE_VERSION"; + case WIFI_REASON_INVALID_RSN_IE_CAP: + return "WIFI_REASON_INVALID_RSN_IE_CAP"; + case WIFI_REASON_802_1X_AUTH_FAILED: + return "WIFI_REASON_802_1X_AUTH_FAILED"; + case WIFI_REASON_CIPHER_SUITE_REJECTED: + return "WIFI_REASON_CIPHER_SUITE_REJECTED"; + case WIFI_REASON_BEACON_TIMEOUT: + return "WIFI_REASON_BEACON_TIMEOUT"; + case WIFI_REASON_NO_AP_FOUND: + return "WIFI_REASON_NO_AP_FOUND"; + case WIFI_REASON_AUTH_FAIL: + return "WIFI_REASON_AUTH_FAIL"; + case WIFI_REASON_ASSOC_FAIL: + return "WIFI_REASON_ASSOC_FAIL"; + case WIFI_REASON_HANDSHAKE_TIMEOUT: + return "WIFI_REASON_HANDSHAKE_TIMEOUT"; +#endif + default: + return "Unknown ESP_ERR error"; } - return "Unknown ESP_ERR error"; } // wifiErrorToString - /** * @brief Convert a string to lower case. * @param [in] value The string to convert to lower case. @@ -527,15 +536,9 @@ std::string GeneralUtils::toLower(std::string& value) { /** * @brief Remove white space from a string. */ -std::string GeneralUtils::trim(const std::string& str) -{ - size_t first = str.find_first_not_of(' '); - if (std::string::npos == first) - { - return str; - } - size_t last = str.find_last_not_of(' '); - return str.substr(first, (last - first + 1)); +std::string GeneralUtils::trim(const std::string& str) { + size_t first = str.find_first_not_of(' '); + if (std::string::npos == first) return str; + size_t last = str.find_last_not_of(' '); + return str.substr(first, (last - first + 1)); } // trim - - diff --git a/cpp_utils/GeneralUtils.h b/cpp_utils/GeneralUtils.h index 3706040e..8eecbd4d 100644 --- a/cpp_utils/GeneralUtils.h +++ b/cpp_utils/GeneralUtils.h @@ -23,7 +23,7 @@ class GeneralUtils { static void dumpInfo(); static bool endsWith(std::string str, char c); static const char* errorToString(esp_err_t errCode); - static const char* wifiErrorToString(uint8_t value); + static const char* wifiErrorToString(uint8_t value); static void hexDump(const uint8_t* pData, uint32_t length); static std::string ipToString(uint8_t* ip); static std::vector split(std::string source, char delimiter); diff --git a/cpp_utils/HIDKeyboardTypes.h b/cpp_utils/HIDKeyboardTypes.h index ef48a526..4e221d57 100644 --- a/cpp_utils/HIDKeyboardTypes.h +++ b/cpp_utils/HIDKeyboardTypes.h @@ -26,9 +26,9 @@ /* Modifiers */ enum MODIFIER_KEY { - KEY_CTRL = 1, - KEY_SHIFT = 2, - KEY_ALT = 4, + KEY_CTRL = 1, + KEY_SHIFT = 2, + KEY_ALT = 4, }; @@ -43,37 +43,37 @@ enum MEDIA_KEY { }; enum FUNCTION_KEY { - KEY_F1 = 128, /* F1 key */ - KEY_F2, /* F2 key */ - KEY_F3, /* F3 key */ - KEY_F4, /* F4 key */ - KEY_F5, /* F5 key */ - KEY_F6, /* F6 key */ - KEY_F7, /* F7 key */ - KEY_F8, /* F8 key */ - KEY_F9, /* F9 key */ - KEY_F10, /* F10 key */ - KEY_F11, /* F11 key */ - KEY_F12, /* F12 key */ + KEY_F1 = 128, /* F1 key */ + KEY_F2, /* F2 key */ + KEY_F3, /* F3 key */ + KEY_F4, /* F4 key */ + KEY_F5, /* F5 key */ + KEY_F6, /* F6 key */ + KEY_F7, /* F7 key */ + KEY_F8, /* F8 key */ + KEY_F9, /* F9 key */ + KEY_F10, /* F10 key */ + KEY_F11, /* F11 key */ + KEY_F12, /* F12 key */ - KEY_PRINT_SCREEN, /* Print Screen key */ - KEY_SCROLL_LOCK, /* Scroll lock */ - KEY_CAPS_LOCK, /* caps lock */ - KEY_NUM_LOCK, /* num lock */ - KEY_INSERT, /* Insert key */ - KEY_HOME, /* Home key */ - KEY_PAGE_UP, /* Page Up key */ - KEY_PAGE_DOWN, /* Page Down key */ + KEY_PRINT_SCREEN, /* Print Screen key */ + KEY_SCROLL_LOCK, /* Scroll lock */ + KEY_CAPS_LOCK, /* caps lock */ + KEY_NUM_LOCK, /* num lock */ + KEY_INSERT, /* Insert key */ + KEY_HOME, /* Home key */ + KEY_PAGE_UP, /* Page Up key */ + KEY_PAGE_DOWN, /* Page Down key */ - RIGHT_ARROW, /* Right arrow */ - LEFT_ARROW, /* Left arrow */ - DOWN_ARROW, /* Down arrow */ - UP_ARROW, /* Up arrow */ + RIGHT_ARROW, /* Right arrow */ + LEFT_ARROW, /* Left arrow */ + DOWN_ARROW, /* Down arrow */ + UP_ARROW, /* Up arrow */ }; typedef struct { - unsigned char usage; - unsigned char modifier; + unsigned char usage; + unsigned char modifier; } KEYMAP; #ifdef US_KEYBOARD diff --git a/cpp_utils/HIDTypes.h b/cpp_utils/HIDTypes.h index 726b84be..64850ef8 100644 --- a/cpp_utils/HIDTypes.h +++ b/cpp_utils/HIDTypes.h @@ -89,8 +89,8 @@ #define MAX_HID_REPORT_SIZE (64) typedef struct { - uint32_t length; - uint8_t data[MAX_HID_REPORT_SIZE]; + uint32_t length; + uint8_t data[MAX_HID_REPORT_SIZE]; } HID_REPORT; #endif diff --git a/cpp_utils/HttpParser.cpp b/cpp_utils/HttpParser.cpp index d9040659..a6bbbc34 100644 --- a/cpp_utils/HttpParser.cpp +++ b/cpp_utils/HttpParser.cpp @@ -42,11 +42,11 @@ static std::string lineTerminator = "\r\n"; * @param [in] str The string we are parsing. * @param [in] token The token delimiter. */ -static std::string toStringToken(std::string::iterator &it, std::string &str, std::string &token) { +static std::string toStringToken(std::string::iterator& it, std::string& str, std::string& token) { std::string ret; std::string part; auto itToken = token.begin(); - for(; it != str.end(); ++it) { + for (; it != str.end(); ++it) { if ((*it) == (*itToken)) { part += (*itToken); ++itToken; @@ -74,7 +74,7 @@ static std::string toStringToken(std::string::iterator &it, std::string &str, st * @param [in] token The token terminating the parse. * @return The parsed string token. */ -static std::string toCharToken(std::string::iterator &it, std::string &str, char token) { +static std::string toCharToken(std::string::iterator& it, std::string& str, char token) { std::string ret; for(; it != str.end(); ++it) { if ((*it) == token) { @@ -97,9 +97,9 @@ static std::string toCharToken(std::string::iterator &it, std::string &str, char * @param [in] line The line of text to parse. * @return A pair of the form name/value. */ -std::pair parseHeader(std::string &line) { - auto it = line.begin(); - std::string name = toCharToken(it, line, ':'); // Parse the line until we find a ':' +std::pair parseHeader(std::string& line) { + auto it = line.begin(); + std::string name = toCharToken(it, line, ':'); // Parse the line until we find a ':' // We normalize the header name to be lower case. GeneralUtils::toLower(name); auto value = GeneralUtils::trim(toStringToken(it, line, lineTerminator)); @@ -142,9 +142,7 @@ std::string HttpParser::getHeader(const std::string& name) { // We normalize the header name to be lower case. std::string localName = name; GeneralUtils::toLower(localName); - if (!hasHeader(localName)) { - return ""; - } + if (!hasHeader(localName)) return ""; return m_headers.at(localName); } // getHeader @@ -169,11 +167,11 @@ std::string HttpParser::getVersion() { } // getVersion std::string HttpParser::getStatus() { - return m_status; + return m_status; } // getStatus std::string HttpParser::getReason() { - return m_reason; + return m_reason; } // getReason /** @@ -198,7 +196,7 @@ void HttpParser::parse(Socket s) { line = s.readToDelim(lineTerminator); parseRequestLine(line); line = s.readToDelim(lineTerminator); - while(!line.empty()) { + while (!line.empty()) { m_headers.insert(parseHeader(line)); line = s.readToDelim(lineTerminator); } @@ -216,13 +214,13 @@ void HttpParser::parse(Socket s) { int length = std::atoi(val.c_str()); uint8_t data[length]; s.receive(data, length, true); - m_body = std::string((char *)data, length); + m_body = std::string((char*) data, length); } else { uint8_t data[512]; int rc = s.receive(data, sizeof(data)); - if (rc > 0) { - m_body = std::string((char *)data, rc); - } + if (rc > 0) { + m_body = std::string((char*) data, rc); + } } ESP_LOGD(LOG_TAG, "<< parse: Size of body: %d", m_body.length()); } // parse @@ -253,10 +251,9 @@ void HttpParser::parse(std::string message) { * @brief Parse A request line. * @param [in] line The request line to parse. */ -// A request Line is built from: -// -// -void HttpParser::parseRequestLine(std::string &line) { +void HttpParser::parseRequestLine(std::string& line) { + // A request Line is built from: + // ESP_LOGD(LOG_TAG, ">> parseRequestLine: \"%s\" [%d]", line.c_str(), line.length()); std::string::iterator it = line.begin(); @@ -275,17 +272,15 @@ void HttpParser::parseRequestLine(std::string &line) { * @brief Parse a response message. * @param [in] line The response to parse. */ -// A response is built from: -// A status line, any number of header lines, a body -// -void HttpParser::parseResponse(std::string message) -{ +void HttpParser::parseResponse(std::string message) { + // A response is built from: + // A status line, any number of header lines, a body auto it = message.begin(); auto line = toStringToken(it, message, lineTerminator); parseStatusLine(line); line = toStringToken(it, message, lineTerminator); - while(!line.empty()) { + while (!line.empty()) { ESP_LOGD(LOG_TAG, "Header: \"%s\"", line.c_str()); m_headers.insert(parseHeader(line)); line = toStringToken(it, message, lineTerminator); @@ -298,11 +293,9 @@ void HttpParser::parseResponse(std::string message) * @brief Parse A status line. * @param [in] line The status line to parse. */ -// A status Line is built from: -// -// -void HttpParser::parseStatusLine(std::string &line) -{ +void HttpParser::parseStatusLine(std::string& line) { + // A status Line is built from: + // ESP_LOGD(LOG_TAG, ">> ParseStatusLine: \"%s\" [%d]", line.c_str(), line.length()); std::string::iterator it = line.begin(); // Get the version @@ -314,4 +307,3 @@ void HttpParser::parseStatusLine(std::string &line) ESP_LOGD(LOG_TAG, "<< ParseStatusLine: method: %s, version: %s, status: %s", m_method.c_str(), m_version.c_str(), m_status.c_str()); } // parseRequestLine - diff --git a/cpp_utils/HttpParser.h b/cpp_utils/HttpParser.h index 47aafcea..06485293 100644 --- a/cpp_utils/HttpParser.h +++ b/cpp_utils/HttpParser.h @@ -12,17 +12,6 @@ #include "Socket.h" class HttpParser { -private: - std::string m_method; - std::string m_url; - std::string m_version; - std::string m_body; - std::string m_status; - std::string m_reason; - std::map m_headers; - void dump(); - void parseRequestLine(std::string &line); - void parseStatusLine(std::string &line); public: HttpParser(); virtual ~HttpParser(); @@ -32,12 +21,25 @@ class HttpParser { std::string getMethod(); std::string getURL(); std::string getVersion(); - std::string getStatus(); - std::string getReason(); + std::string getStatus(); + std::string getReason(); bool hasHeader(const std::string& name); void parse(std::string message); void parse(Socket s); - void parseResponse(std::string message); + void parseResponse(std::string message); + +private: + std::string m_method; + std::string m_url; + std::string m_version; + std::string m_body; + std::string m_status; + std::string m_reason; + std::map m_headers; + void dump(); + void parseRequestLine(std::string& line); + void parseStatusLine(std::string& line); + }; #endif /* CPP_UTILS_HTTPPARSER_H_ */ diff --git a/cpp_utils/HttpRequest.cpp b/cpp_utils/HttpRequest.cpp index 9261af60..ff9336fb 100644 --- a/cpp_utils/HttpRequest.cpp +++ b/cpp_utils/HttpRequest.cpp @@ -41,6 +41,8 @@ #include #include +#define STATE_NAME 0 +#define STATE_VALUE 1 static const char* LOG_TAG="HttpRequest"; @@ -79,10 +81,10 @@ const char HttpRequest::HTTP_METHOD_PUT[] = "PUT"; std::string buildWebsocketKeyResponseHash(std::string requestKey) { std::string newKey = requestKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; uint8_t shaData[20]; - esp_sha(SHA1, (uint8_t*)newKey.data(), newKey.length(), shaData); + esp_sha(SHA1, (uint8_t*) newKey.data(), newKey.length(), shaData); //GeneralUtils::hexDump(shaData, 20); std::string retStr; - GeneralUtils::base64Encode(std::string((char*)shaData, sizeof(shaData)), &retStr); + GeneralUtils::base64Encode(std::string((char*) shaData, sizeof(shaData)), &retStr); return retStr; } // buildWebsocketKeyResponseHash @@ -104,9 +106,8 @@ HttpRequest::HttpRequest(Socket clientSocket) { // a delimiter and then examine each of the parts to see if any of those are "Upgrade". std::vector parts = GeneralUtils::split(getHeader(HTTP_HEADER_CONNECTION), ','); bool upgradeFound = false; - if (std::find(parts.begin(), parts.end(), "Upgrade") != parts.end()) - { - upgradeFound = true; + if (std::find(parts.begin(), parts.end(), "Upgrade") != parts.end()) { + upgradeFound = true; } // Is this a Web Socket? @@ -114,7 +115,7 @@ HttpRequest::HttpRequest(Socket clientSocket) { !getHeader(HTTP_HEADER_HOST).empty() && getHeader(HTTP_HEADER_UPGRADE) == "websocket" && //getHeader(HTTP_HEADER_CONNECTION) == "Upgrade" && - upgradeFound == true && + upgradeFound && !getHeader(HTTP_HEADER_SEC_WEBSOCKET_KEY).empty() && !getHeader(HTTP_HEADER_SEC_WEBSOCKET_VERSION).empty()) { ESP_LOGD(LOG_TAG, "Websocket detected!"); @@ -153,9 +154,6 @@ void HttpRequest::close() { } // close_cpp - - - /** * @brief Dump the HttpRequest for debugging purposes. */ @@ -203,9 +201,6 @@ std::string HttpRequest::getPath() { } // getPath -#define STATE_NAME 0 -#define STATE_VALUE 1 - /** * @brief Get the query part of the request. * The query is a set of name = value pairs. The return is a map keyed by the name items. @@ -218,9 +213,9 @@ std::map HttpRequest::getQuery() { std::map queryMap; std::string possibleQueryString = getPath(); - int qindex = possibleQueryString.find_first_of("?") ; + int qindex = possibleQueryString.find_first_of("?"); if (qindex < 0) { - ESP_LOGD(LOG_TAG, "No query string present") ; + ESP_LOGD(LOG_TAG, "No query string present"); return queryMap ; } std::string queryString = possibleQueryString.substr(qindex + 1, -1) ; @@ -235,7 +230,7 @@ std::map HttpRequest::getQuery() { std::string name = ""; std::string value; // Loop through each character in the query string. - for (int i=0; i HttpRequest::getQuery() { } // getQuery - /** * @brief Get the underlying socket. * @return The underlying socket. @@ -353,11 +347,11 @@ std::vector HttpRequest::pathSplit() { std::istringstream stream(getPath()); std::vector ret; std::string pathPart; - while(std::getline(stream, pathPart, '/')) { + while (std::getline(stream, pathPart, '/')) { ret.push_back(pathPart); } // Debug - for (int i=0; i parseForm(); // Parse the body as a form. std::vector pathSplit(); std::string urlDecode(std::string str); // Decode a URL. +private: + Socket m_clientSocket; // The socket connected to the client. + bool m_isClosed; // Is the client connection closed? + HttpParser m_parser; // The parse to parse HTTP data. + WebSocket* m_pWebSocket; // A possible reference to a WebSocket object instance. + }; #endif /* COMPONENTS_CPP_UTILS_HTTPREQUEST_H_ */ diff --git a/cpp_utils/HttpResponse.cpp b/cpp_utils/HttpResponse.cpp index 4c5c1a4e..46f3e9bd 100644 --- a/cpp_utils/HttpResponse.cpp +++ b/cpp_utils/HttpResponse.cpp @@ -26,12 +26,13 @@ const int HttpResponse::HTTP_STATUS_NOT_IMPLEMENTED = 501; const int HttpResponse::HTTP_STATUS_SERVICE_UNAVAILABLE = 503; static std::string lineTerminator = "\r\n"; -HttpResponse::HttpResponse(HttpRequest *request) { +HttpResponse::HttpResponse(HttpRequest* request) { m_request = request; m_status = 200; m_headerCommitted = false; // We have not yet sent a header. } + HttpResponse::~HttpResponse() { } @@ -43,9 +44,7 @@ HttpResponse::~HttpResponse() { * @param [in] value The value of the header. */ void HttpResponse::addHeader(const std::string name, const std::string value) { - if (m_headerCommitted) { - return; - } + if (m_headerCommitted) return; m_responseHeaders.insert(std::pair(name, value)); } // addHeader @@ -57,7 +56,7 @@ void HttpResponse::addHeader(const std::string name, const std::string value) { */ void HttpResponse::close() { // If we haven't yet sent the header of the data, send that now. - if (m_headerCommitted == false) { + if (!m_headerCommitted) { sendHeader(); } m_request->close(); @@ -70,9 +69,7 @@ void HttpResponse::close() { * @return The value of the named header. */ std::string HttpResponse::getHeader(std::string name) { - if (m_responseHeaders.find(name) == m_responseHeaders.end()) { - return ""; - } + if (m_responseHeaders.find(name) == m_responseHeaders.end()) return ""; return m_responseHeaders.at(name); } // getHeader @@ -97,7 +94,7 @@ void HttpResponse::sendData(std::string data) { } // If we haven't yet sent the header of the data, send that now. - if (m_headerCommitted == false) { + if (!m_headerCommitted) { sendHeader(); } @@ -115,7 +112,7 @@ void HttpResponse::sendData(uint8_t* pData, size_t size) { } // If we haven't yet sent the header of the data, send that now. - if (m_headerCommitted == false) { + if (!m_headerCommitted) { sendHeader(); } @@ -124,12 +121,11 @@ void HttpResponse::sendData(uint8_t* pData, size_t size) { ESP_LOGD(LOG_TAG, "<< sendData"); } // sendData -void HttpResponse::sendFile(std::string fileName, size_t bufSize) -{ +void HttpResponse::sendFile(std::string fileName, size_t bufSize) { ESP_LOGI(LOG_TAG, "Opening file: %s", fileName.c_str()); std::ifstream ifStream; ifStream.open(fileName, std::ifstream::in | std::ifstream::binary); // Attempt to open the file for reading. - + // If we failed to open the requested file, then it probably didn't exist so return a not found. if (!ifStream.is_open()) { ESP_LOGE(LOG_TAG, "Unable to open file %s for reading", fileName.c_str()); @@ -139,15 +135,15 @@ void HttpResponse::sendFile(std::string fileName, size_t bufSize) close(); return; // Since we failed to open the file, no further work to be done. } - + // We now have an open file and want to push the content of that file through to the browser. // because of defect #252 we have to do some pretty important re-work here. Specifically, we can't host the whole file in // RAM at one time. Instead what we have to do is ensure that we only have enough data in RAM to be sent. - + setStatus(HttpResponse::HTTP_STATUS_OK, "OK"); uint8_t *pData = new uint8_t[bufSize]; - while(!ifStream.eof()) { - ifStream.read((char *)pData, bufSize); + while (!ifStream.eof()) { + ifStream.read((char*) pData, bufSize); sendData(pData, ifStream.gcount()); } delete[] pData; @@ -160,7 +156,7 @@ void HttpResponse::sendFile(std::string fileName, size_t bufSize) */ void HttpResponse::sendHeader() { // If we haven't yet sent the header of the data, send that now. - if (m_headerCommitted == false) { + if (!m_headerCommitted) { std::ostringstream oss; oss << m_request->getVersion() << " " << m_status << " " << m_statusMessage << lineTerminator; for (auto it = m_responseHeaders.begin(); it != m_responseHeaders.end(); ++it) { @@ -188,5 +184,3 @@ void HttpResponse::setStatus(const int status, const std::string message) { m_status = status; m_statusMessage = message; } // setStatus - - diff --git a/cpp_utils/HttpResponse.h b/cpp_utils/HttpResponse.h index 7080ea90..5dfaa976 100644 --- a/cpp_utils/HttpResponse.h +++ b/cpp_utils/HttpResponse.h @@ -14,15 +14,6 @@ #include "HttpRequest.h" class HttpResponse { -private: - bool m_headerCommitted; // Has the header been sent? - HttpRequest* m_request; // The request associated with this response. - std::map m_responseHeaders; // The headers to be sent with the response. - int m_status; // The status to be sent with the response. - std::string m_statusMessage; // The status message to be sent with the response. - - void sendHeader(); // Send the header to the client. - public: static const int HTTP_STATUS_CONTINUE; static const int HTTP_STATUS_SWITCHING_PROTOCOL; @@ -46,8 +37,18 @@ class HttpResponse { std::map getHeaders(); // Get all headers. void sendData(std::string data); // Send data to the client. void sendData(uint8_t* pData, size_t size); // Send data to the client. - void sendFile(std::string fileName, size_t bufSize=4*1024); // Send file contents if exists. void setStatus(int status, std::string message); // Set the response status. + void sendFile(std::string fileName, size_t bufSize = 4 * 1024); // Send file contents if exists. + +private: + bool m_headerCommitted; // Has the header been sent? + HttpRequest* m_request; // The request associated with this response. + std::map m_responseHeaders; // The headers to be sent with the response. + int m_status; // The status to be sent with the response. + std::string m_statusMessage; // The status message to be sent with the response. + + void sendHeader(); // Send the header to the client. + }; #endif /* COMPONENTS_CPP_UTILS_HTTPRESPONSE_H_ */ diff --git a/cpp_utils/HttpServer.cpp b/cpp_utils/HttpServer.cpp index 1b1845f1..fb90fcc9 100644 --- a/cpp_utils/HttpServer.cpp +++ b/cpp_utils/HttpServer.cpp @@ -26,17 +26,16 @@ static const char* LOG_TAG = "HttpServer"; #undef close - /** * Constructor for HTTP Server */ HttpServer::HttpServer() { - m_fileBufferSize = 4*1024; // Default size of the file buffer. m_portNumber = 80; // The default port number. m_clientTimeout = 5; // The default timeout 5 seconds. m_rootPath = ""; // The default path. m_useSSL = false; // Default SSL is no. setDirectoryListing(false); // Default directory listing is disabled. + m_fileBufferSize = 4 * 1024; // Default size of the file buffer. } // HttpServer @@ -44,6 +43,7 @@ HttpServer::~HttpServer() { ESP_LOGD(LOG_TAG, "~HttpServer"); } + /** * @brief Be an HTTP server task. * Here we define a Task that will be run when the HTTP server starts. It is this task @@ -52,7 +52,7 @@ HttpServer::~HttpServer() { */ class HttpServerTask: public Task { public: - HttpServerTask(std::string name): Task(name, 16*1024) { + HttpServerTask(std::string name): Task(name, 16 * 1024) { m_pHttpServer = nullptr; }; @@ -70,7 +70,7 @@ class HttpServerTask: public Task { * * @param [in] request The HTTP request to process. */ - void processRequest(HttpRequest &request) { + void processRequest(HttpRequest& request) { ESP_LOGD("HttpServerTask", ">> processRequest: Method: %s, Path: %s", request.getMethod().c_str(), request.getPath().c_str()); @@ -107,9 +107,9 @@ class HttpServerTask: public Task { // If the file name ends with a '/' then remove it ... we are normalizing to NO trailing slashes. if (GeneralUtils::endsWith(fileName, '/')) { - fileName = fileName.substr(0, fileName.length()-1); + fileName = fileName.substr(0, fileName.length() - 1); } - + HttpResponse response(&request); // Test if the path is a directory. if (FileSystem::isDirectory(fileName)) { @@ -129,20 +129,18 @@ class HttpServerTask: public Task { * @param [in] data A reference to the HttpServer. */ void run(void* data) { - m_pHttpServer = (HttpServer*)data; // The passed in data is an instance of an HttpServer. + m_pHttpServer = (HttpServer*) data; // The passed in data is an instance of an HttpServer. m_pHttpServer->m_socket.setSSL(m_pHttpServer->m_useSSL); m_pHttpServer->m_socket.listen(m_pHttpServer->m_portNumber, false /* is datagram */, true /* Allow address reuse */); ESP_LOGD("HttpServerTask", "Listening on port %d", m_pHttpServer->getPort()); Socket clientSocket; - while(1) { // Loop forever. - + while (true) { // Loop forever. ESP_LOGD("HttpServerTask", "Waiting for new peer client"); try { clientSocket = m_pHttpServer->m_socket.accept(); // Block waiting for a new external client connection. clientSocket.setTimeout(m_pHttpServer->getClientTimeout()); - } - catch(std::exception &e) { + } catch (std::exception& e) { ESP_LOGE("HttpServerTask", "Caught an exception waiting for new client!"); m_pHttpServer->m_semaphoreServerStarted.give(); // Release the semaphore .. we are now no longer running. return; @@ -174,7 +172,7 @@ class HttpServerTask: public Task { * Example: * @code{.cpp} * static void handle_REST_WiFi(WebServer::HttpRequest *pRequest, WebServer::HttpResponse *pResponse) { - * ... + * ... * } * * webServer.addPathHandler("GET", "\\/ESP32\\/WiFi", handle_REST_WiFi); @@ -187,7 +185,7 @@ class HttpServerTask: public Task { void HttpServer::addPathHandler( std::string method, std::regex* pathExpr, - void (*handler)(HttpRequest *pHttpRequest, HttpResponse *pHttpResponse)) { + void (*handler)(HttpRequest* pHttpRequest, HttpResponse* pHttpResponse)) { // We are maintaining a C++ vector of PathHandler objects. We add a new entry into that vector. m_pathHandlers.push_back(PathHandler(method, pathExpr, handler)); @@ -204,7 +202,7 @@ void HttpServer::addPathHandler( * Example: * @code{.cpp} * static void handle_REST_WiFi(WebServer::HttpRequest *pRequest, WebServer::HttpResponse *pResponse) { - * ... + * ... * } * * webServer.addPathHandler("GET", "/ESP32/WiFi", handle_REST_WiFi); @@ -217,7 +215,7 @@ void HttpServer::addPathHandler( void HttpServer::addPathHandler( std::string method, std::string path, - void (*handler)(HttpRequest *pHttpRequest, HttpResponse *pHttpResponse)) { + void (*handler)(HttpRequest* pHttpRequest, HttpResponse* pHttpResponse)) { // We are maintaining a C++ vector of PathHandler objects. We add a new entry into that vector. m_pathHandlers.push_back(PathHandler(method, path, handler)); @@ -299,8 +297,7 @@ void HttpServer::listDirectory(std::string path, HttpResponse& response) { ss << "" << it->getName() << ""; if (it->isDirectory()) { ss << "<dir>"; - } - else { + } else { ss << "" << it->length() << ""; } @@ -314,6 +311,7 @@ void HttpServer::listDirectory(std::string path, HttpResponse& response) { response.close(); } // listDirectory + /** * @brief Set different socket timeout for new connections. * @param [in] use Set to true to enable directory listing. @@ -322,6 +320,7 @@ void HttpServer::setClientTimeout(uint32_t timeout) { m_clientTimeout = timeout; } + /** * @brief Get current socket's timeout for new connections. * @param [in] use Set to true to enable directory listing. @@ -330,6 +329,7 @@ uint32_t HttpServer::getClientTimeout() { return m_clientTimeout; } + /** * @brief Set whether or not we will list directories. * @param [in] use Set to true to enable directory listing. @@ -369,7 +369,6 @@ void HttpServer::setFileBufferSize(size_t fileBufferSize) { * @return N/A. */ void HttpServer::setRootPath(std::string path) { - // Should the user have supplied a path that ends in a "/" remove the trailing slash. This also // means that "/" becomes "". if (GeneralUtils::endsWith(path, '/')) { @@ -393,7 +392,7 @@ void HttpServer::start(uint16_t portNumber, bool useSSL) { // Take the semaphore that says that we are now running. If we are already running, then end here as // there is nothing further to do. - if (m_semaphoreServerStarted.take(100, "start") == false) { + if (!m_semaphoreServerStarted.take(100, "start")) { ESP_LOGD(LOG_TAG, "<< start: Already running"); return; } @@ -428,7 +427,7 @@ void HttpServer::stop() { * @param [in] pathPattern The path pattern to be matched. * @param [in] webServerRequestHandler The request handler to be called. */ -PathHandler::PathHandler(std::string method, std::regex *pRegex, +PathHandler::PathHandler(std::string method, std::regex* pRegex, void (*pWebServerRequestHandler) ( HttpRequest* pHttpRequest, @@ -471,12 +470,9 @@ PathHandler::PathHandler(std::string method, std::string matchPath, * @return True if the path matches. */ bool PathHandler::match(std::string method, std::string path) { - if (method != m_method) { - return false; - } + if (method != m_method) return false; if (m_isRegex) { ESP_LOGD("PathHandler", "regex matching: %s with %s", m_textPattern.c_str(), path.c_str()); - return std::regex_search(path, *m_pRegex); } ESP_LOGD("PathHandler", "plain matching: %s with %s", m_textPattern.c_str(), path.c_str()); @@ -490,10 +486,6 @@ bool PathHandler::match(std::string method, std::string path) { * @param [in] response An object representing the response. * @return N/A. */ -void PathHandler::invokePathHandler(HttpRequest* request, HttpResponse *response) { +void PathHandler::invokePathHandler(HttpRequest* request, HttpResponse* response) { m_pRequestHandler(request, response); } // invokePathHandler - - - - diff --git a/cpp_utils/HttpServer.h b/cpp_utils/HttpServer.h index 95558c05..8baa7bbb 100644 --- a/cpp_utils/HttpServer.h +++ b/cpp_utils/HttpServer.h @@ -83,7 +83,7 @@ class HttpServer { void setDirectoryListing(bool use); // Should we list the content of directories? void setFileBufferSize(size_t fileBufferSize); // Set the size of the file buffer void setRootPath(std::string path); // Set the root of the file system path. - void start(uint16_t portNumber, bool useSSL=false); + void start(uint16_t portNumber, bool useSSL = false); void stop(); // Stop a previously started server. private: diff --git a/cpp_utils/I2C.cpp b/cpp_utils/I2C.cpp index 96618bc2..d2413bae 100644 --- a/cpp_utils/I2C.cpp +++ b/cpp_utils/I2C.cpp @@ -67,7 +67,7 @@ void I2C::endTransaction() { ESP_LOGE(LOG_TAG, "i2c_master_stop: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } - errRc = ::i2c_master_cmd_begin(m_portNum, m_cmd, 1000/portTICK_PERIOD_MS); + errRc = ::i2c_master_cmd_begin(m_portNum, m_cmd, 1000 / portTICK_PERIOD_MS); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "i2c_master_cmd_begin: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } @@ -81,8 +81,7 @@ void I2C::endTransaction() { * * @return The address of the %I2C slave. */ -uint8_t I2C::getAddress() const -{ +uint8_t I2C::getAddress() const { return m_address; } @@ -95,7 +94,7 @@ uint8_t I2C::getAddress() const * @param [in] sclPin The pin to use for SCL clock. * @return N/A. */ -void I2C::init(uint8_t address, gpio_num_t sdaPin, gpio_num_t sclPin, uint32_t clockSpeed, i2c_port_t portNum) { +void I2C::init(uint8_t address, gpio_num_t sdaPin, gpio_num_t sclPin, uint32_t clockSpeed, i2c_port_t portNum, bool pullup) { ESP_LOGD(LOG_TAG, ">> I2c::init. address=%d, sda=%d, scl=%d, clockSpeed=%d, portNum=%d", address, sdaPin, sclPin, clockSpeed, portNum); assert(portNum < I2C_NUM_MAX); m_portNum = portNum; @@ -107,9 +106,9 @@ void I2C::init(uint8_t address, gpio_num_t sdaPin, gpio_num_t sclPin, uint32_t c conf.mode = I2C_MODE_MASTER; conf.sda_io_num = sdaPin; conf.scl_io_num = sclPin; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; - conf.master.clk_speed = 100000; + conf.sda_pullup_en = pullup ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + conf.scl_pullup_en = pullup ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE; + conf.master.clk_speed = clockSpeed; esp_err_t errRc = ::i2c_param_config(m_portNum, &conf); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "i2c_param_config: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); @@ -136,7 +135,7 @@ void I2C::read(uint8_t* bytes, size_t length, bool ack) { if (debug) { ESP_LOGD(LOG_TAG, "read(size=%d, ack=%d)", length, ack); } - if (m_directionKnown == false) { + if (!m_directionKnown) { m_directionKnown = true; esp_err_t errRc = ::i2c_master_write_byte(m_cmd, (m_address << 1) | I2C_MASTER_READ, !ack); if (errRc != ESP_OK) { @@ -157,11 +156,11 @@ void I2C::read(uint8_t* bytes, size_t length, bool ack) { * @param [in] ack Whether or not we should send an ACK to the slave after reading a byte. * @return N/A. */ -void I2C::read(uint8_t *byte, bool ack) { +void I2C::read(uint8_t* byte, bool ack) { if (debug) { ESP_LOGD(LOG_TAG, "read(size=1, ack=%d)", ack); } - if (m_directionKnown == false) { + if (!m_directionKnown) { m_directionKnown = true; esp_err_t errRc = ::i2c_master_write_byte(m_cmd, (m_address << 1) | I2C_MASTER_READ, !ack); if (errRc != ESP_OK) { @@ -180,12 +179,11 @@ void I2C::read(uint8_t *byte, bool ack) { * @return N/A. */ void I2C::scan() { - uint8_t i; printf("Data Pin: %d, Clock Pin: %d\n", this->m_sdaPin, this->m_sclPin); printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); printf("00: "); - for (i=3; i<0x78; i++) { - if (i%16 == 0) { + for (uint8_t i = 3; i < 0x78; i++) { + if (i % 16 == 0) { printf("\n%.2x:", i); } if (slavePresent(i)) { @@ -203,8 +201,7 @@ void I2C::scan() { * * @param [in] address The address of the %I2C slave. */ -void I2C::setAddress(uint8_t address) -{ +void I2C::setAddress(uint8_t address) { this->m_address = address; } // setAddress @@ -230,7 +227,7 @@ bool I2C::slavePresent(uint8_t address) { ::i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, 1 /* expect ack */); ::i2c_master_stop(cmd); - esp_err_t espRc = ::i2c_master_cmd_begin(m_portNum, cmd, 100/portTICK_PERIOD_MS); + esp_err_t espRc = ::i2c_master_cmd_begin(m_portNum, cmd, 100 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); return espRc == 0; // Return true if the slave is present and false otherwise. } // slavePresent @@ -279,7 +276,7 @@ void I2C::write(uint8_t byte, bool ack) { if (debug) { ESP_LOGD(LOG_TAG, "write(val=0x%.2x, ack=%d)", byte, ack); } - if (m_directionKnown == false) { + if (!m_directionKnown) { m_directionKnown = true; esp_err_t errRc = ::i2c_master_write_byte(m_cmd, (m_address << 1) | I2C_MASTER_WRITE, !ack); if (errRc != ESP_OK) { @@ -305,7 +302,7 @@ void I2C::write(uint8_t *bytes, size_t length, bool ack) { if (debug) { ESP_LOGD(LOG_TAG, "write(length=%d, ack=%d)", length, ack); } - if (m_directionKnown == false) { + if (!m_directionKnown) { m_directionKnown = true; esp_err_t errRc = ::i2c_master_write_byte(m_cmd, (m_address << 1) | I2C_MASTER_WRITE, !ack); if (errRc != ESP_OK) { @@ -317,5 +314,3 @@ void I2C::write(uint8_t *bytes, size_t length, bool ack) { ESP_LOGE(LOG_TAG, "i2c_master_write: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } } // write - - diff --git a/cpp_utils/I2C.h b/cpp_utils/I2C.h index 9886d63a..64b63427 100644 --- a/cpp_utils/I2C.h +++ b/cpp_utils/I2C.h @@ -17,14 +17,6 @@ * @brief Interface to %I2C functions. */ class I2C { -private: - uint8_t m_address; - i2c_cmd_handle_t m_cmd; - bool m_directionKnown; - gpio_num_t m_sdaPin; - gpio_num_t m_sclPin; - i2c_port_t m_portNum; - public: /** * @brief The default SDA pin. @@ -45,17 +37,26 @@ class I2C { void beginTransaction(); void endTransaction(); uint8_t getAddress() const; - void init(uint8_t address, gpio_num_t sdaPin = DEFAULT_SDA_PIN, gpio_num_t sclPin = DEFAULT_CLK_PIN, uint32_t clkSpeed = DEFAULT_CLK_SPEED, i2c_port_t portNum = I2C_NUM_0); - void read(uint8_t* bytes, size_t length, bool ack=true); - void read(uint8_t* byte, bool ack=true); + void init(uint8_t address, gpio_num_t sdaPin = DEFAULT_SDA_PIN, gpio_num_t sclPin = DEFAULT_CLK_PIN, uint32_t clkSpeed = DEFAULT_CLK_SPEED, i2c_port_t portNum = I2C_NUM_0, bool pullup = true); + void read(uint8_t* bytes, size_t length, bool ack = true); + void read(uint8_t* byte, bool ack = true); void scan(); void setAddress(uint8_t address); void setDebug(bool enabled); bool slavePresent(uint8_t address); void start(); void stop(); - void write(uint8_t byte, bool ack=true); - void write(uint8_t* bytes, size_t length, bool ack=true); + void write(uint8_t byte, bool ack = true); + void write(uint8_t* bytes, size_t length, bool ack = true); + +private: + uint8_t m_address; + i2c_cmd_handle_t m_cmd; + bool m_directionKnown; + gpio_num_t m_sdaPin; + gpio_num_t m_sclPin; + i2c_port_t m_portNum; + }; #endif /* MAIN_I2C_H_ */ diff --git a/cpp_utils/I2S.cpp b/cpp_utils/I2S.cpp index c5bcb997..15ba2fa7 100644 --- a/cpp_utils/I2S.cpp +++ b/cpp_utils/I2S.cpp @@ -27,7 +27,6 @@ static const char* LOG_TAG = "I2S"; static intr_handle_t i2s_intr_handle; - /** * A representation of a DMA buffer. */ @@ -67,6 +66,7 @@ DMABuffer::~DMABuffer() { delete[] m_desc.buf; } // ~DMABuffer + /** * @brief Dump the state of the buffer. * @return N/A @@ -74,7 +74,7 @@ DMABuffer::~DMABuffer() { void DMABuffer::dump() { std::ostringstream ss; ss << "size: " << m_desc.size; - ss << ", buf: 0x" << std::hex << (uint32_t)m_desc.buf << std::dec; + ss << ", buf: 0x" << std::hex << (uint32_t) m_desc.buf << std::dec; ss << ", length: " << m_desc.length; ss << ", offset: " << m_desc.offset; ss << ", sosf: " << m_desc.sosf; @@ -82,10 +82,8 @@ void DMABuffer::dump() { ss << ", owner: " << m_desc.owner; ESP_LOGD(LOG_TAG, "Desc: %s", ss.str().c_str()); int length = 100; - if (length > m_desc.length) { - length = m_desc.length; - } - GeneralUtils::hexDump((uint8_t*)m_desc.buf, length); + if (length > m_desc.length) length = m_desc.length; + GeneralUtils::hexDump((uint8_t*) m_desc.buf, length); } /** @@ -95,23 +93,15 @@ void DMABuffer::dump() { * @return The number of bytes actually copied. */ uint32_t DMABuffer::getData(uint8_t* pData, uint32_t length) { - uint8_t* pBuf = (uint8_t*)m_desc.buf; - if (length > getLength()) { - length = getLength(); - } + uint8_t* pBuf = (uint8_t*) m_desc.buf; + if (length > getLength()) length = getLength(); uint32_t i; - // // The descriptor buffer is filled with data that contains: - // // b1 00 b0 00 b3 00 b2 00 b5 00 b4 00 b7 00 b6 00 - // // Our goal is to populate the passed in buffer with data of the form: - // // b0 b1 b2 b3 b4 b5 b6 b7 ... - // // The following alogrithm does that. - // - for (i=0; igetDesc()); - pCurrentDMABuffer = pCurrentDMABuffer->getNext(); - I2S0.int_clr.val = I2S0.int_raw.val; - pI2S->m_dmaSemaphore.giveFromISR(); +static void IRAM_ATTR i2s_isr(void* arg) { + I2S* pI2S = (I2S*) arg; + //ESP_EARLY_LOGV(LOG_TAG, "I2S isr"); + pLastDMABuffer = pCurrentDMABuffer; + //logI2SIntr(); + //logDesc(pCurrentDMABuffer->getDesc()); + pCurrentDMABuffer = pCurrentDMABuffer->getNext(); + I2S0.int_clr.val = I2S0.int_raw.val; + pI2S->m_dmaSemaphore.giveFromISR(); } /** @@ -261,20 +246,20 @@ void I2S::cameraMode(dma_config_t config, int desc_count, int sample_count) { const uint32_t const_high = 0x38; - gpio_matrix_in(config.pin_d0, I2S0I_DATA_IN0_IDX, false); - gpio_matrix_in(config.pin_d1, I2S0I_DATA_IN1_IDX, false); - gpio_matrix_in(config.pin_d2, I2S0I_DATA_IN2_IDX, false); - gpio_matrix_in(config.pin_d3, I2S0I_DATA_IN3_IDX, false); - gpio_matrix_in(config.pin_d4, I2S0I_DATA_IN4_IDX, false); - gpio_matrix_in(config.pin_d5, I2S0I_DATA_IN5_IDX, false); - gpio_matrix_in(config.pin_d6, I2S0I_DATA_IN6_IDX, false); - gpio_matrix_in(config.pin_d7, I2S0I_DATA_IN7_IDX, false); - gpio_matrix_in(config.pin_vsync, I2S0I_V_SYNC_IDX, true); - gpio_matrix_in(config.pin_href, I2S0I_H_SYNC_IDX, false); - //gpio_matrix_in(const_high, I2S0I_V_SYNC_IDX, false); - //gpio_matrix_in(const_high, I2S0I_H_SYNC_IDX, false); - gpio_matrix_in(const_high, I2S0I_H_ENABLE_IDX, false); - gpio_matrix_in(config.pin_pclk, I2S0I_WS_IN_IDX, false); + gpio_matrix_in(config.pin_d0, I2S0I_DATA_IN0_IDX, false); + gpio_matrix_in(config.pin_d1, I2S0I_DATA_IN1_IDX, false); + gpio_matrix_in(config.pin_d2, I2S0I_DATA_IN2_IDX, false); + gpio_matrix_in(config.pin_d3, I2S0I_DATA_IN3_IDX, false); + gpio_matrix_in(config.pin_d4, I2S0I_DATA_IN4_IDX, false); + gpio_matrix_in(config.pin_d5, I2S0I_DATA_IN5_IDX, false); + gpio_matrix_in(config.pin_d6, I2S0I_DATA_IN6_IDX, false); + gpio_matrix_in(config.pin_d7, I2S0I_DATA_IN7_IDX, false); + gpio_matrix_in(config.pin_vsync, I2S0I_V_SYNC_IDX, true); + gpio_matrix_in(config.pin_href, I2S0I_H_SYNC_IDX, false); +// gpio_matrix_in(const_high, I2S0I_V_SYNC_IDX, false); +// gpio_matrix_in(const_high, I2S0I_H_SYNC_IDX, false); + gpio_matrix_in(const_high, I2S0I_H_ENABLE_IDX, false); + gpio_matrix_in(config.pin_pclk, I2S0I_WS_IN_IDX, false); // Enable and configure I2S peripheral periph_module_enable(PERIPH_I2S0_MODULE); @@ -345,10 +330,10 @@ void I2S::cameraMode(dma_config_t config, int desc_count, int sample_count) { ESP_LOGD(LOG_TAG, "Initializing %d descriptors", desc_count); - DMABuffer *pFirst = new DMABuffer(); - DMABuffer *pLast = pFirst; - for (int i=1; isetNext(pNewDMABuffer); pLast = pNewDMABuffer; } @@ -356,45 +341,45 @@ void I2S::cameraMode(dma_config_t config, int desc_count, int sample_count) { pCurrentDMABuffer = pFirst; // I2S_RX_EOF_NUM_REG - I2S0.rx_eof_num = sample_count; - - // I2S_IN_LINK_REG -> I2S_INLINK_ADDR - I2S0.in_link.addr = (uint32_t) pFirst; - - // I2S_IN_LINK_REG -> I2S_INLINK_START - I2S0.in_link.start = 1; - - I2S0.int_clr.val = I2S0.int_raw.val; - I2S0.int_ena.val = 0; - I2S0.int_ena.in_done = 1; - - // Register the interrupt handler. - esp_intr_alloc( - ETS_I2S0_INTR_SOURCE, - ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, - &i2s_isr, - this, - &i2s_intr_handle); - - m_dmaSemaphore.take(); - // Start the interrupt handler - esp_intr_enable(i2s_intr_handle); - - I2S0.conf.rx_start = 1; - - /* - while(1) { - m_dmaSemaphore.wait(); - uint32_t dataLength = pLastDMABuffer->getLength(); - ESP_LOGD(LOG_TAG, "Got a DMA buffer; length=%d", dataLength); - //pLastDMABuffer->dump(); - uint8_t *pData = new uint8_t[dataLength]; - pLastDMABuffer->getData(pData, dataLength); + I2S0.rx_eof_num = sample_count; + + // I2S_IN_LINK_REG -> I2S_INLINK_ADDR + I2S0.in_link.addr = (uint32_t) pFirst; + + // I2S_IN_LINK_REG -> I2S_INLINK_START + I2S0.in_link.start = 1; + + I2S0.int_clr.val = I2S0.int_raw.val; + I2S0.int_ena.val = 0; + I2S0.int_ena.in_done = 1; + + // Register the interrupt handler. + esp_intr_alloc( + ETS_I2S0_INTR_SOURCE, + ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, + &i2s_isr, + this, + &i2s_intr_handle); + + m_dmaSemaphore.take(); + // Start the interrupt handler + esp_intr_enable(i2s_intr_handle); + + I2S0.conf.rx_start = 1; + + /* + while(1) { + m_dmaSemaphore.wait(); + uint32_t dataLength = pLastDMABuffer->getLength(); + ESP_LOGD(LOG_TAG, "Got a DMA buffer; length=%d", dataLength); + //pLastDMABuffer->dump(); + uint8_t *pData = new uint8_t[dataLength]; + pLastDMABuffer->getData(pData, dataLength); GeneralUtils::hexDump(pData, dataLength); delete[] pData; m_dmaSemaphore.take(); - } - */ + } + */ ESP_LOGD(LOG_TAG, "<< cameraMode"); } diff --git a/cpp_utils/IFTTT.cpp b/cpp_utils/IFTTT.cpp index 0cf7a6d9..6af2279d 100644 --- a/cpp_utils/IFTTT.cpp +++ b/cpp_utils/IFTTT.cpp @@ -37,7 +37,7 @@ void IFTTT::trigger( std::string value2, std::string value3) { m_restClient.setURL("https://maker.ifttt.com/trigger/" + event + "/with/key/" + m_key); - cJSON *root; + cJSON* root; root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "value1", value1.c_str()); diff --git a/cpp_utils/JSON.cpp b/cpp_utils/JSON.cpp index c55f3a78..31f8cdb1 100644 --- a/cpp_utils/JSON.cpp +++ b/cpp_utils/JSON.cpp @@ -125,11 +125,8 @@ void JsonArray::addString(std::string value) { * @return The boolean value at the given index. */ bool JsonArray::getBoolean(int item) { - cJSON *node = cJSON_GetArrayItem(m_node, item); - if (node->valueint == 0) { - return false; - } - return true; + cJSON* node = cJSON_GetArrayItem(m_node, item); + return (node->valueint != 0); } // getBoolean @@ -139,7 +136,7 @@ bool JsonArray::getBoolean(int item) { * @return The double value at the given index. */ double JsonArray::getDouble(int item) { - cJSON *node = cJSON_GetArrayItem(m_node, item); + cJSON* node = cJSON_GetArrayItem(m_node, item); return node->valuedouble; } // getDouble @@ -150,7 +147,7 @@ double JsonArray::getDouble(int item) { * @return The int value at the given index. */ int JsonArray::getInt(int item) { - cJSON *node = cJSON_GetArrayItem(m_node, item); + cJSON* node = cJSON_GetArrayItem(m_node, item); return node->valueint; } // getInt @@ -161,7 +158,7 @@ int JsonArray::getInt(int item) { * @return The object value at the given index. */ JsonObject JsonArray::getObject(int item) { - cJSON *node = cJSON_GetArrayItem(m_node, item); + cJSON* node = cJSON_GetArrayItem(m_node, item); return JsonObject(node); } // getObject @@ -172,7 +169,7 @@ JsonObject JsonArray::getObject(int item) { * @return The object value at the given index. */ std::string JsonArray::getString(int item) { - cJSON *node = cJSON_GetArrayItem(m_node, item); + cJSON* node = cJSON_GetArrayItem(m_node, item); return std::string(node->valuestring); } // getString @@ -182,7 +179,7 @@ std::string JsonArray::getString(int item) { * @return A JSON string representation of the array. */ std::string JsonArray::toString() { - char *data = cJSON_Print(m_node); + char* data = cJSON_Print(m_node); std::string ret(data); free(data); return ret; @@ -194,7 +191,7 @@ std::string JsonArray::toString() { * @return A string representation. */ std::string JsonArray::toStringUnformatted() { - char *data = cJSON_PrintUnformatted(m_node); + char* data = cJSON_PrintUnformatted(m_node); std::string ret(data); free(data); return ret; @@ -217,7 +214,7 @@ JsonObject::JsonObject(cJSON* node) { } // JsonObject JsonArray JsonObject::getArray(std::string name) { - cJSON *node = cJSON_GetObjectItem(m_node, name.c_str()); + cJSON* node = cJSON_GetObjectItem(m_node, name.c_str()); return JsonArray(node); } @@ -228,10 +225,8 @@ JsonArray JsonObject::getArray(std::string name) { * @return The boolean value from the object. */ bool JsonObject::getBoolean(std::string name) { - cJSON *node = cJSON_GetObjectItem(m_node, name.c_str()); - if (node == nullptr) { - return false; - } + cJSON* node = cJSON_GetObjectItem(m_node, name.c_str()); + if (node == nullptr) return false; return cJSON_IsTrue(node); } // getBoolean @@ -242,10 +237,8 @@ bool JsonObject::getBoolean(std::string name) { * @return The double value from the object. */ double JsonObject::getDouble(std::string name) { - cJSON *node = cJSON_GetObjectItem(m_node, name.c_str()); - if (node == nullptr) { - return 0.0; - } + cJSON* node = cJSON_GetObjectItem(m_node, name.c_str()); + if (node == nullptr) return 0.0; return node->valuedouble; } // getDouble @@ -256,10 +249,8 @@ double JsonObject::getDouble(std::string name) { * @return The int value from the object. */ int JsonObject::getInt(std::string name) { - cJSON *node = cJSON_GetObjectItem(m_node, name.c_str()); - if (node == nullptr) { - return 0; - } + cJSON* node = cJSON_GetObjectItem(m_node, name.c_str()); + if (node == nullptr) return 0; return node->valueint; } // getInt @@ -270,7 +261,7 @@ int JsonObject::getInt(std::string name) { * @return The object value from the object. */ JsonObject JsonObject::getObject(std::string name) { - cJSON *node = cJSON_GetObjectItem(m_node, name.c_str()); + cJSON* node = cJSON_GetObjectItem(m_node, name.c_str()); return JsonObject(node); } // getObject @@ -281,10 +272,8 @@ JsonObject JsonObject::getObject(std::string name) { * @return The string value from the object. A zero length string is returned when the object is not present. */ std::string JsonObject::getString(std::string name) { - cJSON *node = cJSON_GetObjectItem(m_node, name.c_str()); - if (node == nullptr) { - return ""; - } + cJSON* node = cJSON_GetObjectItem(m_node, name.c_str()); + if (node == nullptr) return ""; return std::string(node->valuestring); } // getString @@ -325,7 +314,7 @@ void JsonObject::setArray(std::string name, JsonArray array) { * @return N/A. */ void JsonObject::setBoolean(std::string name, bool value) { - cJSON_AddItemToObject(m_node, name.c_str(), value?cJSON_CreateTrue():cJSON_CreateFalse()); + cJSON_AddItemToObject(m_node, name.c_str(), value ? cJSON_CreateTrue() : cJSON_CreateFalse()); } // setBoolean @@ -347,7 +336,7 @@ void JsonObject::setDouble(std::string name, double value) { * @return N/A. */ void JsonObject::setInt(std::string name, int value) { - cJSON_AddItemToObject(m_node, name.c_str(), cJSON_CreateNumber((double)value)); + cJSON_AddItemToObject(m_node, name.c_str(), cJSON_CreateNumber((double) value)); } // setInt @@ -378,7 +367,7 @@ void JsonObject::setString(std::string name, std::string value) { * @return A JSON string representation of the object. */ std::string JsonObject::toString() { - char *data = cJSON_Print(m_node); + char* data = cJSON_Print(m_node); std::string ret(data); free(data); return ret; @@ -390,7 +379,7 @@ std::string JsonObject::toString() { * @return A string representation. */ std::string JsonObject::toStringUnformatted() { - char *data = cJSON_PrintUnformatted(m_node); + char* data = cJSON_PrintUnformatted(m_node); std::string ret(data); free(data); return ret; diff --git a/cpp_utils/JSON.h b/cpp_utils/JSON.h index 13f8f0a2..f132a0a7 100644 --- a/cpp_utils/JSON.h +++ b/cpp_utils/JSON.h @@ -25,6 +25,7 @@ class JSON { static void deleteArray(JsonArray jsonArray); static JsonObject parseObject(std::string text); static JsonArray parseArray(std::string text); + }; // JSON @@ -33,7 +34,6 @@ class JSON { */ class JsonArray { public: - int getInt(int item); JsonObject getObject(int item); std::string getString(int item); @@ -47,6 +47,7 @@ class JsonArray { std::string toString(); std::string toStringUnformatted(); std::size_t size(); + private: JsonArray(cJSON* node); friend class JSON; @@ -54,7 +55,8 @@ class JsonArray { /** * @brief The underlying cJSON node. */ - cJSON *m_node; + cJSON* m_node; + }; // JsonArray @@ -88,6 +90,7 @@ class JsonObject { * @brief The underlying cJSON node. */ cJSON* m_node; + }; // JsonObject diff --git a/cpp_utils/MAX7219.cpp b/cpp_utils/MAX7219.cpp index d83615d9..4cac347d 100644 --- a/cpp_utils/MAX7219.cpp +++ b/cpp_utils/MAX7219.cpp @@ -76,7 +76,7 @@ const static uint8_t charTable[] = { 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000 }; -MAX7219::MAX7219(SPI *spi, int numDevices) { +MAX7219::MAX7219(SPI* spi, int numDevices) { assert(spi != nullptr); this->spi = spi; if (numDevices <= 0 || numDevices > 8) { @@ -84,7 +84,7 @@ MAX7219::MAX7219(SPI *spi, int numDevices) { } maxDevices = numDevices; - for (int i = 0; i < 64; i++) { + for (uint8_t i = 0; i < 64; i++) { status[i] = 0x00; } for (int i = 0; i < maxDevices; i++) { @@ -106,21 +106,18 @@ int MAX7219::getDeviceCount() { void MAX7219::shutdown(bool b, int addr) { - if (addr < 0 || addr >= maxDevices) - return; + if (addr < 0 || addr >= maxDevices) return; + if (b) { spiTransfer(addr, OP_SHUTDOWN, 0); - } - else { + } else { spiTransfer(addr, OP_SHUTDOWN, 1); } } void MAX7219::setScanLimit(int limit, int addr) { - if (addr < 0 || addr >= maxDevices) { - return; - } + if (addr < 0 || addr >= maxDevices) return; if (limit >= 0 && limit < 8) { spiTransfer(addr, OP_SCANLIMIT, limit); } @@ -128,9 +125,7 @@ void MAX7219::setScanLimit(int limit, int addr) { void MAX7219::setIntensity(int intensity, int addr) { - if (addr < 0 || addr >= maxDevices) { - return; - } + if (addr < 0 || addr >= maxDevices) return; if (intensity >= 0 && intensity < 16) { spiTransfer(addr, OP_INTENSITY, intensity); } @@ -138,13 +133,11 @@ void MAX7219::setIntensity(int intensity, int addr) { void MAX7219::clearDisplay(int addr) { - int offset; + if (addr < 0 || addr >= maxDevices) return; - if (addr < 0 || addr >= maxDevices) { - return; - } + int offset; offset = addr * 8; - for (int i = 0; i < 8; i++) { + for (uint8_t i = 0; i < 8; i++) { status[offset + i] = 0; spiTransfer(addr, i + 1, status[offset + i]); } @@ -152,12 +145,11 @@ void MAX7219::clearDisplay(int addr) { void MAX7219::setLed(int row, int column, bool state, int addr) { + if (addr < 0 || addr >= maxDevices) return; + int offset; - uint8_t val = 0x00; + uint8_t val = 0; - if (addr < 0 || addr >= maxDevices) { - return; - } if (row < 0 || row > 7 || column < 0 || column > 7) { return; } @@ -165,8 +157,7 @@ void MAX7219::setLed(int row, int column, bool state, int addr) { val = 0b10000000 >> column; if (state) { status[offset + row] = status[offset + row] | val; - } - else { + } else { val = ~val; status[offset + row] = status[offset + row] & val; } @@ -175,28 +166,20 @@ void MAX7219::setLed(int row, int column, bool state, int addr) { void MAX7219::setRow(int row, uint8_t value, int addr) { - int offset; - if (addr < 0 || addr >= maxDevices) { - return; - } - if (row < 0 || row > 7) { - return; - } - offset = addr * 8; + if (addr < 0 || addr >= maxDevices) return; + if (row < 0 || row > 7) return; + + int offset = addr * 8; status[offset + row] = value; spiTransfer(addr, row + 1, status[offset + row]); } void MAX7219::setColumn(int col, uint8_t value, int addr) { - uint8_t val; + if (addr < 0 || addr >= maxDevices) return; + if (col < 0 || col > 7) return; - if (addr < 0 || addr >= maxDevices) { - return; - } - if (col < 0 || col > 7) { - return; - } + uint8_t val; for (int row = 0; row < 8; row++) { val = value >> (7 - row); val = val & 0x01; @@ -206,17 +189,11 @@ void MAX7219::setColumn(int col, uint8_t value, int addr) { void MAX7219::setDigit(int digit, uint8_t value, bool dp, int addr) { - int offset; - uint8_t v; + if (addr < 0 || addr >= maxDevices) return; + if (digit < 0 || digit > 7 || value > 15) return; - if (addr < 0 || addr >= maxDevices) { - return; - } - if (digit < 0 || digit > 7 || value > 15) { - return; - } - offset = addr * 8; - v = charTable[value]; + int offset = addr * 8; + uint8_t v = charTable[value]; if (dp) { v |= 0b10000000; } @@ -226,22 +203,13 @@ void MAX7219::setDigit(int digit, uint8_t value, bool dp, int addr) { void MAX7219::setChar(int digit, char value, bool dp, int addr) { - int offset; - uint8_t index, v; + if (addr < 0 || addr >= maxDevices) return; + if (digit < 0 || digit > 7) return; - if (addr < 0 || addr >= maxDevices) { - return; - } - if (digit < 0 || digit > 7) { - return; - } - offset = addr * 8; - index = (uint8_t) value; - if (index > 127) { - //no defined beyond index 127, so we use the space char - index = 32; - } - v = charTable[index]; + int offset = addr * 8; + uint8_t index = (uint8_t) value; + if (index > 127) index = 32; // not defined beyond index 127, so we use the space char + uint8_t v = charTable[index]; if (dp) { v |= 0b10000000; } @@ -250,7 +218,7 @@ void MAX7219::setChar(int digit, char value, bool dp, int addr) { } -void MAX7219::spiTransfer(int addr, volatile uint8_t opcode, volatile uint8_t data) { +void MAX7219::spiTransfer(int addr, volatile uint8_t opcode, volatile uint8_t data) { //Create an array with the data to shift out int offset = addr * 2; int maxbytes = maxDevices * 2; @@ -268,13 +236,13 @@ void MAX7219::spiTransfer(int addr, volatile uint8_t opcode, volatile uint8_t da } void MAX7219::setNumber(uint32_t number, int addr) { - //number = number % (uint32_t)pow(10, maxDevices); - for (auto i=0; i<8; i++) { - if (number == 0 && i > 0){ + // number = number % (uint32_t) pow(10, maxDevices); + for (uint8_t i = 0; i < 8; i++) { + if (number == 0 && i > 0) { setChar(i, ' ', addr); } else { - setDigit(i, number%10, addr); - number = number/10; + setDigit(i, number % 10, addr); + number = number / 10; } } } diff --git a/cpp_utils/MAX7219.h b/cpp_utils/MAX7219.h index b5ae41f4..d3faf353 100644 --- a/cpp_utils/MAX7219.h +++ b/cpp_utils/MAX7219.h @@ -50,18 +50,6 @@ * and setColumn(). */ class MAX7219 { -private: - - /* Send out a single command to the device */ - void spiTransfer(int addr, uint8_t opcode, uint8_t data); - - /* We keep track of the led-status for all 8 devices in this array */ - uint8_t status[64]; - - /* The maximum number of devices we use */ - int maxDevices; - SPI *spi; - public: /** * @brief Create a new %MAX7219 controller @@ -70,7 +58,7 @@ class MAX7219 { * @param [in] numDevices maximum number of devices that can be controlled that are * daisy chained together. */ - MAX7219(SPI *spi, int numDevices = 1); + MAX7219(SPI* spi, int numDevices = 1); /** @@ -101,7 +89,7 @@ class MAX7219 { * @param [in] dp Sets the decimal point. * @param [in] addr Address of the display. */ - void setChar(int digit, char value, bool dp=false, int addr=0); + void setChar(int digit, char value, bool dp=false, int addr = 0); /** @@ -111,7 +99,7 @@ class MAX7219 { * @param [in] value each bit set to 1 will light up the corresponding Led. * @param [in] addr address of the display. */ - void setColumn(int col, uint8_t value, int addr=0); + void setColumn(int col, uint8_t value, int addr = 0); /** @@ -122,7 +110,7 @@ class MAX7219 { * @param [in] dp Sets the decimal point. * @param [in] addr Address of the display. */ - void setDigit(int digit, uint8_t value, bool dp=false, int addr=0); + void setDigit(int digit, uint8_t value, bool dp=false, int addr = 0); /** @@ -131,7 +119,7 @@ class MAX7219 { * @param [in] intensity the brightness of the display. (0..15). * @param [in] addr The address of the display to control. */ - void setIntensity(int intensity, int addr=0); + void setIntensity(int intensity, int addr = 0); /** @@ -142,7 +130,7 @@ class MAX7219 { * @param [in] state If true the led is switched on, if false it is switched off. * @param [in] addr Address of the display. */ - void setLed(int row, int col, bool state, int addr=0); + void setLed(int row, int col, bool state, int addr = 0); /** @@ -153,7 +141,7 @@ class MAX7219 { * @param [in] number The number to display. * @param [in] addr Address of the display. */ - void setNumber(uint32_t number, int addr=0); + void setNumber(uint32_t number, int addr = 0); /** @@ -163,7 +151,7 @@ class MAX7219 { * @param [in] value Each bit set to 1 will light up the corresponding Led. * @param [in] addr Address of the display. */ - void setRow(int row, uint8_t value, int addr=0); + void setRow(int row, uint8_t value, int addr = 0); /** @@ -175,7 +163,7 @@ class MAX7219 { * @param [in] limit Number of digits to be displayed (1..8). * @param [in] addr Address of the display to control. */ - void setScanLimit(int limit, int addr=0); + void setScanLimit(int limit, int addr = 0); /** @@ -185,7 +173,18 @@ class MAX7219 { * for normal operation. * @param [in] addr The address of the display to control. */ - void shutdown(bool status, int addr=0); + void shutdown(bool status, int addr = 0); + +private: + /* Send out a single command to the device */ + void spiTransfer(int addr, uint8_t opcode, uint8_t data); + + /* We keep track of the led-status for all 8 devices in this array */ + uint8_t status[64]; + + /* The maximum number of devices we use */ + int maxDevices; + SPI* spi; }; diff --git a/cpp_utils/MFRC522.cpp b/cpp_utils/MFRC522.cpp index a860e9ba..940c170c 100644 --- a/cpp_utils/MFRC522.cpp +++ b/cpp_utils/MFRC522.cpp @@ -18,8 +18,8 @@ #include "MFRC522.h" #include "MFRC522Debug.h" -#include -#include +#include "FreeRTOS.h" +#include "GPIO.h" #include #include #include @@ -41,29 +41,37 @@ static const char LOG_TAG[] = "MFRC522"; /** * Writes a byte to the specified register in the MFRC522 chip. * The interface is described in the datasheet section 8.1.2. + * @param reg The register to write to. One of the PCD_Register enums. + * @param value The value to write. */ -void MFRC522::PCD_WriteRegister( - PCD_Register reg, ///< The register to write to. One of the PCD_Register enums. - byte value ///< The value to write. - ) { +void MFRC522::PCD_WriteRegister(PCD_Register reg, byte value) { uint8_t data[2]; data[0] = reg; data[1] = value; + + ESP32CPP::GPIO::low((gpio_num_t)_chipSelectPin); // Select slave m_spi.transfer(data, 2); + ESP32CPP::GPIO::high((gpio_num_t)_chipSelectPin); // Release slave + } // End PCD_WriteRegister() + /** * Writes a number of bytes to the specified register in the MFRC522 chip. * The interface is described in the datasheet section 8.1.2. + * @param reg The register to write to. One of the PCD_Register enums. + * @param count The number of bytes to write to the register + * @param values The values to write. Byte array. */ -void MFRC522::PCD_WriteRegister( PCD_Register reg, ///< The register to write to. One of the PCD_Register enums. - byte count, ///< The number of bytes to write to the register - byte *values ///< The values to write. Byte array. - ) { - uint8_t* pData = new uint8_t[count+1]; +void MFRC522::PCD_WriteRegister(PCD_Register reg, byte count, byte* values) { + uint8_t* pData = new uint8_t[count + 1]; pData[0] = reg; - memcpy(pData+1, values, count); - m_spi.transfer(pData, count+1); + memcpy(pData + 1, values, count); + + ESP32CPP::GPIO::low((gpio_num_t)_chipSelectPin); // Select slave + m_spi.transfer(pData, count + 1); + ESP32CPP::GPIO::high((gpio_num_t)_chipSelectPin); // Release slave + delete[] pData; } // End PCD_WriteRegister() @@ -71,32 +79,38 @@ void MFRC522::PCD_WriteRegister( PCD_Register reg, ///< The register to write to /** * Reads a byte from the specified register in the MFRC522 chip. * The interface is described in the datasheet section 8.1.2. + * @param reg The register to read from. One of the PCD_Register enums. */ -byte MFRC522::PCD_ReadRegister( PCD_Register reg ///< The register to read from. One of the PCD_Register enums. - ) { +byte MFRC522::PCD_ReadRegister(PCD_Register reg) { uint8_t data[2]; data[0] = reg | 0x80; data[1] = 0; + + ESP32CPP::GPIO::low((gpio_num_t)_chipSelectPin); // Select slave m_spi.transfer(data, 2); + ESP32CPP::GPIO::high((gpio_num_t)_chipSelectPin); // Release slave + return data[1]; } // End PCD_ReadRegister() + /** * Reads a number of bytes from the specified register in the MFRC522 chip. * The interface is described in the datasheet section 8.1.2. + * @param reg The register to read from. One of the PCD_Register enums. + * @param count The number of bytes to read + * @param values Byte array to store the values in. + * @param rxAlign Only bit positions rxAlign..7 in values[0] are updated. */ -void MFRC522::PCD_ReadRegister( PCD_Register reg, ///< The register to read from. One of the PCD_Register enums. - byte count, ///< The number of bytes to read - byte *values, ///< Byte array to store the values in. - byte rxAlign ///< Only bit positions rxAlign..7 in values[0] are updated. - ) { - if (count == 0) { - return; - } +void MFRC522::PCD_ReadRegister(PCD_Register reg, byte count, byte* values, byte rxAlign) { + if (count == 0) return; + //Serial.print(F("Reading ")); Serial.print(count); Serial.println(F(" bytes from register.")); byte address = 0x80 | reg; // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. byte index = 0; // Index in values array. count--; // One read is performed outside of the loop + + ESP32CPP::GPIO::low((gpio_num_t)_chipSelectPin); // Select slave m_spi.transferByte(address); // Tell MFRC522 which address we want to read if (rxAlign) { // Only update bit positions rxAlign..7 in values[0] // Create bit mask for bit positions rxAlign..7 @@ -112,25 +126,28 @@ void MFRC522::PCD_ReadRegister( PCD_Register reg, ///< The register to read from index++; } values[index] = m_spi.transferByte(0); // Read the final byte. Send 0 to stop reading. + ESP32CPP::GPIO::high((gpio_num_t)_chipSelectPin); // Release slave } // End PCD_ReadRegister() + /** * Sets the bits given in mask in register reg. + * @param reg The register to update. One of the PCD_Register enums. + * @param mask The bits to set. */ -void MFRC522::PCD_SetRegisterBitMask( PCD_Register reg, ///< The register to update. One of the PCD_Register enums. - byte mask ///< The bits to set. - ) { +void MFRC522::PCD_SetRegisterBitMask(PCD_Register reg, byte mask) { byte tmp; tmp = PCD_ReadRegister(reg); - PCD_WriteRegister(reg, tmp | mask); // set bit mask + PCD_WriteRegister(reg, tmp | mask); // set bit mask } // End PCD_SetRegisterBitMask() + /** * Clears the bits given in mask from register reg. + * @param reg The register to update. One of the PCD_Register enums. + * @param mask The bits to clear. */ -void MFRC522::PCD_ClearRegisterBitMask( PCD_Register reg, ///< The register to update. One of the PCD_Register enums. - byte mask ///< The bits to clear. - ) { +void MFRC522::PCD_ClearRegisterBitMask(PCD_Register reg, byte mask) { byte tmp; tmp = PCD_ReadRegister(reg); PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask @@ -139,13 +156,12 @@ void MFRC522::PCD_ClearRegisterBitMask( PCD_Register reg, ///< The register to u /** * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. - * + * @param data In: Pointer to the data to transfer to the FIFO for CRC calculation. + * @param length In: The number of bytes to transfer. + * @param result Out: Pointer to result buffer. Result is written to result[0..1], low byte first. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. - byte length, ///< In: The number of bytes to transfer. - byte *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low byte first. - ) { +MFRC522::StatusCode MFRC522::PCD_CalculateCRC(byte* data, byte length, byte* result) { PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization @@ -159,7 +175,7 @@ MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to for (uint16_t i = 5000; i > 0; i--) { // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved byte n = PCD_ReadRegister(DivIrqReg); - if (n & 0x04) { // CRCIRq bit set - calculation done + if (n & 0x04) { // CRCIRq bit set - calculation done PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. // Transfer the result from the registers to the result buffer result[0] = PCD_ReadRegister(CRCResultRegL); @@ -172,32 +188,31 @@ MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to } // End PCD_CalculateCRC() -///////////////////////////////////////////////////////////////////////////////////// // Functions for manipulating the MFRC522 -///////////////////////////////////////////////////////////////////////////////////// + /** * Initializes the MFRC522 chip. */ void MFRC522::PCD_Init() { //m_spi.setHost(VSPI_HOST); + + ESP32CPP::GPIO::setOutput((gpio_num_t)_chipSelectPin); m_spi.init(); bool hardReset = false; - // Set the chipSelectPin as digital output, do not select the slave yet -/* - pinMode(_chipSelectPin, OUTPUT); - digitalWrite(_chipSelectPin, HIGH); -*/ + // pinMode(_chipSelectPin, OUTPUT); + // digitalWrite(_chipSelectPin, HIGH); + // If a valid pin number has been set, pull device out of power down / reset state. if (_resetPowerDownPin != UNUSED_PIN) { // Set the resetPowerDownPin as digital output, do not reset or power down. //pinMode(_resetPowerDownPin, OUTPUT); ESP32CPP::GPIO::setInput((gpio_num_t)_resetPowerDownPin); - if (ESP32CPP::GPIO::read((gpio_num_t)_resetPowerDownPin) == false) { // The MFRC522 chip is in power down mode. + if (!ESP32CPP::GPIO::read((gpio_num_t)_resetPowerDownPin)) { // The MFRC522 chip is in power down mode. ESP32CPP::GPIO::setOutput((gpio_num_t)_resetPowerDownPin); ESP32CPP::GPIO::high((gpio_num_t)_resetPowerDownPin); // Exit power down mode. This triggers a hard reset. // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms. @@ -221,27 +236,30 @@ void MFRC522::PCD_Init() { // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]. // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg. PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds - PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25μs. PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. + PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25μs. + PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. PCD_WriteRegister(TReloadRegL, 0xE8); - PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting + PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) - PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) + PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) } // End PCD_Init() + /** * Initializes the MFRC522 chip. + * @param chipSelectPin Pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) + * @param resetPowerDownPin Pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) */ -void MFRC522::PCD_Init( byte chipSelectPin, ///< Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) - byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) - ) { +void MFRC522::PCD_Init(byte chipSelectPin, byte resetPowerDownPin) { _chipSelectPin = chipSelectPin; _resetPowerDownPin = resetPowerDownPin; // Set the chipSelectPin as digital output, do not select the slave yet PCD_Init(); } // End PCD_Init() + /** * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. */ @@ -252,11 +270,12 @@ void MFRC522::PCD_Reset() { // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms. FreeRTOS::sleep(50); // Wait for the PowerDown bit in CommandReg to be cleared - while (PCD_ReadRegister(CommandReg) & (1<<4)) { + while (PCD_ReadRegister(CommandReg) & (1 << 4)) { // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry. } } // End PCD_Reset() + /** * Turns the antenna on by enabling pins TX1 and TX2. * After a reset these pins are disabled. @@ -268,6 +287,7 @@ void MFRC522::PCD_AntennaOn() { } } // End PCD_AntennaOn() + /** * Turns the antenna off by disabling pins TX1 and TX2. */ @@ -275,6 +295,7 @@ void MFRC522::PCD_AntennaOff() { PCD_ClearRegisterBitMask(TxControlReg, 0x03); } // End PCD_AntennaOff() + /** * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf @@ -283,21 +304,23 @@ void MFRC522::PCD_AntennaOff() { * @return Value of the RxGain, scrubbed to the 3 bits used. */ byte MFRC522::PCD_GetAntennaGain() { - return PCD_ReadRegister(RFCfgReg) & (0x07<<4); + return PCD_ReadRegister(RFCfgReg) & (0x07 << 4); } // End PCD_GetAntennaGain() + /** * Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf * NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. */ void MFRC522::PCD_SetAntennaGain(byte mask) { - if (PCD_GetAntennaGain() != mask) { // only bother if there is a change - PCD_ClearRegisterBitMask(RFCfgReg, (0x07<<4)); // clear needed to allow 000 pattern + if (PCD_GetAntennaGain() != mask) { // only bother if there is a change + PCD_ClearRegisterBitMask(RFCfgReg, (0x07 << 4)); // clear needed to allow 000 pattern PCD_SetRegisterBitMask(RFCfgReg, mask & (0x07<<4)); // only set RxGain[2:0] bits } } // End PCD_SetAntennaGain() + /** * Performs a self-test of the MFRC522 * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf @@ -335,9 +358,7 @@ bool MFRC522::PCD_PerformSelfTest() { // It is reported that some devices does not trigger CRCIRq flag // during selftest. n = PCD_ReadRegister(FIFOLevelReg); - if (n >= 64) { - break; - } + if (n >= 64) break; } PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. @@ -373,9 +394,7 @@ bool MFRC522::PCD_PerformSelfTest() { // Verify that the results match up to our expectations for (uint8_t i = 0; i < 64; i++) { - if (result[i] != (reference[i])) { - return false; - } + if (result[i] != (reference[i])) return false; } // Test passed; all is good. @@ -383,45 +402,47 @@ bool MFRC522::PCD_PerformSelfTest() { } // End PCD_PerformSelfTest() ///////////////////////////////////////////////////////////////////////////////////// + // Functions for communicating with PICCs ///////////////////////////////////////////////////////////////////////////////////// + /** * Executes the Transceive command. * CRC validation can only be done if backData and backLen are specified. - * + * @param sendData Pointer to the data to transfer to the FIFO. + * @param sendLen Number of bytes to transfer to the FIFO. + * @param backData nullptr or pointer to buffer if data should be read back after executing the command. + * @param backLen In: Max number of bytes to write to *backData. Out: The number of bytes returned. + * @param validBits In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default nullptr. + * @param rxAlign In: Defines the bit position in backData[0] for the first bit received. Default 0. + * @param checkCRC In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO. - byte sendLen, ///< Number of bytes to transfer to the FIFO. - byte *backData, ///< nullptr or pointer to buffer if data should be read back after executing the command. - byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. - byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default nullptr. - byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. - ) { +MFRC522::StatusCode MFRC522::PCD_TransceiveData(byte* sendData, byte sendLen, byte* backData, byte* backLen, byte* validBits, byte rxAlign, bool checkCRC) { byte waitIRq = 0x30; // RxIRq and IdleIRq return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC); } // End PCD_TransceiveData() + /** * Transfers data to the MFRC522 FIFO, executes a command, waits for completion and transfers data back from the FIFO. * CRC validation can only be done if backData and backLen are specified. * + * @param command The command to execute. One of the PCD_Command enums. + * @param waitIRq The bits in the ComIrqReg register that signals successful completion of the command. + * @param sendData Pointer to the data to transfer to the FIFO. + * @param sendLen Number of bytes to transfer to the FIFO. + * @param backData nullptr or pointer to buffer if data should be read back after executing the command. + * @param backLen In: Max number of bytes to write to *backData. Out: The number of bytes returned. + * @param validBits In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. + * @param rxAlign In: Defines the bit position in backData[0] for the first bit received. Default 0. + * @param checkCRC In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The command to execute. One of the PCD_Command enums. - byte waitIRq, ///< The bits in the ComIrqReg register that signals successful completion of the command. - byte *sendData, ///< Pointer to the data to transfer to the FIFO. - byte sendLen, ///< Number of bytes to transfer to the FIFO. - byte *backData, ///< nullptr or pointer to buffer if data should be read back after executing the command. - byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. - byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. - byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. - bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. - ) { +MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC(byte command, byte waitIRq, byte* sendData, byte sendLen, byte* backData, byte* backLen, byte* validBits, byte rxAlign, bool checkCRC) { // Prepare values for BitFramingReg - byte txLastBits = validBits ? *validBits : 0; + byte txLastBits = validBits ? *validBits : (byte) 0; byte bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. @@ -449,9 +470,7 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co } } // 35.7ms and nothing happend. Communication with the MFRC522 might be down. - if (i == 0) { - return STATUS_TIMEOUT; - } + if (i == 0) return STATUS_TIMEOUT; // Stop now if any errors except collisions were detected. byte errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr @@ -464,10 +483,8 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co // If the caller wants data back, get it from the MFRC522. if (backData && backLen) { byte n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO - if (n > *backLen) { - return STATUS_NO_ROOM; - } - *backLen = n; // Number of bytes returned + if (n > *backLen) return STATUS_NO_ROOM; + *backLen = n; // Number of bytes returned PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO _validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid. if (validBits) { @@ -483,19 +500,13 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co // Perform CRC_A validation if requested. if (backData && backLen && checkCRC) { // In this case a MIFARE Classic NAK is not OK. - if (*backLen == 1 && _validBits == 4) { - return STATUS_MIFARE_NACK; - } + if (*backLen == 1 && _validBits == 4) return STATUS_MIFARE_NACK; // We need at least the CRC_A value and all 8 bits of the last byte must be received. - if (*backLen < 2 || _validBits != 0) { - return STATUS_CRC_WRONG; - } + if (*backLen < 2 || _validBits != 0) return STATUS_CRC_WRONG; // Verify CRC_A - do our own calculation and store the control in controlBuffer. byte controlBuffer[2]; MFRC522::StatusCode status = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); - if (status != STATUS_OK) { - return status; - } + if (status != STATUS_OK) return status; if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) { return STATUS_CRC_WRONG; } @@ -504,58 +515,57 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co return STATUS_OK; } // End PCD_CommunicateWithPICC() + /** * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. * + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PICC_RequestA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in - byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. - ) { +MFRC522::StatusCode MFRC522::PICC_RequestA(byte* bufferATQA, byte* bufferSize) { return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); } // End PICC_RequestA() + /** * Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. * + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in - byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. - ) { +MFRC522::StatusCode MFRC522::PICC_WakeupA(byte* bufferATQA, byte* bufferSize) { return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize); } // End PICC_WakeupA() + /** * Transmits REQA or WUPA commands. * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. * + * @param command The command to send - PICC_CMD_REQA or PICC_CMD_WUPA + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA - byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in - byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. - ) { +MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA(byte command, byte* bufferATQA, byte* bufferSize) { byte validBits; MFRC522::StatusCode status; - if (bufferATQA == nullptr || *bufferSize < 2) { // The ATQA response is 2 bytes long. - return STATUS_NO_ROOM; - } PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] + if (bufferATQA == nullptr || *bufferSize < 2) return STATUS_NO_ROOM; // The ATQA response is 2 bytes long. status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits); - if (status != STATUS_OK) { - return status; - } - if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits. - return STATUS_ERROR; - } + if (status != STATUS_OK) return status; + + if (*bufferSize != 2 || validBits != 0) return STATUS_ERROR; // ATQA must be exactly 16 bits. return STATUS_OK; } // End PICC_REQA_or_WUPA() + /** * Transmits SELECT/ANTICOLLISION commands to select a single PICC. * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or PICC_WakeupA(). @@ -573,9 +583,7 @@ MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command * * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. - byte validBits ///< The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size. - ) { +MFRC522::StatusCode MFRC522::PICC_Select(Uid* uid, byte validBits) { bool uidComplete; bool selectDone; bool useCascadeTag; @@ -589,7 +597,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. - byte *responseBuffer; + byte* responseBuffer; byte responseLength; // Description of buffer structure: @@ -615,9 +623,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct // 3 uid6 uid7 uid8 uid9 // Sanity checks - if (validBits > 80) { - return STATUS_INVALID; - } + if (validBits > 80) return STATUS_INVALID; // Prepare MFRC522 PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. @@ -632,22 +638,18 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct uidIndex = 0; useCascadeTag = validBits && uid->size > 4; // When we know that the UID has more than 4 bytes break; - case 2: buffer[0] = PICC_CMD_SEL_CL2; uidIndex = 3; useCascadeTag = validBits && uid->size > 7; // When we know that the UID has more than 7 bytes break; - case 3: buffer[0] = PICC_CMD_SEL_CL3; uidIndex = 6; useCascadeTag = false; // Never used in CL3. break; - default: return STATUS_INTERNAL_ERROR; - break; } // How many UID bits are known in this Cascade Level? @@ -686,16 +688,13 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; // Calculate CRC_A result = PCD_CalculateCRC(buffer, 7, &buffer[7]); - if (result != STATUS_OK) { - return result; - } txLastBits = 0; // 0 => All 8 bits are valid. bufferUsed = 9; + if (result != STATUS_OK) return result; // Store response in the last 3 bytes of buffer (BCC and CRC_A - not needed after tx) responseBuffer = &buffer[6]; responseLength = 3; - } - else { // This is an ANTICOLLISION. + } else { // This is an ANTICOLLISION. //Serial.print(F("ANTICOLLISION: currentLevelKnownBits=")); Serial.println(currentLevelKnownBits, DEC); txLastBits = currentLevelKnownBits % 8; count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part. @@ -715,31 +714,25 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign); if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. byte valueOfCollReg = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] - if (valueOfCollReg & 0x20) { // CollPosNotValid - return STATUS_COLLISION; // Without a valid collision position we cannot continue - } + if (valueOfCollReg & 0x20) return STATUS_COLLISION; // CollPosNotValid, Without a valid collision position we cannot continue byte collisionPos = valueOfCollReg & 0x1F; // Values 0-31, 0 means bit 32. if (collisionPos == 0) { collisionPos = 32; } - if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen - return STATUS_INTERNAL_ERROR; - } + if (collisionPos <= currentLevelKnownBits) return STATUS_INTERNAL_ERROR; // No progress - should not happen + // Choose the PICC with the bit set. currentLevelKnownBits = collisionPos; count = (currentLevelKnownBits - 1) % 8; // The bit to modify index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First byte is index 0. buffer[index] |= (1 << count); } - else if (result != STATUS_OK) { - return result; - } + else if (result != STATUS_OK) return result; else { // STATUS_OK if (currentLevelKnownBits >= 32) { // This was a SELECT. selectDone = true; // No more anticollision // We continue below outside the while. - } - else { // This was an ANTICOLLISION. + } else { // This was an ANTICOLLISION. // We now have all 32 bits of the UID in this Cascade Level currentLevelKnownBits = 32; // Run loop again to do the SELECT. @@ -757,21 +750,18 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct } // Check response SAK (Select Acknowledge) - if (responseLength != 3 || txLastBits != 0) { // SAK must be exactly 24 bits (1 byte + CRC_A). - return STATUS_ERROR; - } + if (responseLength != 3 || txLastBits != 0) return STATUS_ERROR; // SAK must be exactly 24 bits (1 byte + CRC_A). + // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those bytes are not needed anymore. result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]); - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; + if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2])) { return STATUS_CRC_WRONG; } if (responseBuffer[0] & 0x04) { // Cascade bit set - UID not complete yes cascadeLevel++; - } - else { + } else { uidComplete = true; uid->sak = responseBuffer[0]; } @@ -783,6 +773,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct return STATUS_OK; } // End PICC_Select() + /** * Instructs a PICC in state ACTIVE(*) to go to state HALT. * @@ -797,9 +788,7 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { buffer[1] = 0; // Calculate CRC_A result = PCD_CalculateCRC(buffer, 2, &buffer[2]); - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; // Send the command. // The standard says: @@ -807,12 +796,10 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { // HLTA command, this response shall be interpreted as 'not acknowledge'. // We interpret that this way: Only STATUS_TIMEOUT is a success. result = PCD_TransceiveData(buffer, sizeof(buffer), nullptr, 0); - if (result == STATUS_TIMEOUT) { - return STATUS_OK; - } - if (result == STATUS_OK) { // That is ironically NOT ok in this case ;-) - return STATUS_ERROR; - } + + if (result == STATUS_TIMEOUT) return STATUS_OK; + if (result == STATUS_OK) return STATUS_ERROR; // That is ironically NOT ok in this case ;-) + return result; } // End PICC_HaltA() @@ -820,6 +807,7 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { // Functions for communicating with MIFARE PICCs ///////////////////////////////////////////////////////////////////////////////////// + /** * Executes the MFRC522 MFAuthent command. * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. @@ -830,13 +818,13 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { * * All keys are set to FFFFFFFFFFFFh at chip delivery. * + * @param command PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B + * @param blockAddr The block number. See numbering in the comments in the .h file. + * @param key Pointer to the Crypteo1 key to use (6 bytes) + * @param uid Pointer to Uid struct. The first 4 bytes of the UID is used. * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. */ -MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B - byte blockAddr, ///< The block number. See numbering in the comments in the .h file. - MIFARE_Key *key, ///< Pointer to the Crypteo1 key to use (6 bytes) - Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used. - ) { +MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key* key, Uid* uid) { byte waitIRq = 0x10; // IdleIRq // Build command buffer @@ -844,20 +832,21 @@ MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AU sendData[0] = command; sendData[1] = blockAddr; for (byte i = 0; i < MF_KEY_SIZE; i++) { // 6 key bytes - sendData[2+i] = key->keyByte[i]; + sendData[2 + i] = key->keyByte[i]; } // Use the last uid bytes as specified in http://cache.nxp.com/documents/application_note/AN10927.pdf // section 3.2.5 "MIFARE Classic Authentication". // The only missed case is the MF1Sxxxx shortcut activation, // but it requires cascade tag (CT) byte, that is not part of uid. - for (byte i = 0; i < 4; i++) { // The last 4 bytes of the UID - sendData[8+i] = uid->uidByte[i+uid->size-4]; + for (byte i = 0; i < 4; i++) { // The last 4 bytes of the UID + sendData[8 + i] = uid->uidByte[i + uid->size - 4]; } // Start the authentication. return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData)); } // End PCD_Authenticate() + /** * Used to exit the PCD from its authenticated state. * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start. @@ -867,6 +856,7 @@ void MFRC522::PCD_StopCrypto1() { PCD_ClearRegisterBitMask(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0] } // End PCD_StopCrypto1() + /** * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. * @@ -881,32 +871,29 @@ void MFRC522::PCD_StopCrypto1() { * The buffer must be at least 18 bytes because a CRC_A is also returned. * Checks the CRC_A before returning STATUS_OK. * + * @param blockAddr MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. + * @param buffer The buffer to store the data in + * @param bufferSize Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. - byte *buffer, ///< The buffer to store the data in - byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Read(byte blockAddr, byte* buffer, byte* bufferSize) { MFRC522::StatusCode result; // Sanity check - if (buffer == nullptr || *bufferSize < 18) { - return STATUS_NO_ROOM; - } + if (buffer == nullptr || *bufferSize < 18) return STATUS_NO_ROOM; // Build command buffer buffer[0] = PICC_CMD_MF_READ; buffer[1] = blockAddr; // Calculate CRC_A result = PCD_CalculateCRC(buffer, 2, &buffer[2]); - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; // Transmit the buffer and receive the response, validate CRC_A. return PCD_TransceiveData(buffer, 4, buffer, bufferSize, nullptr, 0, true); } // End MIFARE_Read() + /** * Writes 16 bytes to the active PICC. * @@ -915,19 +902,16 @@ MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: * For MIFARE Ultralight the operation is called "COMPATIBILITY WRITE". * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. - * * + * @param blockAddr MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. + * @param buffer The 16 bytes to write to the PICC + * @param bufferSize Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. - byte *buffer, ///< The 16 bytes to write to the PICC - byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Write(byte blockAddr, byte* buffer, byte bufferSize) { MFRC522::StatusCode result; // Sanity check - if (buffer == nullptr || bufferSize < 16) { - return STATUS_INVALID; - } + if (buffer == nullptr || bufferSize < 16) return STATUS_INVALID; // Mifare Classic protocol requires two communications to perform a write. // Step 1: Tell the PICC we want to write to block blockAddr. @@ -935,34 +919,28 @@ MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: cmdBuffer[0] = PICC_CMD_MF_WRITE; cmdBuffer[1] = blockAddr; result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; // Step 2: Transfer the data result = PCD_MIFARE_Transceive(buffer, bufferSize); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; return STATUS_OK; } // End MIFARE_Write() + /** * Writes a 4 byte page to the active MIFARE Ultralight PICC. - * + * @param page The page (2-15) to write to. + * @param buffer The 4 bytes to write to the PICC + * @param bufferSize Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page (2-15) to write to. - byte *buffer, ///< The 4 bytes to write to the PICC - byte bufferSize ///< Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write(byte page, byte* buffer, byte bufferSize) { MFRC522::StatusCode result; // Sanity check - if (buffer == nullptr || bufferSize < 4) { - return STATUS_INVALID; - } + if (buffer == nullptr || bufferSize < 4) return STATUS_INVALID; // Build commmand buffer byte cmdBuffer[6]; @@ -972,106 +950,105 @@ MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page // Perform the write result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; + return STATUS_OK; } // End MIFARE_Ultralight_Write() + /** * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Use MIFARE_Transfer() to store the result in a block. + * @param blockAddr The block (0-0xff) number. + * @param delta This number is subtracted from the value of block blockAddr. * * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0-0xff) number. - int32_t delta ///< This number is subtracted from the value of block blockAddr. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Decrement(byte blockAddr, int32_t delta) { return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta); } // End MIFARE_Decrement() + /** * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Use MIFARE_Transfer() to store the result in a block. * + * @param blockAddr The block (0-0xff) number. + * @param delta This number is added to the value of block blockAddr. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0-0xff) number. - int32_t delta ///< This number is added to the value of block blockAddr. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Increment(byte blockAddr, int32_t delta) { return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta); } // End MIFARE_Increment() + /** * MIFARE Restore copies the value of the addressed block into a volatile memory. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Use MIFARE_Transfer() to store the result in a block. * + * @param blockAddr The block (0-0xff) number. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0xff) number. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Restore(byte blockAddr) { // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2. // Doing only a single step does not work, so I chose to transfer 0L in step two. return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L); } // End MIFARE_Restore() + /** * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. * + * @param command The command to use + * @param blockAddr The block (0-0xff) number. + * @param data The data to transfer in step 2 * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The command to use - byte blockAddr, ///< The block (0-0xff) number. - int32_t data ///< The data to transfer in step 2 - ) { +MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper(byte command, byte blockAddr, int32_t data) { MFRC522::StatusCode result; byte cmdBuffer[2]; // We only need room for 2 bytes. // Step 1: Tell the PICC the command and block address cmdBuffer[0] = command; cmdBuffer[1] = blockAddr; - result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } + result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. + if (result != STATUS_OK) return result; // Step 2: Transfer the data - result = PCD_MIFARE_Transceive( (byte *)&data, 4, true); // Adds CRC_A and accept timeout as success. - if (result != STATUS_OK) { - return result; - } + result = PCD_MIFARE_Transceive((byte*) &data, 4, true); // Adds CRC_A and accept timeout as success. + if (result != STATUS_OK) return result; return STATUS_OK; } // End MIFARE_TwoStepHelper() + /** * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * + * @param blockAddr The block (0-0xff) number. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0xff) number. - ) { +MFRC522::StatusCode MFRC522::MIFARE_Transfer(byte blockAddr) { MFRC522::StatusCode result; byte cmdBuffer[2]; // We only need room for 2 bytes. // Tell the PICC we want to transfer the result into block blockAddr. cmdBuffer[0] = PICC_CMD_MF_TRANSFER; cmdBuffer[1] = blockAddr; - result = PCD_MIFARE_Transceive( cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. - if (result != STATUS_OK) { - return result; - } + result = PCD_MIFARE_Transceive(cmdBuffer, 2); // Adds CRC_A and checks that the response is MF_ACK. + if (result != STATUS_OK) return result; return STATUS_OK; } // End MIFARE_Transfer() + /** * Helper routine to read the current value from a Value Block. * @@ -1083,7 +1060,7 @@ MFRC522::StatusCode MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0 * @param[out] value Current value of the Value Block. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, int32_t *value) { +MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, int32_t* value) { MFRC522::StatusCode status; byte buffer[18]; byte size = sizeof(buffer); @@ -1092,11 +1069,12 @@ MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, int32_t *value) { status = MIFARE_Read(blockAddr, buffer, &size); if (status == STATUS_OK) { // Extract the value - *value = (int32_t(buffer[3])<<24) | (int32_t(buffer[2])<<16) | (int32_t(buffer[1])<<8) | int32_t(buffer[0]); + *value = (int32_t(buffer[3]) << 24) | (int32_t(buffer[2]) << 16) | (int32_t(buffer[1]) << 8) | int32_t(buffer[0]); } return status; } // End MIFARE_GetValue() + /** * Helper routine to write a specific value into a Value Block. * @@ -1129,6 +1107,7 @@ MFRC522::StatusCode MFRC522::MIFARE_SetValue(byte blockAddr, int32_t value) { return MIFARE_Write(blockAddr, buffer, 16); } // End MIFARE_SetValue() + /** * Authenticate with a NTAG216. * @@ -1138,8 +1117,7 @@ MFRC522::StatusCode MFRC522::MIFARE_SetValue(byte blockAddr, int32_t value) { * @param[in] pACK result success???. * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Authenticate with 32bit password -{ +MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) { //Authenticate with 32bit password // TODO: Fix cmdBuffer length and rxlength. They really should match. // (Better still, rxlength should not even be necessary.) @@ -1148,14 +1126,13 @@ MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Aut cmdBuffer[0] = 0x1B; //Comando de autentificacion - for (byte i = 0; i<4; i++) - cmdBuffer[i+1] = passWord[i]; + for (byte i = 0; i < 4; i++) { + cmdBuffer[i + 1] = passWord[i]; + } result = PCD_CalculateCRC(cmdBuffer, 5, &cmdBuffer[5]); - if (result!=STATUS_OK) { - return result; - } + if (result!=STATUS_OK) return result; // Transceive the data, store the reply in cmdBuffer[] byte waitIRq = 0x30; // RxIRq and IdleIRq @@ -1167,9 +1144,7 @@ MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Aut pACK[0] = cmdBuffer[0]; pACK[1] = cmdBuffer[1]; - if (result!=STATUS_OK) { - return result; - } + if (result!=STATUS_OK) return result; return STATUS_OK; } // End PCD_NTAG216_AUTH() @@ -1179,30 +1154,27 @@ MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Aut // Support functions ///////////////////////////////////////////////////////////////////////////////////// + /** * Wrapper for MIFARE protocol communication. * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. * + * @param sendData Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. + * @param sendLen Number of bytes in sendData. + * @param acceptTimeout True => A timeout is also success * @return STATUS_OK on success, STATUS_??? otherwise. */ -MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. - byte sendLen, ///< Number of bytes in sendData. - bool acceptTimeout ///< True => A timeout is also success - ) { +MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive(byte* sendData, byte sendLen, bool acceptTimeout) { MFRC522::StatusCode result; byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. // Sanity check - if (sendData == nullptr || sendLen > 16) { - return STATUS_INVALID; - } + if (sendData == nullptr || sendLen > 16) return STATUS_INVALID; // Copy sendData[] to cmdBuffer[] and add CRC_A memcpy(cmdBuffer, sendData, sendLen); result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]); - if (result != STATUS_OK) { - return result; - } + if (result != STATUS_OK) return result; sendLen += 2; // Transceive the data, store the reply in cmdBuffer[] @@ -1210,19 +1182,11 @@ MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointe byte cmdBufferSize = sizeof(cmdBuffer); byte validBits = 0; result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize, &validBits); - if (acceptTimeout && result == STATUS_TIMEOUT) { - return STATUS_OK; - } - if (result != STATUS_OK) { - return result; - } + if (acceptTimeout && result == STATUS_TIMEOUT) return STATUS_OK; + if (result != STATUS_OK) return result; // The PICC must reply with a 4 bit ACK - if (cmdBufferSize != 1 || validBits != 4) { - return STATUS_ERROR; - } - if (cmdBuffer[0] != MF_ACK) { - return STATUS_MIFARE_NACK; - } + if (cmdBufferSize != 1 || validBits != 4) return STATUS_ERROR; + if (cmdBuffer[0] != MF_ACK) return STATUS_MIFARE_NACK; return STATUS_OK; } // End PCD_MIFARE_Transceive() @@ -1230,10 +1194,10 @@ MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointe /** * Translates the SAK (Select Acknowledge) to a PICC type. * + * @param sak The SAK byte returned from PICC_Select(). * @return PICC_Type */ -MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select(). - ) { +MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak) { // http://www.nxp.com/documents/application_note/AN10833.pdf // 3.2 Coding of Select Acknowledge (SAK) // ignore 8-bit (iso14443 starts with LSBit = bit 1) @@ -1276,19 +1240,21 @@ void MFRC522::PCD_DumpVersionToSerial() { ESP_LOGD(LOG_TAG, "%s", oss.str().c_str()); // When 0x00 or 0xFF is returned, communication probably failed - if ((v == 0x00) || (v == 0xFF)) + if ((v == 0x00) || (v == 0xFF)) { ESP_LOGD(LOG_TAG, "WARNING: Communication failure, is the MFRC522 properly connected?"); + } } // End PCD_DumpVersionToSerial() + /** * Dumps debug info about the selected PICC to Serial. * On success the PICC is halted after dumping the data. * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. * + * @param uid Pointer to Uid struct returned from a successful PICC_Select(). * @DEPRECATED Kept for bakward compatibility */ -void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). - ) { +void MFRC522::PICC_DumpToSerial(Uid* uid) { MIFARE_Key key; // Dump UID, SAK and Type @@ -1325,17 +1291,17 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro break; // No memory dump here } - ESP_LOGD(LOG_TAG,""); PICC_HaltA(); // Already done if it was a MIFARE Classic PICC. } // End PICC_DumpToSerial() + /** * Dumps card info (UID,SAK,Type) about the selected PICC to Serial. * + * @param uid Pointer to Uid struct returned from a successful PICC_Select(). * @DEPRECATED kept for backward compatibility */ -void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). - ) { +void MFRC522::PICC_DumpDetailsToSerial(Uid* uid) { // UID std::ostringstream oss; oss << std::hex << std::setfill('0'); @@ -1351,7 +1317,6 @@ void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct retur oss << "" << "Card SAK: " << std::setw(2) << (int)uid->sak; ESP_LOGD(LOG_TAG, "%s", oss.str().c_str()); - // (suggested) PICC type PICC_Type piccType = PICC_GetType(uid->sak); oss.str(""); @@ -1359,31 +1324,30 @@ void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct retur ESP_LOGD(LOG_TAG, "%s", oss.str().c_str()); } // End PICC_DumpDetailsToSerial() + /** * Dumps memory contents of a MIFARE Classic PICC. * On success the PICC is halted after dumping the data. + * + * @param uid Pointer to Uid struct returned from a successful PICC_Select(). + * @param piccType One of the PICC_Type enums. + * @param key Key A used for all sectors. */ -void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). - PICC_Type piccType, ///< One of the PICC_Type enums. - MIFARE_Key *key ///< Key A used for all sectors. - ) { +void MFRC522::PICC_DumpMifareClassicToSerial(Uid* uid, PICC_Type piccType, MIFARE_Key* key) { byte no_of_sectors = 0; switch (piccType) { case PICC_TYPE_MIFARE_MINI: // Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. no_of_sectors = 5; break; - case PICC_TYPE_MIFARE_1K: // Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. no_of_sectors = 16; break; - case PICC_TYPE_MIFARE_4K: // Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. no_of_sectors = 40; break; - default: // Should not happen. Ignore. break; } @@ -1399,15 +1363,17 @@ void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid st PCD_StopCrypto1(); } // End PICC_DumpMifareClassicToSerial() + /** * Dumps memory contents of a sector of a MIFARE Classic PICC. * Uses PCD_Authenticate(), MIFARE_Read() and PCD_StopCrypto1. * Always uses PICC_CMD_MF_AUTH_KEY_A because only Key A can always read the sector trailer access bits. + * + * @param uid Pointer to Uid struct returned from a successful PICC_Select(). + * @param key Key A for the sector. + * @param sector The sector to dump, 0..39. */ -void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to Uid struct returned from a successful PICC_Select(). - MIFARE_Key *key, ///< Key A for the sector. - byte sector ///< The sector to dump, 0..39. - ) { +void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid* uid, MIFARE_Key* key, byte sector) { MFRC522::StatusCode status; byte firstBlock; // Address of lowest address to dump actually last block dumped) byte no_of_blocks; // Number of blocks in sector @@ -1436,8 +1402,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U else if (sector < 40) { // Sectors 32-39 has 16 blocks each no_of_blocks = 16; firstBlock = 128 + (sector - 32) * no_of_blocks; - } - else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors. + } else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors. return; } @@ -1452,28 +1417,23 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U // Sector number - only on first line std::ostringstream oss; if (isSectorTrailer) { - if(sector < 10) { + if (sector < 10) { oss << " "; // Pad with spaces - } - else { + } else { oss << " "; // Pad with spaces } - oss << (int)sector; - + oss << (int) sector; oss << " "; - } - else { oss << " "; + } else { } // Block number - if(blockAddr < 10) { + if (blockAddr < 10) { oss << " "; // Pad with spaces - } - else { - if(blockAddr < 100) { + } else { + if (blockAddr < 100) { oss << " "; // Pad with spaces - } - else { + } else { oss << " "; // Pad with spaces } } @@ -1502,7 +1462,6 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U oss << std::hex << std::setfill('0'); for (byte index = 0; index < 16; index++) { oss << " " << std::setw(2) << (int)buffer[index]; - if ((index % 4) == 3) { oss << " "; } @@ -1527,8 +1486,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U if (no_of_blocks == 4) { group = blockOffset; firstInGroup = true; - } - else { + } else { group = blockOffset / 5; firstInGroup = (group == 3) || (group != (blockOffset + 1) / 5); } @@ -1536,15 +1494,15 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U if (firstInGroup) { // Print access bits oss << std::dec; - oss << " [ " << (int)((g[group] >> 2) & 1) << " " << (int)((g[group] >> 1) & 1) << " " << (int) ((g[group] >> 0) & 1) << " ] "; + oss << " [ " << ((g[group] >> 2) & 1) << " " << ((g[group] >> 1) & 1) << " " << ((g[group] >> 0) & 1) << " ] "; if (invertedError) { oss << " Inverted access bits did not match! "; } } if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block - int32_t value = (int32_t(buffer[3])<<24) | (int32_t(buffer[2])<<16) | (int32_t(buffer[1])<<8) | int32_t(buffer[0]); - oss << " Value=0x" << std::hex << value << " Adr=0x" << (int)buffer[12]; + int32_t value = (int32_t(buffer[3]) << 24) | (int32_t(buffer[2]) << 16) | (int32_t(buffer[1]) << 8) | int32_t(buffer[0]); + oss << " Value=0x" << std::hex << value << " Adr=0x" << (int) buffer[12]; } ESP_LOGD(LOG_TAG, "%s", oss.str().c_str()); } @@ -1552,6 +1510,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U return; } // End PICC_DumpMifareClassicSectorToSerial() + /** * Dumps memory contents of a MIFARE Ultralight PICC. */ @@ -1564,7 +1523,7 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() { std::ostringstream oss; oss << "Page 0 1 2 3"; // Try the mpages of the original Ultralight. Ultralight C has more pages. - for (byte page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time. + for (byte page = 0; page < 16; page += 4) { // Read returns data for 4 pages at a time. // Read pages byteCount = sizeof(buffer); status = MIFARE_Read(page, buffer, &byteCount); @@ -1582,22 +1541,24 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() { for (byte index = 0; index < 4; index++) { i = 4 * offset + index; - oss << std::hex << std::setw(2) << (int)buffer[i]; + oss << std::hex << std::setw(2) << (int) buffer[i]; } ESP_LOGD(LOG_TAG, "%s", oss.str().c_str()); } } } // End PICC_DumpMifareUltralightToSerial() + /** * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tuples C1 is MSB (=4) and C3 is LSB (=1). + * + * @param accessBitBuffer Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. + * @param g0 Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) + * @param g1 Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) + * @param g2 Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) + * @param g3 Access bits C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) */ -void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. - byte g0, ///< Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) - byte g1, ///< Access bits C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) - byte g2, ///< Access bits C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) - byte g3 ///< Access bits C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) - ) { +void MFRC522::MIFARE_SetAccessBits(byte* accessBitBuffer, byte g0, byte g1, byte g2, byte g3) { byte c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); byte c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); byte c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0); @@ -1611,6 +1572,7 @@ void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte // Convenience functions - does not add extra functionality ///////////////////////////////////////////////////////////////////////////////////// + /** * Returns true if a PICC responds to PICC_CMD_REQA. * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. @@ -1631,6 +1593,7 @@ bool MFRC522::PICC_IsNewCardPresent() { return (result == STATUS_OK || result == STATUS_COLLISION); } // End PICC_IsNewCardPresent() + /** * Simple wrapper around PICC_Select. * Returns true if a UID could be read. diff --git a/cpp_utils/MFRC522.h b/cpp_utils/MFRC522.h index 2e060712..9e03ba4f 100644 --- a/cpp_utils/MFRC522.h +++ b/cpp_utils/MFRC522.h @@ -76,7 +76,6 @@ #define MFRC522_h - #include #include @@ -258,7 +257,6 @@ class MFRC522 { PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2 PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3 PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. - PICC_CMD_RATS = 0xE0, // Request command for Answer To Reset. // The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. // The read/write commands can also be used for MIFARE Ultralight. @@ -329,18 +327,20 @@ class MFRC522 { ///////////////////////////////////////////////////////////////////////////////////// // Functions for setting up the Arduino ///////////////////////////////////////////////////////////////////////////////////// + //MFRC522(); ///////////////////////////////////////////////////////////////////////////////////// // Basic interface functions for communicating with the MFRC522 ///////////////////////////////////////////////////////////////////////////////////// + void PCD_WriteRegister(PCD_Register reg, byte value); - void PCD_WriteRegister(PCD_Register reg, byte count, byte *values); + void PCD_WriteRegister(PCD_Register reg, byte count, byte* values); byte PCD_ReadRegister(PCD_Register reg); - void PCD_ReadRegister(PCD_Register reg, byte count, byte *values, byte rxAlign = 0); + void PCD_ReadRegister(PCD_Register reg, byte count, byte* values, byte rxAlign = 0); void PCD_SetRegisterBitMask(PCD_Register reg, byte mask); void PCD_ClearRegisterBitMask(PCD_Register reg, byte mask); - StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result); + StatusCode PCD_CalculateCRC(byte* data, byte length, byte* result); ///////////////////////////////////////////////////////////////////////////////////// // Functions for manipulating the MFRC522 @@ -357,46 +357,46 @@ class MFRC522 { ///////////////////////////////////////////////////////////////////////////////////// // Functions for communicating with PICCs ///////////////////////////////////////////////////////////////////////////////////// - StatusCode PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = nullptr, byte rxAlign = 0, bool checkCRC = false); - StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = nullptr, byte *backLen = nullptr, byte *validBits = nullptr, byte rxAlign = 0, bool checkCRC = false); - StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize); - StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize); - StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize); - virtual StatusCode PICC_Select(Uid *uid, byte validBits = 0); + StatusCode PCD_TransceiveData(byte* sendData, byte sendLen, byte* backData, byte* backLen, byte* validBits = nullptr, byte rxAlign = 0, bool checkCRC = false); + StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte* sendData, byte sendLen, byte* backData = nullptr, byte* backLen = nullptr, byte* validBits = nullptr, byte rxAlign = 0, bool checkCRC = false); + StatusCode PICC_RequestA(byte* bufferATQA, byte* bufferSize); + StatusCode PICC_WakeupA(byte* bufferATQA, byte* bufferSize); + StatusCode PICC_REQA_or_WUPA(byte command, byte* bufferATQA, byte* bufferSize); + virtual StatusCode PICC_Select(Uid* uid, byte validBits = 0); StatusCode PICC_HaltA(); ///////////////////////////////////////////////////////////////////////////////////// // Functions for communicating with MIFARE PICCs ///////////////////////////////////////////////////////////////////////////////////// - StatusCode PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); + StatusCode PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key* key, Uid* uid); void PCD_StopCrypto1(); - StatusCode MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize); - StatusCode MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize); - StatusCode MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize); + StatusCode MIFARE_Read(byte blockAddr, byte* buffer, byte* bufferSize); + StatusCode MIFARE_Write(byte blockAddr, byte* buffer, byte bufferSize); + StatusCode MIFARE_Ultralight_Write(byte page, byte* buffer, byte bufferSize); StatusCode MIFARE_Decrement(byte blockAddr, int32_t delta); StatusCode MIFARE_Increment(byte blockAddr, int32_t delta); StatusCode MIFARE_Restore(byte blockAddr); StatusCode MIFARE_Transfer(byte blockAddr); - StatusCode MIFARE_GetValue(byte blockAddr, int32_t *value); + StatusCode MIFARE_GetValue(byte blockAddr, int32_t* value); StatusCode MIFARE_SetValue(byte blockAddr, int32_t value); - StatusCode PCD_NTAG216_AUTH(byte *passWord, byte pACK[]); + StatusCode PCD_NTAG216_AUTH(byte* passWord, byte pACK[]); ///////////////////////////////////////////////////////////////////////////////////// // Support functions ///////////////////////////////////////////////////////////////////////////////////// - StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false); + StatusCode PCD_MIFARE_Transceive(byte* sendData, byte sendLen, bool acceptTimeout = false); static PICC_Type PICC_GetType(byte sak); // Support functions for debuging void PCD_DumpVersionToSerial(); - void PICC_DumpToSerial(Uid *uid); - void PICC_DumpDetailsToSerial(Uid *uid); - void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key); - void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); + void PICC_DumpToSerial(Uid* uid); + void PICC_DumpDetailsToSerial(Uid* uid); + void PICC_DumpMifareClassicToSerial(Uid* uid, PICC_Type piccType, MIFARE_Key* key); + void PICC_DumpMifareClassicSectorToSerial(Uid* uid, MIFARE_Key* key, byte sector); void PICC_DumpMifareUltralightToSerial(); // Advanced functions for MIFARE - void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); + void MIFARE_SetAccessBits(byte* accessBitBuffer, byte g0, byte g1, byte g2, byte g3); ///////////////////////////////////////////////////////////////////////////////////// // Convenience functions - does not add extra functionality diff --git a/cpp_utils/MFRC522Debug.h b/cpp_utils/MFRC522Debug.h index 6c1c9ac6..e8033495 100644 --- a/cpp_utils/MFRC522Debug.h +++ b/cpp_utils/MFRC522Debug.h @@ -4,11 +4,10 @@ #define MFRC522Debug_h class MFRC522Debug { -private: - public: // Get human readable code and type static const char* PICC_GetTypeName(MFRC522::PICC_Type type); static const char* GetStatusCodeName(MFRC522::StatusCode code); + }; #endif // MFRC522Debug_h diff --git a/cpp_utils/MMU.cpp b/cpp_utils/MMU.cpp new file mode 100644 index 00000000..ee7adb59 --- /dev/null +++ b/cpp_utils/MMU.cpp @@ -0,0 +1,126 @@ +/* + * MMU.cpp + * + * Created on: Jun 30, 2018 + * Author: kolban + */ + +#include "MMU.h" +#include +#include +#include + +// The following functions are provided by spi_flash.h +extern "C" { + extern void spi_flash_disable_interrupts_caches_and_other_cpu(); + + // Enable cache, enable interrupts (to be added in future), resume scheduler + extern void spi_flash_enable_interrupts_caches_and_other_cpu(); +} + + +typedef struct { + uint32_t low; + uint32_t high; +} addressRange_t; + +static addressRange_t entryNumberToAddressRange(uint32_t entryNumber) { + addressRange_t ret; + if (entryNumber < 64) { + ret.low = 0x3F400000 + 64 * 1024 * entryNumber; + ret.high = 0x3F400000 + 64 * 1024 * (entryNumber + 1) - 1; + return ret; + } + ret.low = 0x40000000 + 64 * 1024 * (entryNumber - 64); + ret.high = 0x40000000 + 64 * 1024 * (entryNumber + 1 - 64) - 1; + return ret; +} + + +static uint32_t flashPageToOffset(uint32_t page) { + return page * 64 * 1024; +} + + + +/* static */ void MMU::dump() { + const uint32_t mappingInvalid = 1 << 8; + + printf("PRO CPU MMU\n"); + for (uint16_t i = 0; i < 256; i++) { + if (!(DPORT_PRO_FLASH_MMU_TABLE[i] & mappingInvalid)) { + addressRange_t addressRange = entryNumberToAddressRange(i); + printf("Entry: %2d (0x%8.8x - 0x%8.8x), Page: %d - offset: 0x%x\n", + i, + addressRange.low, addressRange.high, + DPORT_PRO_FLASH_MMU_TABLE[i] & 0xff, + flashPageToOffset(DPORT_PRO_FLASH_MMU_TABLE[i] & 0xff)); + } + } + printf("\n"); + printf("APP CPU MMU\n"); + for (uint16_t i = 0; i < 256; i++) { + if (!(DPORT_APP_FLASH_MMU_TABLE[i] & mappingInvalid)) { + addressRange_t addressRange = entryNumberToAddressRange(i); + printf("Entry: %2d (0x%8.8x - 0x%8.8x), Page: %d - offset: 0x%x\n", + i, + addressRange.low, addressRange.high, + DPORT_APP_FLASH_MMU_TABLE[i] & 0xff, + flashPageToOffset(DPORT_APP_FLASH_MMU_TABLE[i] & 0xff)); + } + } +} // MMU#dumpMMU + +extern "C" { + static void IRAM_ATTR mapFlashToVMA_Internal(uint32_t flashOffset, void* vma, size_t size); +} + +static void IRAM_ATTR mapFlashToVMA_Internal(uint32_t flashOffset, void* vma, size_t size) { + printf(">> MMU::mapFlashToVMA: flash offset: 0x%x, VMA: 0x%x, size: %d\n", flashOffset, (uint32_t)vma, size); + uint32_t mmuEntryStart; // The MMU table entry to start mapping. + uint32_t mmuEntryEnd; // The MMU table entry to end mapping. + + if ((uint32_t) vma >= 0x40000000 && (uint32_t) vma < 0x40C00000) { + mmuEntryStart = (((uint32_t) vma - 0x40000000) / (64 * 1024)) + 64; + mmuEntryEnd = (((uint32_t) vma - 0x40000000 + size) / (64 * 1024)) + 64; + } + else if ((uint32_t) vma >= 0x3F400000 && (uint32_t) vma < 0x3F800000) { + mmuEntryStart = (((uint32_t) vma - 0x3F400000) / (64 * 1024)); + mmuEntryEnd = (((uint32_t) vma - 0x3F400000 + size) / (64 * 1024)); + } else { + printf(" - Unable to map from flash to VMA."); + return; + } + + // At this point we have populated mmuEntryStart and mmuEntryEnd which are the MMU table entries. + uint32_t pFlashStart = flashOffset; + uint32_t pFlashEnd = flashOffset + size; + + printf(" - Mapping flash to VMA via MMU. MMU entries start: %d, end: %d, mapping flash 0x%x (flash page: %d) to 0x%x (flash page: %d)\n", + mmuEntryStart, mmuEntryEnd, pFlashStart, pFlashStart/(64 * 1024), pFlashEnd, pFlashEnd / (64 * 1024)); + + uint32_t flashRegion = pFlashStart / (64 * 1024); // Determine the 64K chunk of flash to be mapped (we map in units of 64K). + + spi_flash_disable_interrupts_caches_and_other_cpu(); + + // For each of the mapping entries, map it to the corresponding flash region. + for (uint32_t i = mmuEntryStart; i <= mmuEntryEnd; i++) { + DPORT_PRO_FLASH_MMU_TABLE[i] = flashRegion; // There are two tables. One for the PRO CPU and one for the APP CPU. + DPORT_APP_FLASH_MMU_TABLE[i] = flashRegion; // Map both of them to the flash region. + flashRegion++; + } + + Cache_Flush(0); + Cache_Flush(1); + spi_flash_enable_interrupts_caches_and_other_cpu(); +} // mapFlashToVMA + +/** + * Map an area of flash memory into VMA. + * @param flashOffset The offset in flash of the start of data. + * @param vma Where in VMA the data should appear. + * @size How much data to map. + */ +void IRAM_ATTR MMU::mapFlashToVMA(uint32_t flashOffset, void* vma, size_t size) { + mapFlashToVMA_Internal(flashOffset, vma, size); +} diff --git a/cpp_utils/MMU.h b/cpp_utils/MMU.h new file mode 100644 index 00000000..d8ba6b64 --- /dev/null +++ b/cpp_utils/MMU.h @@ -0,0 +1,22 @@ +/* + * MMU.h + * + * Created on: Jun 30, 2018 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_MMU_H_ +#define COMPONENTS_CPP_UTILS_MMU_H_ +#include +#include +#include + +class MMU { +public: + MMU(); + virtual ~MMU(); + static void dump(); + static void mapFlashToVMA(uint32_t flashOffset, void* vma, size_t size); +}; + +#endif /* COMPONENTS_CPP_UTILS_MMU_H_ */ diff --git a/cpp_utils/MPU6050.cpp b/cpp_utils/MPU6050.cpp index 5bcf5bb9..0f6931ae 100644 --- a/cpp_utils/MPU6050.cpp +++ b/cpp_utils/MPU6050.cpp @@ -9,14 +9,15 @@ #define MPU6050_GYRO_XOUT_H 0x43 #define MPU6050_PWR_MGMT_1 0x6B + /** * @brief Construct an %MPU6050 handler. */ MPU6050::MPU6050() { accel_x = accel_y = accel_z = 0; gyro_x = gyro_y = gyro_z = 0; - i2c=nullptr; - inited=false; + i2c = nullptr; + inited = false; } @@ -43,7 +44,7 @@ void MPU6050::readAccel() { uint8_t data[6]; i2c->beginTransaction(); i2c->read(data, 5, true); - i2c->read(data+5, false); + i2c->read(data + 5, false); i2c->endTransaction(); accel_x = (data[0] << 8) | data[1]; @@ -51,6 +52,7 @@ void MPU6050::readAccel() { accel_z = (data[4] << 8) | data[5]; } // readAccel + /** * @brief Read the gyroscopic values from the device. * @@ -66,7 +68,7 @@ void MPU6050::readGyro() { uint8_t data[6]; i2c->beginTransaction(); i2c->read(data, 5, true); - i2c->read(data+5, false); + i2c->read(data + 5, false); i2c->endTransaction(); gyro_x = (data[0] << 8) | data[1]; @@ -74,6 +76,7 @@ void MPU6050::readGyro() { gyro_z = (data[4] << 8) | data[5]; } // readGyro + /** * @brief Initialize the %MPU6050. * @param [in] sdaPin The %GPIO pin to use for %I2C SDA. @@ -94,5 +97,5 @@ void MPU6050::init(gpio_num_t sdaPin, gpio_num_t clkPin) { i2c->write(MPU6050_PWR_MGMT_1); i2c->write(0); i2c->endTransaction(); - inited=true; + inited = true; } diff --git a/cpp_utils/MPU6050.h b/cpp_utils/MPU6050.h index fe69193d..8207f6d6 100644 --- a/cpp_utils/MPU6050.h +++ b/cpp_utils/MPU6050.h @@ -16,61 +16,49 @@ * A call to init() must precede all other API calls. */ class MPU6050 { -private: - I2C *i2c; - short accel_x, accel_y, accel_z; - short gyro_x, gyro_y, gyro_z; - bool inited; public: MPU6050(); virtual ~MPU6050(); - /** * @brief Get the X acceleration value. */ - short getAccelX() const - { + short getAccelX() const { return accel_x; } /** * @brief Get the Y acceleration value. */ - short getAccelY() const - { + short getAccelY() const { return accel_y; } /** * @brief Get the Z acceleration value. */ - short getAccelZ() const - { + short getAccelZ() const { return accel_z; } /** * @brief Get the X gyroscopic value. */ - short getGyroX() const - { + short getGyroX() const { return gyro_x; } /** * @brief Get the Y gyroscopic value. */ - short getGyroY() const - { + short getGyroY() const { return gyro_y; } /** * @brief Get the Z gyroscopic value. */ - short getGyroZ() const - { + short getGyroZ() const { return gyro_z; } @@ -86,10 +74,16 @@ class MPU6050 { return sqrt(accel_x * accel_x + accel_y * accel_y + accel_z * accel_z); } - void init(gpio_num_t sdaPin=I2C::DEFAULT_SDA_PIN, gpio_num_t clkPin=I2C::DEFAULT_CLK_PIN); + void init(gpio_num_t sdaPin = I2C::DEFAULT_SDA_PIN, gpio_num_t clkPin = I2C::DEFAULT_CLK_PIN); void readAccel(); - void readGyro(); + +private: + I2C* i2c; + short accel_x, accel_y, accel_z; + short gyro_x, gyro_y, gyro_z; + bool inited; + }; #endif /* MAIN_MPU6050_H_ */ diff --git a/cpp_utils/MRFC522Debug.cpp b/cpp_utils/MRFC522Debug.cpp index 82cd031d..56ba91d0 100644 --- a/cpp_utils/MRFC522Debug.cpp +++ b/cpp_utils/MRFC522Debug.cpp @@ -1,46 +1,48 @@ #include "MFRC522Debug.h" + /** * Returns a __FlashStringHelper pointer to the PICC type name. * + * @param piccType One of the PICC_Type enums. * @return const __FlashStringHelper * */ -const char* MFRC522Debug::PICC_GetTypeName(MFRC522::PICC_Type piccType ///< One of the PICC_Type enums. -) { +const char* MFRC522Debug::PICC_GetTypeName(MFRC522::PICC_Type piccType) { switch (piccType) { - case MFRC522::PICC_TYPE_ISO_14443_4: return "PICC compliant with ISO/IEC 14443-4"; + case MFRC522::PICC_TYPE_ISO_14443_4: return "PICC compliant with ISO/IEC 14443-4"; case MFRC522::PICC_TYPE_ISO_18092: return "PICC compliant with ISO/IEC 18092 (NFC)"; - case MFRC522::PICC_TYPE_MIFARE_MINI: return "MIFARE Mini, 320 bytes"; + case MFRC522::PICC_TYPE_MIFARE_MINI: return "MIFARE Mini, 320 bytes"; case MFRC522::PICC_TYPE_MIFARE_1K: return "MIFARE 1KB"; case MFRC522::PICC_TYPE_MIFARE_4K: return "MIFARE 4KB"; case MFRC522::PICC_TYPE_MIFARE_UL: return "MIFARE Ultralight or Ultralight C"; - case MFRC522::PICC_TYPE_MIFARE_PLUS: return "MIFARE Plus"; - case MFRC522::PICC_TYPE_MIFARE_DESFIRE: return "MIFARE DESFire"; - case MFRC522::PICC_TYPE_TNP3XXX: return "MIFARE TNP3XXX"; - case MFRC522::PICC_TYPE_NOT_COMPLETE: return "SAK indicates UID is not complete."; + case MFRC522::PICC_TYPE_MIFARE_PLUS: return "MIFARE Plus"; + case MFRC522::PICC_TYPE_MIFARE_DESFIRE: return "MIFARE DESFire"; + case MFRC522::PICC_TYPE_TNP3XXX: return "MIFARE TNP3XXX"; + case MFRC522::PICC_TYPE_NOT_COMPLETE: return "SAK indicates UID is not complete."; case MFRC522::PICC_TYPE_UNKNOWN: - default: return "Unknown type"; + default: return "Unknown type"; } } // End PICC_GetTypeName() + /** * Returns a __FlashStringHelper pointer to a status code name. * + * @param code One of the StatusCode enums. * @return const __FlashStringHelper * */ -const char *MFRC522Debug::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. -) { +const char *MFRC522Debug::GetStatusCodeName(MFRC522::StatusCode code) { switch (code) { - case MFRC522::STATUS_OK: return "Success."; + case MFRC522::STATUS_OK: return "Success."; case MFRC522::STATUS_ERROR: return "Error in communication."; - case MFRC522::STATUS_COLLISION: return "Collission detected."; - case MFRC522::STATUS_TIMEOUT: return "Timeout in communication."; - case MFRC522::STATUS_NO_ROOM: return "A buffer is not big enough."; - case MFRC522::STATUS_INTERNAL_ERROR: return "Internal error in the code. Should not happen."; - case MFRC522::STATUS_INVALID: return "Invalid argument."; + case MFRC522::STATUS_COLLISION: return "Collision detected."; + case MFRC522::STATUS_TIMEOUT: return "Timeout in communication."; + case MFRC522::STATUS_NO_ROOM: return "A buffer is not big enough."; + case MFRC522::STATUS_INTERNAL_ERROR: return "Internal error in the code. Should not happen."; + case MFRC522::STATUS_INVALID: return "Invalid argument."; case MFRC522::STATUS_CRC_WRONG: return "The CRC_A does not match."; - case MFRC522::STATUS_MIFARE_NACK: return "A MIFARE PICC responded with NAK."; - default: return "Unknown error"; + case MFRC522::STATUS_MIFARE_NACK: return "A MIFARE PICC responded with NAK."; + default: return "Unknown error"; } } // End GetStatusCodeName() diff --git a/cpp_utils/Makefile.arduino b/cpp_utils/Makefile.arduino index b9524dcf..5638b266 100644 --- a/cpp_utils/Makefile.arduino +++ b/cpp_utils/Makefile.arduino @@ -80,4 +80,3 @@ build_ble: install: build_ble rm -rf ${ARDUINO_LIBS}/ESP32_BLE unzip Arduino/ESP32_BLE.zip -d $(ARDUINO_LIBS) - diff --git a/cpp_utils/Memory.cpp b/cpp_utils/Memory.cpp index e3be59db..33e5ae80 100644 --- a/cpp_utils/Memory.cpp +++ b/cpp_utils/Memory.cpp @@ -29,7 +29,7 @@ size_t Memory::m_lastHeapSize = 0; */ /* STATIC */ bool Memory::checkIntegrity() { bool rc = ::heap_caps_check_integrity_all(true); - if (rc == false && m_pRecords != nullptr) { + if (!rc && m_pRecords != nullptr) { dumpRanges(); abort(); } @@ -47,7 +47,7 @@ size_t Memory::m_lastHeapSize = 0; /* STATIC */ void Memory::dumpHeapChange(std::string tag) { size_t currentUsage = heap_caps_get_free_size(MALLOC_CAP_8BIT); - int diff = currentUsage - m_lastHeapSize; + size_t diff = currentUsage - m_lastHeapSize; ESP_LOGD(LOG_TAG, "%s: Heap changed by %d bytes (%d to %d)", tag.c_str(), diff, m_lastHeapSize, currentUsage); m_lastHeapSize = currentUsage; } // dumpHeapChange @@ -58,32 +58,29 @@ size_t Memory::m_lastHeapSize = 0; */ /* STATIC */ void Memory::dumpRanges() { // Each record contained in the Heap trace has the following format: - // // * uint32_t ccount – Timestamp of record. // * void* address – Address that was allocated or released. // * size_t size – Size of the block that was requested and allocated. // * void* alloced_by[CONFIG_HEAP_TRACING_STACK_DEPTH] – Call stack of allocator // * void* freed_by[CONFIG_HEAP_TRACING_STACK_DEPTH] – Call stack of releasor - // - if (m_pRecords == nullptr) { - return; - } + if (m_pRecords == nullptr) return; + esp_log_level_set("*", ESP_LOG_NONE); - size_t count = heap_trace_get_count(); + size_t count = (size_t) heap_trace_get_count(); heap_trace_record_t record; printf(">>> dumpRanges\n"); - for (size_t i=0; i +#include #include "NeoPixelWiFiEventHandler.h" +static const char* LOG_TAG = "NeoPixelWiFiEventHandler"; + NeoPixelWiFiEventHandler::NeoPixelWiFiEventHandler(gpio_num_t gpioPin) { this->gpioPin = gpioPin; ws2812 = new WS2812(gpioPin, 8); @@ -17,42 +20,42 @@ NeoPixelWiFiEventHandler::~NeoPixelWiFiEventHandler() { } esp_err_t NeoPixelWiFiEventHandler::apStart() { - printf("XXX apStart\n"); + ESP_LOGD(LOG_TAG, "XXX apStart"); ws2812->setPixel(0, 0, 00, 64); ws2812->show(); return ESP_OK; } esp_err_t NeoPixelWiFiEventHandler::staConnected(system_event_sta_connected_t info) { - printf("XXX staConnected\n"); + ESP_LOGD(LOG_TAG, "XXX staConnected"); ws2812->setPixel(0, 57, 89, 66); ws2812->show(); return ESP_OK; } esp_err_t NeoPixelWiFiEventHandler::staDisconnected(system_event_sta_disconnected_t info) { - printf("XXX staDisconnected\n"); + ESP_LOGD(LOG_TAG, "XXX staDisconnected"); ws2812->setPixel(0, 64, 0, 0); ws2812->show(); return ESP_OK; } esp_err_t NeoPixelWiFiEventHandler::staStart() { - printf("XXX staStart\n"); + ESP_LOGD(LOG_TAG, "XXX staStart"); ws2812->setPixel(0, 64, 64, 0); ws2812->show(); return ESP_OK; } esp_err_t NeoPixelWiFiEventHandler::staGotIp(system_event_sta_got_ip_t info) { - printf("XXX staGotIp\n"); + ESP_LOGD(LOG_TAG, "XXX staGotIp"); ws2812->setPixel(0, 0, 64, 0); ws2812->show(); return ESP_OK; } esp_err_t NeoPixelWiFiEventHandler::wifiReady() { - printf("XXX wifiReady\n"); + ESP_LOGD(LOG_TAG, "XXX wifiReady"); ws2812->setPixel(0, 64, 64, 0); ws2812->show(); return ESP_OK; diff --git a/cpp_utils/NeoPixelWiFiEventHandler.h b/cpp_utils/NeoPixelWiFiEventHandler.h index 3e9b596e..d59cafff 100644 --- a/cpp_utils/NeoPixelWiFiEventHandler.h +++ b/cpp_utils/NeoPixelWiFiEventHandler.h @@ -28,9 +28,10 @@ class NeoPixelWiFiEventHandler: public WiFiEventHandler { esp_err_t staDisconnected(system_event_sta_disconnected_t info) override; esp_err_t wifiReady() override; esp_err_t staStart() override; + private: gpio_num_t gpioPin; - WS2812 *ws2812; + WS2812* ws2812; }; #endif /* MAIN_NEOPIXELWIFIEVENTHANDLER_H_ */ diff --git a/cpp_utils/OV7670.cpp b/cpp_utils/OV7670.cpp index c2de1316..a3c3811d 100644 --- a/cpp_utils/OV7670.cpp +++ b/cpp_utils/OV7670.cpp @@ -14,31 +14,34 @@ #include "GeneralUtils.h" #include "sdkconfig.h" #include + +#define OV7670_I2C_ADDR (0x21) + extern "C" { #include #include } -static const char *LOG_TAG="OV7670"; +static const char* LOG_TAG = "OV7670"; static bool getBit(uint8_t value, uint8_t bitNum) { - return (value & (1<> 3) << 3; uint8_t green = (((byte1 & 0b111) << 3) | ((byte2 & 0b11100000) >> 5)) << 2; uint8_t blue = (byte2 & 0b11111) << 3; - *pLine = (red + green + blue)/3; + *pLine = (red + green + blue) / 3; pLine++; - i+=2; + i += 2; } pLine = pLineSave; - GeneralUtils::hexDump(pLine, length/2); + GeneralUtils::hexDump(pLine, length / 2); } void OV7670::setFormat(uint8_t value) { @@ -120,7 +123,6 @@ void OV7670::setTestPattern(uint8_t value) { * */ -#define OV7670_I2C_ADDR (0x21) /* static void IRAM_ATTR isr_vsync(void* arg) { ESP_EARLY_LOGD(LOG_TAG, "VSYNC"); @@ -183,20 +185,19 @@ OV7670::~OV7670() { } -static esp_err_t camera_enable_out_clock(camera_config_t* config) -{ +static esp_err_t camera_enable_out_clock(camera_config_t* config) { ESP_LOGD(LOG_TAG, ">> camera_enable_out_clock: freq_hz=%d, pin=%d", config->xclk_freq_hz, config->pin_xclk); periph_module_enable(PERIPH_LEDC_MODULE); ledc_timer_config_t timer_conf; - timer_conf.duty_resolution = (ledc_timer_bit_t)1; timer_conf.freq_hz = config->xclk_freq_hz; + timer_conf.duty_resolution = (ledc_timer_bit_t) 1; timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE; timer_conf.timer_num = config->ledc_timer; esp_err_t err = ledc_timer_config(&timer_conf); if (err != ESP_OK) { - ESP_LOGE(LOG_TAG, "ledc_timer_config failed, rc=%x", err); - return err; + ESP_LOGE(LOG_TAG, "ledc_timer_config failed, rc=%x", err); + return err; } ledc_channel_config_t ch_conf; @@ -209,8 +210,8 @@ static esp_err_t camera_enable_out_clock(camera_config_t* config) err = ledc_channel_config(&ch_conf); if (err != ESP_OK) { - ESP_LOGE(LOG_TAG, "ledc_channel_config failed, rc=%x", err); - return err; + ESP_LOGE(LOG_TAG, "ledc_channel_config failed, rc=%x", err); + return err; } ESP_LOGD(LOG_TAG, "<< camera_enable_out_clock"); return ESP_OK; @@ -274,88 +275,90 @@ void OV7670::dump() { uint32_t outputFormat = getBit(com7, 2) << 1 | getBit(com7, 0); //uint32_t outputFormat = (com7 & (1<<2)) >> 1 | (com7 & (1<<0)); std::string outputFormatString; - switch(outputFormat) { - case 0b00: - outputFormatString = "YUV"; - break; - case 0b10: - outputFormatString = "RGB"; - break; - case 0b01: - outputFormatString = "Raw Bayer RGB"; - break; - case 0b11: - outputFormatString = "Process Bayer RGB"; - break; - default: - outputFormatString = "Unknown"; - break; - } - ESP_LOGD(LOG_TAG, "Output format: %s", outputFormatString.c_str()); - if (outputFormat == 0b10) { - uint8_t com15 = readRegister(OV7670_REG_COM15); - uint8_t rgbType = getBit(com15, 5) << 1 | getBit(com15,4); - char *rgbTypeString; - switch(rgbType) { + switch (outputFormat) { case 0b00: + outputFormatString = "YUV"; + break; case 0b10: - rgbTypeString = (char*)"Normal RGB Output"; + outputFormatString = "RGB"; break; case 0b01: - rgbTypeString = (char*)"RGB 565"; + outputFormatString = "Raw Bayer RGB"; break; case 0b11: - rgbTypeString = (char*)"RGB 555"; + outputFormatString = "Process Bayer RGB"; break; default: - rgbTypeString = (char*)"Unknown"; + outputFormatString = "Unknown"; break; + } + ESP_LOGD(LOG_TAG, "Output format: %s", outputFormatString.c_str()); + if (outputFormat == 0b10) { + uint8_t com15 = readRegister(OV7670_REG_COM15); + uint8_t rgbType = getBit(com15, 5) << 1 | getBit(com15, 4); + char* rgbTypeString; + switch (rgbType) { + case 0b00: + case 0b10: + rgbTypeString = (char*) "Normal RGB Output"; + break; + case 0b01: + rgbTypeString = (char*) "RGB 565"; + break; + case 0b11: + rgbTypeString = (char*) "RGB 555"; + break; + default: + rgbTypeString = (char*) "Unknown"; + break; } ESP_LOGD(LOG_TAG, "Rgb Type: %s", rgbTypeString); } - ESP_LOGD(LOG_TAG, "Color bar: %s", getBit(com7, 1)?"Enabled":"Disabled"); + ESP_LOGD(LOG_TAG, "Color bar: %s", getBit(com7, 1) ? "Enabled" : "Disabled"); uint8_t scaling_xsc = readRegister(OV7670_REG_SCALING_XSC); uint8_t scaling_ysc = readRegister(OV7670_REG_SCALING_YSC); uint32_t testPattern = getBit(scaling_xsc, 7) << 1 | getBit(scaling_ysc, 7); - char *testPatternString; - switch(testPattern) { - case 0b00: - testPatternString = (char*)"No test output"; - break; - case 0b01: - testPatternString = (char*)"Shifting 1"; - break; - case 0b10: - testPatternString = (char*)"8-bar color bar"; - break; - case 0b11: - testPatternString = (char*)"Fade to gray color bar"; - break; - default: - testPatternString = (char*)"Unknown"; - break; + char* testPatternString; + switch (testPattern) { + case 0b00: + testPatternString = (char*) "No test output"; + break; + case 0b01: + testPatternString = (char*) "Shifting 1"; + break; + case 0b10: + testPatternString = (char*) "8-bar color bar"; + break; + case 0b11: + testPatternString = (char*) "Fade to gray color bar"; + break; + default: + testPatternString = (char*) "Unknown"; + break; } ESP_LOGD(LOG_TAG, "Test pattern: %s", testPatternString); ESP_LOGD(LOG_TAG, "Horizontal scale factor: %d", scaling_xsc & 0x3f); ESP_LOGD(LOG_TAG, "Vertical scale factor: %d", scaling_ysc & 0x3f); uint8_t com15 = readRegister(OV7670_REG_COM15); - switch((com15 & 0b11000000) >> 6) { - case 0b00: - case 0b01: - ESP_LOGD(LOG_TAG, "Output range: 0x10 to 0xf0"); - break; - case 0b10: - ESP_LOGD(LOG_TAG, "Output range: 0x01 to 0xfe"); - break; - case 0b11: - ESP_LOGD(LOG_TAG, "Output range: 0x00 to 0xff"); - break; + switch ((com15 & 0b11000000) >> 6) { + case 0b00: + case 0b01: + ESP_LOGD(LOG_TAG, "Output range: 0x10 to 0xf0"); + break; + case 0b10: + ESP_LOGD(LOG_TAG, "Output range: 0x01 to 0xfe"); + break; + case 0b11: + ESP_LOGD(LOG_TAG, "Output range: 0x00 to 0xff"); + break; + default: + break; } } // dump /* -static void log(char *marker) { +static void log(char* marker) { ESP_LOGD(LOG_TAG, "%s", marker); FreeRTOS::sleep(100); } @@ -394,7 +397,7 @@ void OV7670::init(camera_config_t cameraConfig) { // Create the I2C interface. m_i2c = new I2C(); - m_i2c->init(OV7670_I2C_ADDR, (gpio_num_t)m_cameraConfig.pin_sscb_sda, (gpio_num_t)m_cameraConfig.pin_sscb_scl); + m_i2c->init(OV7670_I2C_ADDR, (gpio_num_t) m_cameraConfig.pin_sscb_sda, (gpio_num_t) m_cameraConfig.pin_sscb_scl); m_i2c->scan(); ESP_LOGD(LOG_TAG, "Do you see 0x21 listed?"); resetCamera(); @@ -430,46 +433,42 @@ void OV7670::init(camera_config_t cameraConfig) { } */ - I2S i2s; - dma_config_t dmaConfig; - dmaConfig.pin_d0 = cameraConfig.pin_d0; - dmaConfig.pin_d1 = cameraConfig.pin_d1; - dmaConfig.pin_d2 = cameraConfig.pin_d2; - dmaConfig.pin_d3 = cameraConfig.pin_d3; - dmaConfig.pin_d4 = cameraConfig.pin_d4; - dmaConfig.pin_d5 = cameraConfig.pin_d5; - dmaConfig.pin_d6 = cameraConfig.pin_d6; - dmaConfig.pin_d7 = cameraConfig.pin_d7; - dmaConfig.pin_href = cameraConfig.pin_href; - dmaConfig.pin_pclk = cameraConfig.pin_pclk; - dmaConfig.pin_vsync = cameraConfig.pin_vsync; - i2s.cameraMode(dmaConfig, 50, 360*2); - ESP_LOGD(LOG_TAG, "Waiting for data!"); - while(1) { - DMAData dmaData = i2s.waitForData(); - //GeneralUtils::hexDump(dmaData.getData(), dmaData.getLength()); - toGrayscale(dmaData.getData(), dmaData.getLength()); - dmaData.free(); - } - - ESP_LOGD(LOG_TAG, "Waiting for positive edge on VSYNC"); - while (gpio_get_level(m_cameraConfig.pin_vsync) == 0) { - ; - } - while (gpio_get_level(m_cameraConfig.pin_vsync) != 0) { - ; - } - - - ESP_LOGD(LOG_TAG, "Got VSYNC"); - - - - - while(1) { - FreeRTOS::sleep(1000); - ESP_LOGD(LOG_TAG, "VSYNC Counter: %d, lastHref=%d, pclk=%d", vsyncCounter, lastHref, pclkCounter); - } + I2S i2s; + dma_config_t dmaConfig; + dmaConfig.pin_d0 = cameraConfig.pin_d0; + dmaConfig.pin_d1 = cameraConfig.pin_d1; + dmaConfig.pin_d2 = cameraConfig.pin_d2; + dmaConfig.pin_d3 = cameraConfig.pin_d3; + dmaConfig.pin_d4 = cameraConfig.pin_d4; + dmaConfig.pin_d5 = cameraConfig.pin_d5; + dmaConfig.pin_d6 = cameraConfig.pin_d6; + dmaConfig.pin_d7 = cameraConfig.pin_d7; + dmaConfig.pin_href = cameraConfig.pin_href; + dmaConfig.pin_pclk = cameraConfig.pin_pclk; + dmaConfig.pin_vsync = cameraConfig.pin_vsync; + i2s.cameraMode(dmaConfig, 50, 360 * 2); + ESP_LOGD(LOG_TAG, "Waiting for data!"); + while (true) { + DMAData dmaData = i2s.waitForData(); +// GeneralUtils::hexDump(dmaData.getData(), dmaData.getLength()); + toGrayscale(dmaData.getData(), dmaData.getLength()); + dmaData.free(); + } + + ESP_LOGD(LOG_TAG, "Waiting for positive edge on VSYNC"); + while (gpio_get_level(m_cameraConfig.pin_vsync) == 0) { + ; + } + while (gpio_get_level(m_cameraConfig.pin_vsync) != 0) { + ; + } + + ESP_LOGD(LOG_TAG, "Got VSYNC"); + + while (true) { + FreeRTOS::sleep(1000); + ESP_LOGD(LOG_TAG, "VSYNC Counter: %d, lastHref=%d, pclk=%d", vsyncCounter, lastHref, pclkCounter); + } ESP_LOGD(LOG_TAG, "<< init"); } // init diff --git a/cpp_utils/OV7670.h b/cpp_utils/OV7670.h index b7baf1f9..0fb4fa19 100644 --- a/cpp_utils/OV7670.h +++ b/cpp_utils/OV7670.h @@ -198,11 +198,13 @@ class OV7670 { void setRGBFormat(uint8_t value); void setTestPattern(uint8_t value); void resetCamera(); + private: uint8_t readRegister(uint8_t reg); void writeRegister(uint8_t reg, uint8_t value); camera_config_t m_cameraConfig; - I2C *m_i2c; + I2C* m_i2c; + }; #endif /* CPP_UTILS_OV7670_H_ */ diff --git a/cpp_utils/PCF8574.cpp b/cpp_utils/PCF8574.cpp index 4d850a8b..d246b7a6 100644 --- a/cpp_utils/PCF8574.cpp +++ b/cpp_utils/PCF8574.cpp @@ -18,14 +18,17 @@ * @param [in] address The %I2C address of the device on the %I2C bus. */ PCF8574::PCF8574(uint8_t address) { - i2c.setAddress(address); + i2c = new I2C(); + i2c->setAddress(address); lastWrite = 0; } + /** * @brief Class instance destructor. */ PCF8574::~PCF8574() { + delete i2c; } @@ -35,9 +38,9 @@ PCF8574::~PCF8574() { */ uint8_t PCF8574::read() { uint8_t value; - i2c.beginTransaction(); - i2c.read(&value,true); - i2c.endTransaction(); + i2c->beginTransaction(); + i2c->read(&value,true); + i2c->endTransaction(); return value; } // read @@ -49,11 +52,9 @@ uint8_t PCF8574::read() { * @return True if the pin is high, false otherwise. Undefined if there is no signal on the pin. */ bool PCF8574::readBit(uint8_t bit) { - if (bit > 7) { - return false; - } + if (bit > 7) return false; uint8_t value = read(); - return (value & (1<beginTransaction(); + i2c->write(value, true); + i2c->endTransaction(); lastWrite = value; } // write @@ -83,9 +84,7 @@ void PCF8574::write(uint8_t value) { * @param [in] value The logic level to appear on the identified output pin. */ void PCF8574::writeBit(uint8_t bit, bool value) { - if (bit > 7) { - return; - } + if (bit > 7) return; if (invert) { value = !value; } @@ -117,5 +116,6 @@ void PCF8574::setInvert(bool value) { * @param [in] clkPin The pin to use for the %I2C CLK functions. */ void PCF8574::init(gpio_num_t sdaPin, gpio_num_t clkPin) { - i2c.init(0, sdaPin, clkPin); + uint8_t addr = i2c->getAddress(); + i2c->init(addr, sdaPin, clkPin); } // init diff --git a/cpp_utils/PCF8574.h b/cpp_utils/PCF8574.h index 15b11da9..b8c287f4 100644 --- a/cpp_utils/PCF8574.h +++ b/cpp_utils/PCF8574.h @@ -21,7 +21,7 @@ class PCF8574 { public: PCF8574(uint8_t address); virtual ~PCF8574(); - void init(gpio_num_t sdaPin=I2C::DEFAULT_SDA_PIN, gpio_num_t clkPin=I2C::DEFAULT_CLK_PIN); + void init(gpio_num_t sdaPin = I2C::DEFAULT_SDA_PIN, gpio_num_t clkPin = I2C::DEFAULT_CLK_PIN); uint8_t read(); bool readBit(uint8_t bit); void setInvert(bool value); @@ -29,9 +29,10 @@ class PCF8574 { void writeBit(uint8_t bit, bool value); private: - I2C i2c = I2C(); + I2C* i2c; uint8_t lastWrite; bool invert = false; + }; #endif /* COMPONENTS_CPP_UTILS_PCF8574_H_ */ diff --git a/cpp_utils/PCF8575.cpp b/cpp_utils/PCF8575.cpp index 3714abb1..ea322ef2 100644 --- a/cpp_utils/PCF8575.cpp +++ b/cpp_utils/PCF8575.cpp @@ -8,6 +8,7 @@ #include "PCF8575.h" #include "I2C.h" + /** * @brief Class constructor. * @@ -18,14 +19,17 @@ * @param [in] address The %I2C address of the device on the %I2C bus. */ PCF8575::PCF8575(uint8_t address) { - i2c.setAddress(address); + i2c = new I2C(); + i2c->setAddress(address); m_lastWrite = 0; } + /** * @brief Class instance destructor. */ PCF8575::~PCF8575() { + delete i2c; } @@ -35,10 +39,10 @@ PCF8575::~PCF8575() { */ uint16_t PCF8575::read() { uint16_t value; - i2c.beginTransaction(); - i2c.read((uint8_t*)&value,true); - i2c.read(((uint8_t*)&value) + 1,true); - i2c.endTransaction(); + i2c->beginTransaction(); + i2c->read((uint8_t*) &value, true); + i2c->read(((uint8_t*) &value) + 1, true); + i2c->endTransaction(); return value; } // read @@ -50,11 +54,9 @@ uint16_t PCF8575::read() { * @return True if the pin is high, false otherwise. Undefined if there is no signal on the pin. */ bool PCF8575::readBit(uint16_t bit) { - if (bit > 7) { - return false; - } + if (bit > 7) return false; uint16_t value = read(); - return (value & (1<> 8) & 0xff, true); - i2c.endTransaction(); + i2c->beginTransaction(); + i2c->write(value & 0xff, true); + i2c->write((value >> 8) & 0xff, true); + i2c->endTransaction(); m_lastWrite = value; } // write @@ -85,16 +87,14 @@ void PCF8575::write(uint16_t value) { * @param [in] value The logic level to appear on the identified output pin. */ void PCF8575::writeBit(uint16_t bit, bool value) { - if (bit > 15) { - return; - } + if (bit > 15) return; if (invert) { value = !value; } if (value) { - m_lastWrite |= (1<init(0, sdaPin, clkPin); } // init diff --git a/cpp_utils/PCF8575.h b/cpp_utils/PCF8575.h index 467fae6c..0153124c 100644 --- a/cpp_utils/PCF8575.h +++ b/cpp_utils/PCF8575.h @@ -21,7 +21,7 @@ class PCF8575 { public: PCF8575(uint8_t address); virtual ~PCF8575(); - void init(gpio_num_t sdaPin=I2C::DEFAULT_SDA_PIN, gpio_num_t clkPin=I2C::DEFAULT_CLK_PIN); + void init(gpio_num_t sdaPin = I2C::DEFAULT_SDA_PIN, gpio_num_t clkPin = I2C::DEFAULT_CLK_PIN); uint16_t read(); bool readBit(uint16_t bit); void setInvert(bool value); @@ -29,8 +29,8 @@ class PCF8575 { void writeBit(uint16_t bit, bool value); private: - I2C i2c = I2C(); - uint8_t m_lastWrite; + I2C* i2c; + uint16_t m_lastWrite; bool invert = false; }; diff --git a/cpp_utils/PWM.cpp b/cpp_utils/PWM.cpp index f7119c4a..e67bd4fd 100644 --- a/cpp_utils/PWM.cpp +++ b/cpp_utils/PWM.cpp @@ -97,7 +97,7 @@ void PWM::setDuty(uint32_t duty) { */ void PWM::setDutyPercentage(uint8_t percent) { uint32_t max; - switch(m_dutyResolution) { + switch (m_dutyResolution) { case LEDC_TIMER_10_BIT: max = 1 << 10; break; @@ -120,15 +120,10 @@ void PWM::setDutyPercentage(uint8_t percent) { max = 1 << 10; break; } - if (percent > 100) { - percent = 100; - } + if (percent > 100) percent = 100; uint32_t value = max * percent / 100; - if (value >= max) { - value = max-1; - } + if (value >= max) value = max - 1; setDuty(value); - } // setDutyPercentage @@ -150,5 +145,5 @@ void PWM::setFrequency(uint32_t freq) { * @return N/A. */ void PWM::stop(bool idleLevel) { - ESP_ERROR_CHECK(::ledc_stop(LEDC_HIGH_SPEED_MODE, m_channel, idleLevel)); + ESP_ERROR_CHECK(::ledc_stop(LEDC_HIGH_SPEED_MODE, m_channel, idleLevel ? 1 : 0)); } // stop diff --git a/cpp_utils/PWM.h b/cpp_utils/PWM.h index 01c30a48..8cc1ce39 100644 --- a/cpp_utils/PWM.h +++ b/cpp_utils/PWM.h @@ -32,11 +32,13 @@ class PWM { void setDuty(uint32_t duty); void setDutyPercentage(uint8_t percent); void setFrequency(uint32_t freq); - void stop(bool idleLevel=false); + void stop(bool idleLevel = false); + private: ledc_channel_t m_channel; ledc_timer_t m_timer; ledc_timer_bit_t m_dutyResolution; // Bit size of timer. + }; #endif /* COMPONENTS_CPP_UTILS_PWM_H_ */ diff --git a/cpp_utils/PubSubClient.cpp b/cpp_utils/PubSubClient.cpp index 8aaca5eb..ae95bb33 100644 --- a/cpp_utils/PubSubClient.cpp +++ b/cpp_utils/PubSubClient.cpp @@ -30,6 +30,7 @@ class PubSubClientTask: public Task { Task(name, 16 * 1024) { taskName = name; }; + private: std::string taskName; /** @@ -40,30 +41,24 @@ class PubSubClientTask: public Task { PubSubClient* pPubSubClient = (PubSubClient*) data; ESP_LOGD("PubSubClientTask", "PubSubClientTask Task started!"); - while(1) { + while (true) { if (pPubSubClient->connected()) { - uint16_t len = pPubSubClient->readPacket(); if (len > 0) { // if there was data pPubSubClient->keepAliveTimer->reset(0); //lastInActivity = t; - mqtt_message *msg = new mqtt_message; + mqtt_message* msg = new mqtt_message; pPubSubClient->parseData(msg, len); //pPubSubClient->dumpData(msg); ESP_LOGD(TAG, "Message type (%s)!", pPubSubClient->messageType_toString(msg->type).c_str()); - if (msg->type == PUBLISH) { - if (pPubSubClient->callback) { - if (msg->qos == QOS0) { - pPubSubClient->callback(msg->topic, msg->payload); - } else if (msg->qos == QOS1) { pPubSubClient->callback(msg->topic, msg->payload); @@ -73,31 +68,27 @@ class PubSubClientTask: public Task { pPubSubClient->buffer[3] = (msg->msgId & 0xFF); int rc = pPubSubClient->_client->send(pPubSubClient->buffer, 4); - if(rc < 0) pPubSubClient->_state = CONNECTION_LOST; + if (rc < 0) pPubSubClient->_state = CONNECTION_LOST; pPubSubClient->keepAliveTimer->reset(0); //lastOutActivity = t; - - }else if(msg->qos == QOS2) { + } else if(msg->qos == QOS2) { ESP_LOGD(TAG, "QOS2 is not supported!"); - }else{ + } else { ESP_LOGD(TAG, "QOS-Level unkonwon yet!"); } - } } else if (msg->type == PINGREQ) { pPubSubClient->buffer[0] = PINGRESP; pPubSubClient->buffer[1] = 0; int rc = pPubSubClient->_client->send(pPubSubClient->buffer, 2); - if(rc < 0) pPubSubClient->_state = CONNECTION_LOST; + if (rc < 0) pPubSubClient->_state = CONNECTION_LOST; } else if (msg->type == PINGRESP) { pPubSubClient->PING_outstanding = false; - - }else if (msg->type == SUBACK) { + } else if (msg->type == SUBACK) { pPubSubClient->SUBACK_outstanding = false; pPubSubClient->timeoutTimer->stop(0); - - }else if (msg->type == UNSUBACK) { + } else if (msg->type == UNSUBACK) { pPubSubClient->UNSUBACK_Outstanding = false; pPubSubClient->timeoutTimer->stop(0); } @@ -105,10 +96,11 @@ class PubSubClientTask: public Task { delete(msg); } } - } // While (1) + } // while (true) } // run }; // PubSubClientTask + PubSubClient::PubSubClient() { setup(); this->_state = DISCONNECTED; @@ -116,12 +108,14 @@ PubSubClient::PubSubClient() { setCallback(NULL); } + PubSubClient::PubSubClient(Socket& client) { setup(); this->_state = DISCONNECTED; setClient(client); } + PubSubClient::PubSubClient(std::string addr, uint16_t port) { setup(); this->_state = DISCONNECTED; @@ -129,6 +123,7 @@ PubSubClient::PubSubClient(std::string addr, uint16_t port) { setServer(addr, port); } + PubSubClient::PubSubClient(std::string addr, uint16_t port, Socket& client) { setup(); this->_state = DISCONNECTED; @@ -136,8 +131,8 @@ PubSubClient::PubSubClient(std::string addr, uint16_t port, Socket& client) { setClient(client); } -PubSubClient::PubSubClient(std::string addr, uint16_t port, - MQTT_CALLBACK_SIGNATURE, Socket& client) { + +PubSubClient::PubSubClient(std::string addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Socket& client) { setup(); this->_state = DISCONNECTED; setServer(addr, port); @@ -145,6 +140,7 @@ PubSubClient::PubSubClient(std::string addr, uint16_t port, setClient(client); } + PubSubClient::~PubSubClient() { _client->close(); keepAliveTimer->stop(0); @@ -156,44 +152,46 @@ PubSubClient::~PubSubClient() { delete (m_task); } + /** * @brief This is a Timer called routine mapping routine, which calls * the PubSubClient member function keepAliveChecker. * @param The FreeRTOSTimer root instance for this callback function. * @return N/A. */ -void keepAliveTimerMapper(FreeRTOSTimer *pTimer) { +void keepAliveTimerMapper(FreeRTOSTimer* pTimer) { PubSubClient* m_pubSubClient = (PubSubClient*) pTimer->getData(); m_pubSubClient->keepAliveChecker(); } //keepAliveChecker + /** * @brief This is a Timer called routine mapping routine, which calls * the PubSubClient member function timeoutChecker. * @param The FreeRTOSTimer root instance for this callback function. * @return N/A. */ -void timeoutTimerMapper(FreeRTOSTimer *pTimer) { +void timeoutTimerMapper(FreeRTOSTimer* pTimer) { PubSubClient* m_pubSubClient = (PubSubClient*) pTimer->getData(); m_pubSubClient->timeoutChecker(); } //keepAliveChecker + /** * @brief This is a internal setup routine for the PubSubClient. * @param N/A. * @return N/A. */ -void PubSubClient::setup(void) { +void PubSubClient::setup() { PING_outstanding = false; SUBACK_outstanding = false; UNSUBACK_Outstanding = false; - keepAliveTimer = new FreeRTOSTimer((char*) "keepAliveTimer", - (MQTT_KEEPALIVE * 1000) / portTICK_PERIOD_MS, true, this, + (MQTT_KEEPALIVE * 1000) / portTICK_PERIOD_MS, pdTRUE, this, keepAliveTimerMapper); timeoutTimer = new FreeRTOSTimer((char*) "timeoutTimer", - (MQTT_KEEPALIVE * 1000) / portTICK_PERIOD_MS, true, this, + (MQTT_KEEPALIVE * 1000) / portTICK_PERIOD_MS, pdTRUE, this, timeoutTimerMapper); m_task = new PubSubClientTask("PubSubClientTask"); } // setup @@ -208,8 +206,8 @@ void PubSubClient::setup(void) { * @param N/A. * @return N/A. */ -void PubSubClient::keepAliveChecker(void){ +void PubSubClient::keepAliveChecker() { if (PING_outstanding && connected()) { _state = CONNECTION_TIMEOUT; //_client->close(); @@ -218,7 +216,7 @@ void PubSubClient::keepAliveChecker(void){ buffer[0] = PINGREQ; buffer[1] = 0; int rc = _client->send(buffer, 2); - if(rc < 0) _state = CONNECTION_LOST; + if (rc < 0) _state = CONNECTION_LOST; ESP_LOGD(TAG, "send KeepAlive REQUEST!"); PING_outstanding = true; } @@ -232,8 +230,7 @@ void PubSubClient::keepAliveChecker(void){ * @param N/A. * @return N/A. */ -void PubSubClient::timeoutChecker(void){ - +void PubSubClient::timeoutChecker() { if (connected() && (SUBACK_outstanding || UNSUBACK_Outstanding)) { _state = CONNECTION_TIMEOUT; //_client->close(); @@ -241,15 +238,17 @@ void PubSubClient::timeoutChecker(void){ } } //keepAliveChecker + /** * @brief Connect to a MQTT server. * @param [in] Device id to identify this device. * @return success (true), or no success (false). */ -bool PubSubClient::connect(const char *id) { +bool PubSubClient::connect(const char* id) { return connect(id, NULL, NULL, 0, 0, 0, 0); } + /** * @brief Connect to a MQTT server. * @param [in] Device id to identify this device. @@ -257,10 +256,11 @@ bool PubSubClient::connect(const char *id) { * [in] my password. * @return success (true), or no success (false). */ -bool PubSubClient::connect(const char *id, const char *user, const char *pass) { +bool PubSubClient::connect(const char* id, const char* user, const char* pass) { return connect(id, user, pass, 0, 0, 0, 0); } + /** * @brief Connect to a MQTT server. * @param [in] Device id to identify this device. @@ -270,11 +270,11 @@ bool PubSubClient::connect(const char *id, const char *user, const char *pass) { * [in] last will: payload. * @return success (true), or no success (false). */ -bool PubSubClient::connect(const char *id, const char* willTopic, - uint8_t willQos, bool willRetain, const char* willMessage) { +bool PubSubClient::connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage) { return connect(id, NULL, NULL, willTopic, willQos, willRetain, willMessage); } + /** * @brief Connect to a MQTT server. * @param [in] Device id to identify this device. @@ -286,9 +286,7 @@ bool PubSubClient::connect(const char *id, const char* willTopic, * [in] last will: payload. * @return success (true), or no success (false). */ -bool PubSubClient::connect(const char *id, const char *user, const char *pass, - const char* willTopic, uint8_t willQos, bool willRetain, - const char* willMessage) { +bool PubSubClient::connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage) { _config.id = id; _config.user = user; @@ -302,6 +300,7 @@ bool PubSubClient::connect(const char *id, const char *user, const char *pass, return connect(); } + /** * @brief Connect to a MQTT server with the with the previous settings. * Note: do not call this function without settings, this will not work! @@ -309,30 +308,25 @@ bool PubSubClient::connect(const char *id, const char *user, const char *pass, * @param N/A * @return success (true), or no success (false). */ -bool PubSubClient::connect(){ - +bool PubSubClient::connect() { if (!connected()) { - ESP_LOGD(TAG, "Connect to mqtt server..."); - ESP_LOGD(TAG, "ip: %s port: %d", _config.ip.c_str(), _config.port); int result = _client->connect((char *)_config.ip.c_str(), _config.port); if (result == 0) { - nextMsgId = 1; // Leave room in the buffer for header and variable length field uint16_t length = 5; - unsigned int j; #if MQTT_VERSION == MQTT_VERSION_3_1 - uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; + uint8_t d[9] = { 0x00, 0x06, 'M', 'Q', 'I', 's', 'd', 'p', MQTT_VERSION }; #define MQTT_HEADER_VERSION_LENGTH 9 #elif MQTT_VERSION == MQTT_VERSION_3_1_1 uint8_t d[7] = { 0x00, 0x04, 'M', 'Q', 'T', 'T', MQTT_VERSION }; #define MQTT_HEADER_VERSION_LENGTH 7 #endif - for (j = 0; j < MQTT_HEADER_VERSION_LENGTH; j++) { + for (unsigned int j = 0; j < MQTT_HEADER_VERSION_LENGTH; j++) { buffer[length++] = d[j]; } @@ -399,22 +393,23 @@ bool PubSubClient::connect(){ return true; } + /** * @brief Receiving a MQTT packet and store it in the buffer to parse it. * @param N/A. * @return Number of received bytes. */ -uint16_t PubSubClient::readPacket() { - +size_t PubSubClient::readPacket() { size_t res = _client->receive(buffer, MQTT_MAX_PACKET_SIZE); if (res > MQTT_MAX_PACKET_SIZE) { res = 0; // This will cause the packet to be ignored. } - return res; + return (uint16_t) res; } + /** * @brief Publish a MQTT message. * @param [in] my topic. @@ -425,6 +420,7 @@ bool PubSubClient::publish(const char* topic, const char* payload) { return publish(topic, (const uint8_t*) payload, strlen(payload), false); } + /** * @brief Publish a MQTT message. * @param [in] my topic. @@ -432,11 +428,11 @@ bool PubSubClient::publish(const char* topic, const char* payload) { * [in] is this a retained message (true/false) * @return success (true), or no success (false). */ -bool PubSubClient::publish(const char* topic, const char* payload, - bool retained) { +bool PubSubClient::publish(const char* topic, const char* payload, bool retained) { return publish(topic, (const uint8_t*) payload, strlen(payload), retained); } + /** * @brief Publish a MQTT message. * @param [in] my topic. @@ -444,11 +440,11 @@ bool PubSubClient::publish(const char* topic, const char* payload, * [in] length of the message * @return success (true), or no success (false). */ -bool PubSubClient::publish(const char* topic, const uint8_t* payload, - unsigned int plength) { +bool PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { return publish(topic, payload, plength, false); } + /** * @brief Publish a MQTT message. * @param [in] my topic. @@ -457,8 +453,7 @@ bool PubSubClient::publish(const char* topic, const uint8_t* payload, * [in] is this a retained message (true/false) * @return success (true), or no success (false). */ -bool PubSubClient::publish(const char* topic, const uint8_t* payload, - unsigned int plength, bool retained) { +bool PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, bool retained) { if (connected()) { if (MQTT_MAX_PACKET_SIZE < 5 + 2 + strlen(topic) + plength) { // Too long @@ -480,6 +475,7 @@ bool PubSubClient::publish(const char* topic, const uint8_t* payload, return false; } + //bool PubSubClient::publish_P(const char* topic, const uint8_t* payload, // unsigned int plength, bool retained) { // uint8_t llen = 0; @@ -527,6 +523,7 @@ bool PubSubClient::publish(const char* topic, const uint8_t* payload, // return rc == tlen + 4 + plength; //} + /** * @brief Send a MQTT message over socket. * @param [in] MQTT header. @@ -557,13 +554,13 @@ bool PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { } //#ifdef MQTT_MAX_TRANSFER_SIZE -// uint8_t* writeBuf = buf+(4-llen); -// uint16_t bytesRemaining = length+1+llen; //Match the length type +// uint8_t* writeBuf = buf + (4 - llen); +// uint16_t bytesRemaining = length + 1 + llen; //Match the length type // uint8_t bytesToWrite; // bool result = true; -// while((bytesRemaining > 0) && result) { -// bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; -// rc = _client->write(writeBuf,bytesToWrite); +// while ((bytesRemaining > 0) && result) { +// bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE) ? MQTT_MAX_TRANSFER_SIZE : bytesRemaining; +// rc = _client->write(writeBuf, bytesToWrite); // result = (rc == bytesToWrite); // bytesRemaining -= rc; // writeBuf += rc; @@ -577,6 +574,7 @@ bool PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { //#endif } + /** * @brief Subscribe a MQTT topic. * @param [in] my topic @@ -584,11 +582,8 @@ bool PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { * @return request transmitted with success (true), or no success (false). */ bool PubSubClient::subscribe(const char* topic, bool ack) { + if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) return false; // Too long - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { - // Too long - return false; - } if (connected()) { // Leave room in the buffer for header and variable length field uint16_t length = 5; @@ -601,36 +596,35 @@ bool PubSubClient::subscribe(const char* topic, bool ack) { length = writeString(topic, buffer, length); buffer[length++] = QOS1; - if(write(SUBSCRIBE | QOS1, buffer, length - 5)){ + if (write(SUBSCRIBE | QOS1, buffer, length - 5)) { SUBACK_outstanding = true; - if(ack) timeoutTimer->start(0); + if (ack) timeoutTimer->start(0); return true; } } return false; } + /** * @brief Check the state of subscription. If there was received a subscription * ACK, we return a true here. * @return Is subscription validated with ACK (true/false) */ -bool PubSubClient::isSubscribeDone(void){ +bool PubSubClient::isSubscribeDone() { return !SUBACK_outstanding; } + /** * @brief Unsubscribe a MQTT topic. * @param [in] my topic * [in] qos of unsubscription * @return request transmitted with success (true), or no success (false). */ -bool PubSubClient::unsubscribe(const char* topic, bool ack) { +bool PubSubClient::unsubscribe(const char* topic, bool ack) { + if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) return false; // Too long - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { - // Too long - return false; - } if (connected()) { uint16_t length = 5; nextMsgId++; @@ -641,24 +635,26 @@ bool PubSubClient::unsubscribe(const char* topic, bool ack) { buffer[length++] = (nextMsgId & 0xFF); length = writeString(topic, buffer, length); - if(write(UNSUBSCRIBE | QOS1, buffer, length - 5)){ + if (write(UNSUBSCRIBE | QOS1, buffer, length - 5)) { UNSUBACK_Outstanding = true; - if(ack) timeoutTimer->start(0); + if (ack) timeoutTimer->start(0); return true; } } return false; } + /** * @brief Check the state of unsubscription. If there was received a unsubscription * ACK, we return a true here. * @return Is unsubscription validated with ACK (true/false) */ -bool PubSubClient::isUnsubscribeDone(void){ +bool PubSubClient::isUnsubscribeDone() { return !UNSUBACK_Outstanding; } + /** * @brief Disconnect form MQTT server and close the socket. * @return N/A. @@ -673,11 +669,11 @@ void PubSubClient::disconnect() { timeoutTimer->stop(0); } + /** * @brief calculation help to send a string. */ -uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, - uint16_t pos) { +uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) { const char* idp = string; uint16_t i = 0; pos += 2; @@ -690,34 +686,30 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, return pos; } + /** * @brief Check the connection to the MQTT server. * @return connected (true/false) */ bool PubSubClient::connected() { + if (this->_state != CONNECTED) return false; + bool rc = true; - if (this->_state == CONNECTED) { - - bool rc = true; - - if (_client == nullptr) { - rc = false; - } else if (!_client->isValid()) { - rc = false; + if (_client == nullptr) { + rc = false; + } else if (!_client->isValid()) { + rc = false; - this->_state = CONNECTION_LOST; + this->_state = CONNECTION_LOST; - if (_client->isValid()) _client->close(); - keepAliveTimer->stop(0); - timeoutTimer->stop(0); - } - return rc; + if (_client->isValid()) _client->close(); + keepAliveTimer->stop(0); + timeoutTimer->stop(0); } - return false; - ESP_LOGD(TAG, "_state = %d", _state); - + return rc; } + /** * @brief Set server ip and Port of my MQTT server. * @param [in] ip of the distant MQTT server. @@ -730,6 +722,7 @@ PubSubClient& PubSubClient::setServer(std::string ip, uint16_t port) { return *this; } + /** * @brief Set the callback function for incoming data. * @param [in] callback function @@ -740,6 +733,7 @@ PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) { return *this; } + /** * @brief Set the socket, which we want to use for our MQTT communication. * @param [in] the new socket instance @@ -750,6 +744,7 @@ PubSubClient& PubSubClient::setClient(Socket& client) { return *this; } + /** * @brief Get the current MYTT state form the instance. * @param N/A. @@ -759,25 +754,28 @@ int PubSubClient::state() { return this->_state; } + /** * @brief Parsing the received data in to the internal message struct. */ -void PubSubClient::parseData(mqtt_message* msg, uint16_t len){ - +void PubSubClient::parseData(mqtt_message* msg, uint16_t len) { /********* Parse Fixed header *********/ msg->type = buffer[0] & 0xF0; /* read DUP-Flag */ - if(msg->type == PUBLISH) - msg->dup = (bool)(buffer[0] & 0x18)>>3; + if (msg->type == PUBLISH) { + msg->dup = (bool) (buffer[0] & 0x18) >> 3; + } /* read QoS-Level */ - if(msg->type == PUBLISH) + if(msg->type == PUBLISH) { msg->qos = (buffer[0] & 0x06); + } /* read RETAIN-Frag */ - if(msg->type == PUBLISH) - msg->retained = (bool)(buffer[0] & 0x01); + if(msg->type == PUBLISH) { + msg->retained = (bool) (buffer[0] & 0x01); + } uint8_t remainingLength = buffer[1]; @@ -785,36 +783,36 @@ void PubSubClient::parseData(mqtt_message* msg, uint16_t len){ int pos = 2; /* read topic name */ - if(msg->type == PUBLISH){ + if (msg->type == PUBLISH) { uint16_t topicLen = (buffer[2] << 8) + buffer[3]; msg->topic = ""; - for(int i = 4; i<(topicLen+4); i++){ + for (int i = 4; i < (topicLen + 4); i++) { msg->topic += (char) buffer[i]; pos++; } } /* read Message ID */ - if(msg->type == PUBLISH || msg->type == PUBACK || msg->type == PUBREC || msg->type == PUBCOMP || msg->type == SUBACK || msg->type == UNSUBACK){ - msg->msgId = (buffer[pos]<<8) + (buffer[pos+1]); + if (msg->type == PUBLISH || msg->type == PUBACK || msg->type == PUBREC || msg->type == PUBCOMP || msg->type == SUBACK || msg->type == UNSUBACK) { + msg->msgId = (buffer[pos] << 8) + (buffer[pos + 1]); pos += 2; } /********* read Payload *********/ - if(msg->type == PUBLISH){ + if (msg->type == PUBLISH) { msg->payload = ""; - for(int i = pos; i payload += (char)buffer[i]; + for (int i = pos; i < remainingLength + 2; i++) { + msg->payload += (char) buffer[i]; } } } + /** * @brief Dump the message struct. */ -void PubSubClient::dumpData(mqtt_message* msg){ - +void PubSubClient::dumpData(mqtt_message* msg) { ESP_LOGD(TAG, "mqtt_message_type: %s", messageType_toString(msg->type).c_str()); ESP_LOGD(TAG, "mqtt_qos: %d", msg->qos); ESP_LOGD(TAG, "retained: %d", msg->retained); @@ -824,30 +822,31 @@ void PubSubClient::dumpData(mqtt_message* msg){ ESP_LOGD(TAG, "msgId: %d", msg->msgId); } + /** * @brief Convert the MQTT message type to string. * @param [in] message type byte. * @return message type as std::string. */ -std::string PubSubClient::messageType_toString(uint8_t type){ +std::string PubSubClient::messageType_toString(uint8_t type) { std::string str = "Not in list!"; - switch(type){ - case CONNECT : str = "CONNECT"; break; - case CONNACK : str = "CONNACK"; break; - case PUBLISH : str = "PUBLISH"; break; - case PUBACK : str = "PUBACK"; break; - case PUBREC : str = "PUBREC"; break; - case PUBREL : str = "PUBREL"; break; - case PUBCOMP : str = "PUBCOMP"; break; - case SUBSCRIBE : str = "SUBSCRIBE"; break; - case SUBACK : str = "SUBACK"; break; - case UNSUBSCRIBE: str = "UNSUBSCRIBE"; break; - case UNSUBACK : str = "UNSUBACK"; break; - case PINGREQ : str = "PINGREQ"; break; - case PINGRESP : str = "PINGRESP"; break; - case DISCONNECT : str = "DISCONNECT"; break; - case Reserved : str = "Reserved"; break; + switch (type) { + case CONNECT : str = "CONNECT"; break; + case CONNACK : str = "CONNACK"; break; + case PUBLISH : str = "PUBLISH"; break; + case PUBACK : str = "PUBACK"; break; + case PUBREC : str = "PUBREC"; break; + case PUBREL : str = "PUBREL"; break; + case PUBCOMP : str = "PUBCOMP"; break; + case SUBSCRIBE : str = "SUBSCRIBE"; break; + case SUBACK : str = "SUBACK"; break; + case UNSUBSCRIBE: str = "UNSUBSCRIBE"; break; + case UNSUBACK : str = "UNSUBACK"; break; + case PINGREQ : str = "PINGREQ"; break; + case PINGRESP : str = "PINGRESP"; break; + case DISCONNECT : str = "DISCONNECT"; break; + case Reserved : str = "Reserved"; break; + default : break; } - return str; } diff --git a/cpp_utils/PubSubClient.h b/cpp_utils/PubSubClient.h index 8e56ca59..aad1103e 100644 --- a/cpp_utils/PubSubClient.h +++ b/cpp_utils/PubSubClient.h @@ -51,14 +51,14 @@ struct mqtt_InitTypeDef{ const char* user; const char* pass; - const char * id; + const char* id; const char* willTopic; uint8_t willQos; bool willRetain; const char* willMessage; }; -typedef enum{ +typedef enum { CONNECTION_TIMEOUT = -4, CONNECTION_LOST = -3, CONNECT_FAILED = -2, @@ -69,9 +69,9 @@ typedef enum{ CONNECT_UNAVAILABLE = 3, CONNECT_BAD_CREDENTIALS = 4, CONNECT_UNAUTHORIZED = 5, -}mqtt_state; +} mqtt_state; -typedef enum{ +typedef enum { CONNECT = 1 << 4, // Client request to connect to Server CONNACK = 2 << 4, // Connect Acknowledgment PUBLISH = 3 << 4, // Publish message @@ -87,15 +87,15 @@ typedef enum{ PINGRESP = 13 << 4, // PING Response DISCONNECT = 14 << 4, // Client is Disconnecting Reserved = 15 << 4, // Reserved -}mqtt_message_type; +} mqtt_message_type; -typedef enum{ +typedef enum { QOS0 = (0 << 1), QOS1 = (1 << 1), QOS2 = (2 << 1), -}mqtt_qos; +} mqtt_qos; -struct mqtt_message{ +struct mqtt_message { uint8_t type; uint8_t qos; bool retained; @@ -105,7 +105,7 @@ struct mqtt_message{ uint16_t msgId; }; -#define MQTT_CALLBACK_SIGNATURE void (*callback)(std::string, std::string) +#define MQTT_CALLBACK_SIGNATURE void (*callback) (std::string, std::string) class PubSubClientTask; @@ -130,19 +130,19 @@ class PubSubClient { void disconnect(); bool publish(const char* topic, const char* payload); bool publish(const char* topic, const char* payload, bool retained); - bool publish(const char* topic, const uint8_t * payload, unsigned int plength); - bool publish(const char* topic, const uint8_t * payload, unsigned int plength, bool retained); + bool publish(const char* topic, const uint8_t* payload, unsigned int plength); + bool publish(const char* topic, const uint8_t* payload, unsigned int plength, bool retained); //bool publish_P(const char* topic, const uint8_t * payload, unsigned int plength, bool retained); - bool subscribe (const char* topic, bool ack=false); - bool unsubscribe (const char* topic, bool ack=false); - bool isSubscribeDone (void); - bool isUnsubscribeDone (void); + bool subscribe(const char* topic, bool ack = false); + bool unsubscribe(const char* topic, bool ack = false); + bool isSubscribeDone(); + bool isUnsubscribeDone(); - bool connected (void); - int state (void); - void keepAliveChecker (void); - void timeoutChecker (void); + bool connected(); + int state(); + void keepAliveChecker(); + void timeoutChecker(); private: friend class PubSubClientTask; @@ -159,12 +159,12 @@ class PubSubClient { FreeRTOSTimer* timeoutTimer; MQTT_CALLBACK_SIGNATURE; - void setup (void); - uint16_t readPacket(); - bool write (uint8_t header, uint8_t* buf, uint16_t length); + void setup(); + size_t readPacket(); + bool write(uint8_t header, uint8_t* buf, uint16_t length); uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); - void parseData (mqtt_message* msg, uint16_t len); - void dumpData (mqtt_message* msg); + void parseData(mqtt_message* msg, uint16_t len); + void dumpData(mqtt_message* msg); std::string messageType_toString(uint8_t type); }; diff --git a/cpp_utils/RESTClient.cpp b/cpp_utils/RESTClient.cpp index 7160dca6..a72f80b5 100644 --- a/cpp_utils/RESTClient.cpp +++ b/cpp_utils/RESTClient.cpp @@ -17,7 +17,7 @@ #include "RESTClient.h" -static char tag[] = "RESTClient"; +static const char* LOG_TAG = "RESTClient"; RESTClient::RESTClient() { @@ -37,15 +37,15 @@ RESTClient::~RESTClient() { * @brief Perform an HTTP GET request. */ long RESTClient::get() { - long response_code; // Added return response_code 2018_4_12 + long response_code; // Added return response_code 2018_4_12 prepForCall(); ::curl_easy_setopt(m_curlHandle, CURLOPT_HTTPGET, 1); int rc = ::curl_easy_perform(m_curlHandle); if (rc != CURLE_OK) { - ESP_LOGE(tag, "get(): %s", getErrorMessage().c_str()); + ESP_LOGE(LOG_TAG, "get(): %s", getErrorMessage().c_str()); } - curl_easy_getinfo(m_curlHandle, CURLINFO_RESPONSE_CODE, &response_code); // Added return response_code 2018_4_12 - return response_code; // Added return response_code 2018_4_12 + curl_easy_getinfo(m_curlHandle, CURLINFO_RESPONSE_CODE, &response_code); // Added return response_code 2018_4_12 + return response_code; // Added return response_code 2018_4_12 } // get @@ -56,15 +56,15 @@ long RESTClient::get() { * */ long RESTClient::post(std::string body) { - long response_code; // Added return response_code 2018_4_12 + long response_code; // Added return response_code 2018_4_12 prepForCall(); ::curl_easy_setopt(m_curlHandle, CURLOPT_POSTFIELDS, body.c_str()); int rc = ::curl_easy_perform(m_curlHandle); if (rc != CURLE_OK) { - ESP_LOGE(tag, "post(): %s", getErrorMessage().c_str()); + ESP_LOGE(LOG_TAG, "post(): %s", getErrorMessage().c_str()); } - curl_easy_getinfo(m_curlHandle, CURLINFO_RESPONSE_CODE, &response_code);// Added return response_code 2018_4_12 - return response_code;// Added return response_code 2018_4_12 + curl_easy_getinfo(m_curlHandle, CURLINFO_RESPONSE_CODE, &response_code);// Added return response_code 2018_4_12 + return response_code;// Added return response_code 2018_4_12 } // post @@ -90,10 +90,10 @@ std::string RESTClient::getErrorMessage() { * * @return The number of bytes of data processed. */ -size_t RESTClient::handleData(void *buffer, size_t size, size_t nmemb, void *userp) { +size_t RESTClient::handleData(void* buffer, size_t size, size_t nmemb, void* userp) { //printf("handleData: size: %d, num: %d\n", size, nmemb); - RESTClient *pClient = (RESTClient *)userp; - pClient->m_response.append((const char *)buffer, size*nmemb); + RESTClient* pClient = (RESTClient*) userp; + pClient->m_response.append((const char*) buffer, size * nmemb); return size * nmemb; } // handleData @@ -139,7 +139,7 @@ void RESTClient::prepForCall() { } // prepForCall -RESTTimings::RESTTimings(RESTClient *client) { +RESTTimings::RESTTimings(RESTClient* client) { this->client = client; } diff --git a/cpp_utils/RESTClient.h b/cpp_utils/RESTClient.h index 4ad91d5a..f44612ac 100644 --- a/cpp_utils/RESTClient.h +++ b/cpp_utils/RESTClient.h @@ -19,9 +19,10 @@ class RESTClient; */ class RESTTimings { public: - RESTTimings(RESTClient *client); + RESTTimings(RESTClient* client); void refresh(); std::string toString(); + private: double m_namelookup = 0; double m_connect = 0; @@ -29,7 +30,8 @@ class RESTTimings { double m_pretransfer = 0; double m_starttransfer = 0; double m_total = 0; - RESTClient *client = nullptr; + RESTClient* client = nullptr; + }; /** @@ -107,19 +109,18 @@ class RESTClient { m_verbose = value; }; - - private: - CURL *m_curlHandle; + CURL* m_curlHandle; std::string m_url; char m_errbuf[CURL_ERROR_SIZE]; - struct curl_slist *m_headers = nullptr; + struct curl_slist* m_headers = nullptr; bool m_verbose = false; friend class RESTTimings; - RESTTimings *m_timings; + RESTTimings* m_timings; std::string m_response; - static size_t handleData(void *buffer, size_t size, size_t nmemb, void *userp); + static size_t handleData(void* buffer, size_t size, size_t nmemb, void* userp); void prepForCall(); + }; #endif /* CONFIG_LIBCURL_PRESENT */ #endif /* MAIN_RESTCLIENT_H_ */ diff --git a/cpp_utils/RMT.cpp b/cpp_utils/RMT.cpp index 750da1a6..9f9a5950 100644 --- a/cpp_utils/RMT.cpp +++ b/cpp_utils/RMT.cpp @@ -8,6 +8,7 @@ #include #include "RMT.h" + //static char tag[] = "RMT"; /** * @brief Create a class instance. @@ -22,7 +23,7 @@ RMT::RMT(gpio_num_t pin, rmt_channel_t channel) { config.rmt_mode = RMT_MODE_TX; config.channel = channel; config.gpio_num = pin; - config.mem_block_num = 8-this->channel; + config.mem_block_num = 8 - this->channel; config.clk_div = 8; config.tx_config.loop_en = 0; config.tx_config.carrier_en = 0; @@ -32,7 +33,6 @@ RMT::RMT(gpio_num_t pin, rmt_channel_t channel) { config.tx_config.carrier_level = (rmt_carrier_level_t)1; config.tx_config.carrier_duty_percent = 50; - ESP_ERROR_CHECK(rmt_config(&config)); ESP_ERROR_CHECK(rmt_driver_install(this->channel, 0, 0)); } @@ -45,6 +45,7 @@ RMT::~RMT() { ESP_ERROR_CHECK(::rmt_driver_uninstall(this->channel)); } + /** * @brief Start receiving. */ @@ -52,6 +53,7 @@ void RMT::rxStart() { ESP_ERROR_CHECK(::rmt_rx_start(this->channel, true)); } + /** * @brief Stop receiving. */ @@ -59,6 +61,7 @@ void RMT::rxStop() { ESP_ERROR_CHECK(::rmt_rx_stop(this->channel)); } + /** * @brief Start transmitting. */ @@ -66,6 +69,7 @@ void RMT::txStart() { ESP_ERROR_CHECK(::rmt_tx_start(this->channel, true)); } + /** * @brief Stop transmitting. */ @@ -73,6 +77,7 @@ void RMT::txStop() { ESP_ERROR_CHECK(::rmt_tx_stop(this->channel)); } + /** * @brief Write the items out through the RMT. * @@ -81,7 +86,7 @@ void RMT::txStop() { * is cleared. */ void RMT::write() { - add(false,0); + add(false, 0); ESP_ERROR_CHECK(::rmt_write_items(this->channel, &items[0], items.size(), true)); clear(); } @@ -100,12 +105,13 @@ void RMT::add(bool level, uint32_t duration) { item.duration0 = duration; items.push_back(item); } else { - items.at(bitCount/2).level1 = level; - items.at(bitCount/2).duration1 = duration; + items.at(bitCount / 2).level1 = level; + items.at(bitCount / 2).duration1 = duration; } bitCount++; } + /** * @brief Clear any previously written level/duration pairs that have not been sent. */ diff --git a/cpp_utils/RMT.h b/cpp_utils/RMT.h index 90e59007..8c079f80 100644 --- a/cpp_utils/RMT.h +++ b/cpp_utils/RMT.h @@ -15,7 +15,7 @@ */ class RMT { public: - RMT(gpio_num_t pin, rmt_channel_t channel=RMT_CHANNEL_0); + RMT(gpio_num_t pin, rmt_channel_t channel = RMT_CHANNEL_0); virtual ~RMT(); void add(bool level, uint32_t duration); void clear(); @@ -25,11 +25,11 @@ class RMT { void txStop(); void write(); - private: rmt_channel_t channel; std::vector items; int bitCount = 0; + }; #endif /* COMPONENTS_CPP_UTILS_RMT_H_ */ diff --git a/cpp_utils/SOC.cpp b/cpp_utils/SOC.cpp index 2f4d3a9a..fa12d4e6 100644 --- a/cpp_utils/SOC.cpp +++ b/cpp_utils/SOC.cpp @@ -34,9 +34,9 @@ void SOC::I2S::dump() { I2S0.clkm_conf.clka_en); uint32_t clockSpeed; if (I2S0.clkm_conf.clkm_div_a == 0) { - clockSpeed = 160000000/I2S0.clkm_conf.clkm_div_num; + clockSpeed = 160000000 / I2S0.clkm_conf.clkm_div_num; } else { - clockSpeed = 160000000/(I2S0.clkm_conf.clkm_div_num + I2S0.clkm_conf.clkm_div_b/I2S0.clkm_conf.clkm_div_a); + clockSpeed = 160000000 / (I2S0.clkm_conf.clkm_div_num + I2S0.clkm_conf.clkm_div_b / I2S0.clkm_conf.clkm_div_a); } printf("Clock speed: %d\n", clockSpeed); printf("\n"); @@ -44,8 +44,8 @@ void SOC::I2S::dump() { printf("I2S_CONF_REG\n"); printf("------------\n"); printf("tx_slave_mod: %s, rx_slave_mod: %s, rx_msb_right: %d, rx_right_first: %d\n", - I2S0.conf.tx_slave_mod==0?"Master":"Slave", - I2S0.conf.rx_slave_mod==0?"Master":"Slave", + (I2S0.conf.tx_slave_mod == 0) ? "Master" : "Slave", + (I2S0.conf.rx_slave_mod == 0) ? "Master" : "Slave", I2S0.conf.rx_msb_right, I2S0.conf.rx_right_first); printf("\n"); diff --git a/cpp_utils/SPI.cpp b/cpp_utils/SPI.cpp index 5ce45d15..1312e706 100644 --- a/cpp_utils/SPI.cpp +++ b/cpp_utils/SPI.cpp @@ -101,6 +101,7 @@ void SPI::setHost(spi_host_device_t host) { m_host = host; } // setHost + /** * @brief Send and receive data through %SPI. This is a blocking call. * @@ -111,7 +112,7 @@ void SPI::transfer(uint8_t* data, size_t dataLen) { assert(data != nullptr); assert(dataLen > 0); #ifdef DEBUG - for (auto i=0; i %2d %.2x", i, data[i]); } #endif @@ -141,5 +142,3 @@ uint8_t SPI::transferByte(uint8_t value) { transfer(&value, 1); return value; } // transferByte - - diff --git a/cpp_utils/SPI.h b/cpp_utils/SPI.h index d2de5d99..6ecf64e1 100644 --- a/cpp_utils/SPI.h +++ b/cpp_utils/SPI.h @@ -22,32 +22,33 @@ class SPI { int clkPin = DEFAULT_CLK_PIN, int csPin = DEFAULT_CS_PIN); void setHost(spi_host_device_t host); - void transfer(uint8_t *data, size_t dataLen); + void transfer(uint8_t* data, size_t dataLen); uint8_t transferByte(uint8_t value); + /** * @brief The default MOSI pin. */ - static const int DEFAULT_MOSI_PIN = GPIO_NUM_13; - - /** - * @brief The default MISO pin. - */ - static const int DEFAULT_MISO_PIN = GPIO_NUM_12; - - /** - * @brief The default CLK pin. - */ - static const int DEFAULT_CLK_PIN = GPIO_NUM_14; - - /** - * @brief The default CS pin. - */ - static const int DEFAULT_CS_PIN = GPIO_NUM_15; - - /** - * @brief Value of unset pin. - */ - static const int PIN_NOT_SET = -1; + static const int DEFAULT_MOSI_PIN = GPIO_NUM_13; + + /** + * @brief The default MISO pin. + */ + static const int DEFAULT_MISO_PIN = GPIO_NUM_12; + + /** + * @brief The default CLK pin. + */ + static const int DEFAULT_CLK_PIN = GPIO_NUM_14; + + /** + * @brief The default CS pin. + */ + static const int DEFAULT_CS_PIN = GPIO_NUM_15; + + /** + * @brief Value of unset pin. + */ + static const int PIN_NOT_SET = -1; private: spi_device_handle_t m_handle; diff --git a/cpp_utils/SSLUtils.cpp b/cpp_utils/SSLUtils.cpp index 92ebcfc4..36621b3e 100644 --- a/cpp_utils/SSLUtils.cpp +++ b/cpp_utils/SSLUtils.cpp @@ -20,7 +20,7 @@ SSLUtils::~SSLUtils() { void SSLUtils::setCertificate(std::string certificate) { size_t len = certificate.length(); - m_certificate = (char*)malloc(len + 1); + m_certificate = (char*) malloc(len + 1); memcpy(m_certificate, certificate.data(), len); m_certificate[len] = '\0'; } @@ -31,7 +31,7 @@ char* SSLUtils::getCertificate() { void SSLUtils::setKey(std::string key) { size_t len = key.length(); - m_key = (char*)malloc(len + 1); + m_key = (char*) malloc(len + 1); memcpy(m_key, key.data(), len); m_key[len] = '\0'; } diff --git a/cpp_utils/SmartLED.cpp b/cpp_utils/SmartLED.cpp index e0267585..430c6317 100644 --- a/cpp_utils/SmartLED.cpp +++ b/cpp_utils/SmartLED.cpp @@ -9,13 +9,13 @@ #include "string.h" #include -const char* LOG_TAG = "SmartLED"; +static const char* LOG_TAG = "SmartLED"; SmartLED::SmartLED() { m_brightness = 100; m_pixelCount = 0; m_pixels = nullptr; - m_colorOrder = (char *)"GRB"; + m_colorOrder = (char*) "GRB"; } // SmartLED @@ -32,7 +32,7 @@ SmartLED::~SmartLED() { * The LEDs are not actually updated until a call to show() is subsequently made. */ void SmartLED::clear() { - for (auto i=0; im_pixelCount; i++) { + for (auto i = 0; i < this->m_pixelCount; i++) { m_pixels[i].red = 0; m_pixels[i].green = 0; m_pixels[i].blue = 0; @@ -48,6 +48,7 @@ uint32_t SmartLED::getBrightness() { return m_brightness; } // getBrightness + /** * @brief Return the number of pixels in the chain. * @return The number of pixels in the chain as previously set by setPixelCount(). @@ -65,6 +66,7 @@ void SmartLED::setBrightness(uint32_t percent) { m_brightness = percent; } // setBrightness + /** * @brief Set the color order of data sent to the LEDs. * @@ -77,7 +79,7 @@ void SmartLED::setBrightness(uint32_t percent) { * an alternate order by supply an alternate three character string made up of 'R', 'G' and 'B' * for example "RGB". */ -void SmartLED::setColorOrder(char *colorOrder) { +void SmartLED::setColorOrder(char* colorOrder) { if (colorOrder != nullptr && strlen(colorOrder) == 3) { m_colorOrder = colorOrder; } @@ -94,9 +96,8 @@ void SmartLED::setColorOrder(char *colorOrder) { * @param [in] green The amount of green in the pixel. * @param [in] blue The amount of blue in the pixel. */ -void SmartLED::setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue) { +void SmartLED::setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue) { //assert(index < m_pixelCount); - m_pixels[index].red = red; m_pixels[index].green = green; m_pixels[index].blue = blue; @@ -127,12 +128,12 @@ void SmartLED::setPixel(uint16_t index, pixel_t pixel) { */ void SmartLED::setPixel(uint16_t index, uint32_t pixel) { //assert(index < m_pixelCount); - m_pixels[index].red = pixel & 0xff; m_pixels[index].green = (pixel & 0xff00) >> 8; m_pixels[index].blue = (pixel & 0xff0000) >> 16; } // setPixel + void SmartLED::setPixelCount(uint16_t pixelCount) { ESP_LOGD(LOG_TAG, ">> setPixelCount: %d", pixelCount); if (m_pixels != nullptr) { @@ -143,6 +144,7 @@ void SmartLED::setPixelCount(uint16_t pixelCount) { ESP_LOGD(LOG_TAG, "<< setPixelCount"); } + /** * @brief Set the given pixel to the specified HSB color. * @@ -153,66 +155,60 @@ void SmartLED::setPixelCount(uint16_t pixelCount) { * @param [in] saturation The amount of saturation in the pixel (0-255). * @param [in] brightness The amount of brightness in the pixel (0-255). */ -void SmartLED::setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8_t brightness) { - double sat_red; - double sat_green; - double sat_blue; - double ctmp_red; - double ctmp_green; - double ctmp_blue; - double new_red; - double new_green; - double new_blue; - double dSaturation=(double)saturation/255; - double dBrightness=(double)brightness/255; - - //assert(index < pixelCount); - - if (hue < 120) { - sat_red = (120 - hue) / 60.0; - sat_green = hue / 60.0; - sat_blue = 0; - } else if (hue < 240) { - sat_red = 0; - sat_green = (240 - hue) / 60.0; - sat_blue = (hue - 120) / 60.0; - } else { - sat_red = (hue - 240) / 60.0; - sat_green = 0; - sat_blue = (360 - hue) / 60.0; - } - - if (sat_red>1.0) { - sat_red = 1.0; - } - if (sat_green>1.0) { - sat_green = 1.0; - } - if (sat_blue>1.0) { - sat_blue = 1.0; - } - - ctmp_red = 2 * dSaturation * sat_red + (1 - dSaturation); - ctmp_green = 2 * dSaturation * sat_green + (1 - dSaturation); - ctmp_blue = 2 * dSaturation * sat_blue + (1 - dSaturation); - - if (dBrightness < 0.5) { - new_red = dBrightness * ctmp_red; - new_green = dBrightness * ctmp_green; - new_blue = dBrightness * ctmp_blue; - } else { - new_red = (1 - dBrightness) * ctmp_red + 2 * dBrightness - 1; - new_green = (1 - dBrightness) * ctmp_green + 2 * dBrightness - 1; - new_blue = (1 - dBrightness) * ctmp_blue + 2 * dBrightness - 1; - } - - m_pixels[index].red = (uint8_t)(new_red*255); - m_pixels[index].green = (uint8_t)(new_green*255); - m_pixels[index].blue = (uint8_t)(new_blue*255); -} // setHSBPixel - - - +void SmartLED::setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8_t brightness) { + double sat_red; + double sat_green; + double sat_blue; + double ctmp_red; + double ctmp_green; + double ctmp_blue; + double new_red; + double new_green; + double new_blue; + double dSaturation=(double) saturation / 255; + double dBrightness=(double) brightness / 255; + + //assert(index < pixelCount); + + if (hue < 120) { + sat_red = (120 - hue) / 60.0; + sat_green = hue / 60.0; + sat_blue = 0; + } else if (hue < 240) { + sat_red = 0; + sat_green = (240 - hue) / 60.0; + sat_blue = (hue - 120) / 60.0; + } else { + sat_red = (hue - 240) / 60.0; + sat_green = 0; + sat_blue = (360 - hue) / 60.0; + } + if (sat_red>1.0) { + sat_red = 1.0; + } + if (sat_green>1.0) { + sat_green = 1.0; + } + if (sat_blue>1.0) { + sat_blue = 1.0; + } + ctmp_red = 2 * dSaturation * sat_red + (1 - dSaturation); + ctmp_green = 2 * dSaturation * sat_green + (1 - dSaturation); + ctmp_blue = 2 * dSaturation * sat_blue + (1 - dSaturation); + + if (dBrightness < 0.5) { + new_red = dBrightness * ctmp_red; + new_green = dBrightness * ctmp_green; + new_blue = dBrightness * ctmp_blue; + } else { + new_red = (1 - dBrightness) * ctmp_red + 2 * dBrightness - 1; + new_green = (1 - dBrightness) * ctmp_green + 2 * dBrightness - 1; + new_blue = (1 - dBrightness) * ctmp_blue + 2 * dBrightness - 1; + } + m_pixels[index].red = (uint8_t)(new_red * 255); + m_pixels[index].green = (uint8_t)(new_green * 255); + m_pixels[index].blue = (uint8_t)(new_blue * 255); +} // setHSBPixel diff --git a/cpp_utils/SmartLED.h b/cpp_utils/SmartLED.h index e70c4843..7903f697 100644 --- a/cpp_utils/SmartLED.h +++ b/cpp_utils/SmartLED.h @@ -36,13 +36,14 @@ class SmartLED { virtual void init() = 0; virtual void show() = 0; void setBrightness(uint32_t percent); - void setColorOrder(char *order); + void setColorOrder(char* order); void setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue); void setPixel(uint16_t index, pixel_t pixel); void setPixel(uint16_t index, uint32_t pixel); void setPixelCount(uint16_t pixelCount); void setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8_t brightness); void clear(); + protected: uint32_t m_brightness; char* m_colorOrder; diff --git a/cpp_utils/SockServ.cpp b/cpp_utils/SockServ.cpp index 296b3a4b..020ed096 100644 --- a/cpp_utils/SockServ.cpp +++ b/cpp_utils/SockServ.cpp @@ -7,15 +7,15 @@ #include #include -#include #include #include - #include + #include #include #include "sdkconfig.h" +#include "FreeRTOS.h" #include "SockServ.h" #include "Socket.h" @@ -30,7 +30,6 @@ static const char* LOG_TAG = "SockServ"; */ SockServ::SockServ(uint16_t port) : SockServ() { this->m_port = port; - } // SockServ @@ -61,28 +60,26 @@ SockServ::~SockServ() { * socket is placed on a queue and a semaphore signaled that a new client is available. */ /* static */ void SockServ::acceptTask(void* data) { - SockServ* pSockServ = (SockServ*)data; - try { - while(1) { + SockServ* pSockServ = (SockServ*) data; + while (true) { + try { ESP_LOGD(LOG_TAG, "Waiting on accept"); Socket tempSock = pSockServ->m_serverSocket.accept(); - if (!tempSock.isValid()) { - continue; - } + if (!tempSock.isValid()) continue; pSockServ->m_clientSet.insert(tempSock); xQueueSendToBack(pSockServ->m_acceptQueue, &tempSock, portMAX_DELAY); pSockServ->m_clientSemaphore.give(); + } catch (std::exception e) { + ESP_LOGD(LOG_TAG, "acceptTask ending"); + pSockServ->m_clientSemaphore.give(); // Wake up any waiting clients. + FreeRTOS::deleteTask(); + break; } - } catch(std::exception e) { - ESP_LOGD(LOG_TAG, "acceptTask ending"); - pSockServ->m_clientSemaphore.give(); // Wake up any waiting clients. - FreeRTOS::deleteTask(); } } // acceptTask - /** * @brief Determine the number of connected partners. * @@ -117,7 +114,7 @@ bool SockServ::getSSL() { * @return The amount of data returned or 0 if there was an error. */ size_t SockServ::receiveData(Socket s, void* pData, size_t maxData) { - int rc = s.receive((uint8_t*)pData, maxData); + size_t rc = s.receive((uint8_t*) pData, maxData); if (rc == -1) { ESP_LOGE(LOG_TAG, "recv(): %s", strerror(errno)); return 0; @@ -132,7 +129,7 @@ size_t SockServ::receiveData(Socket s, void* pData, size_t maxData) { * @param[in] str A string from which sequence of bytes will be used to send to the partner. */ void SockServ::sendData(std::string str) { - sendData((uint8_t *)str.data(), str.size()); + sendData((uint8_t*) str.data(), str.size()); } // sendData @@ -144,7 +141,7 @@ void SockServ::sendData(std::string str) { */ void SockServ::sendData(uint8_t* data, size_t length) { for (auto it = m_clientSet.begin(); it != m_clientSet.end(); ++it) { - (*it).send(data, length); + (*it).send(data, length); } } // sendData @@ -173,7 +170,7 @@ void SockServ::start() { //m_serverSocket.setSSL(m_useSSL); m_serverSocket.listen(m_port); // Create a socket and start listening on it. ESP_LOGD(LOG_TAG, "Now listening on port %d", m_port); - FreeRTOS::startTask(acceptTask, "acceptTask", this, 8*1024); + FreeRTOS::startTask(acceptTask, "acceptTask", this, 8 * 1024); } // start @@ -193,7 +190,7 @@ Socket SockServ::waitForData(std::set& socketSet) { fd_set readSet; int maxFd = -1; - for ( auto it = socketSet.begin(); it != socketSet.end(); ++it) { + for (auto it = socketSet.begin(); it != socketSet.end(); ++it) { FD_SET(it->getFD(), &readSet); if (it->getFD() > maxFd) { maxFd = it->getFD(); @@ -201,11 +198,11 @@ Socket SockServ::waitForData(std::set& socketSet) { } // End for int rc = ::select( - maxFd+1, // Number of sockets to scan - &readSet, // Set of read sockets - nullptr, // Set of write sockets - nullptr, // Set of exception sockets - nullptr // Timeout + maxFd+1, // Number of sockets to scan + &readSet, // Set of read sockets + nullptr, // Set of write sockets + nullptr, // Set of exception sockets + nullptr // Timeout ); if (rc == -1) { ESP_LOGE(LOG_TAG, "Error with select"); @@ -213,7 +210,7 @@ Socket SockServ::waitForData(std::set& socketSet) { return s; } - for ( auto it = socketSet.begin(); it != socketSet.end(); ++it) { + for (auto it = socketSet.begin(); it != socketSet.end(); ++it) { if (FD_ISSET(it->getFD(), &readSet)) { return *it; } @@ -241,5 +238,3 @@ Socket SockServ::waitForNewClient() { ESP_LOGD(LOG_TAG, "<< waitForNewClient"); return tempSocket; } // waitForNewClient - - diff --git a/cpp_utils/SockServ.h b/cpp_utils/SockServ.h index e0ffee76..770ec954 100644 --- a/cpp_utils/SockServ.h +++ b/cpp_utils/SockServ.h @@ -51,11 +51,12 @@ class SockServ { void sendData(uint8_t* data, size_t length); void sendData(std::string str); void setPort(uint16_t port); - void setSSL(bool use=true); + void setSSL(bool use = true); void start(); void stop(); Socket waitForData(std::set& socketSet); Socket waitForNewClient(); + }; #endif /* MAIN_SOCKSERV_H_ */ diff --git a/cpp_utils/Socket.cpp b/cpp_utils/Socket.cpp index bc5a064c..db5991ab 100644 --- a/cpp_utils/Socket.cpp +++ b/cpp_utils/Socket.cpp @@ -13,8 +13,6 @@ #include - - #include #include #include @@ -32,11 +30,11 @@ static const char* LOG_TAG = "Socket"; #undef bind static void my_debug( - void *ctx, + void* ctx, int level, - const char *file, + const char* file, int line, - const char *str) { + const char* str) { ((void) level); ((void) ctx); @@ -62,7 +60,7 @@ Socket Socket::accept() { ESP_LOGD(LOG_TAG, ">> accept: Accepting on %s; sockFd: %d, using SSL: %d", addressToString(&addr).c_str(), m_sock, getSSL()); struct sockaddr_in client_addr; socklen_t sin_size; - int clientSockFD = ::lwip_accept_r(m_sock, (struct sockaddr *)&client_addr, &sin_size); + int clientSockFD = ::lwip_accept_r(m_sock, (struct sockaddr*) &client_addr, &sin_size); //printf("------> new connection client %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); if (clientSockFD == -1) { SocketException se(errno); @@ -92,7 +90,7 @@ Socket Socket::accept() { * @return A string representation of the address. */ std::string Socket::addressToString(struct sockaddr* addr) { - struct sockaddr_in *pInAddr = (struct sockaddr_in *)addr; + struct sockaddr_in* pInAddr = (struct sockaddr_in*) addr; char temp[30]; char ip[20]; inet_ntop(AF_INET, &pInAddr->sin_addr, ip, sizeof(ip)); @@ -119,7 +117,7 @@ int Socket::bind(uint16_t port, uint32_t address) { serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(address); serverAddress.sin_port = htons(port); - int rc = ::lwip_bind_r(m_sock, (struct sockaddr *)&serverAddress, sizeof(serverAddress)); + int rc = ::lwip_bind_r(m_sock, (struct sockaddr*) &serverAddress, sizeof(serverAddress)); if (rc != 0) { ESP_LOGE(LOG_TAG, "<< bind: bind[socket=%d]: %d: %s", m_sock, errno, strerror(errno)); return rc; @@ -172,7 +170,7 @@ int Socket::connect(struct in_addr address, uint16_t port) { inet_ntop(AF_INET, &address, msg, sizeof(msg)); ESP_LOGD(LOG_TAG, "Connecting to %s:[%d]", msg, port); createSocket(); - int rc = ::lwip_connect_r(m_sock, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in)); + int rc = ::lwip_connect_r(m_sock, (struct sockaddr*) &serverAddress, sizeof(struct sockaddr_in)); if (rc == -1) { ESP_LOGE(LOG_TAG, "connect_cpp: Error: %s", strerror(errno)); close(); @@ -193,7 +191,7 @@ int Socket::connect(struct in_addr address, uint16_t port) { */ int Socket::connect(char* strAddress, uint16_t port) { struct in_addr address; - inet_pton(AF_INET, (char *)strAddress, &address); + inet_pton(AF_INET, strAddress, &address); return connect(address, port); } @@ -207,8 +205,7 @@ int Socket::createSocket(bool isDatagram) { ESP_LOGD(LOG_TAG, ">> createSocket: isDatagram: %d", isDatagram); if (isDatagram) { m_sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - } - else { + } else { m_sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } if (m_sock == -1) { @@ -290,13 +287,12 @@ bool Socket::operator <(const Socket& other) const { /** * @brief Set the socket option. */ -int Socket::setSocketOption(int option, void* value, size_t len) -{ - int res = ::setsockopt(m_sock, SOL_SOCKET, option, value, len); - if(res < 0) { - ESP_LOGE(LOG_TAG, "%X : %d", option, errno); - } - return res; +int Socket::setSocketOption(int option, void* value, size_t len) { + int res = ::setsockopt(m_sock, SOL_SOCKET, option, value, len); + if (res < 0) { + ESP_LOGE(LOG_TAG, "%X : %d", option, errno); + } + return res; } // setSocketOption @@ -304,15 +300,14 @@ int Socket::setSocketOption(int option, void* value, size_t len) * @brief Socket timeout. * @param [in] seconds to wait. */ -int Socket::setTimeout(uint32_t seconds) -{ - struct timeval tv; - tv.tv_sec = seconds; - tv.tv_usec = 0; - if(setSocketOption(SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) { - return -1; - } - return setSocketOption(SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); +int Socket::setTimeout(uint32_t seconds) { + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + if (setSocketOption(SO_RCVTIMEO, (char*) &tv, sizeof(struct timeval)) < 0) { + return -1; + } + return setSocketOption(SO_SNDTIMEO, (char*) &tv, sizeof(struct timeval)); } @@ -320,21 +315,15 @@ std::string Socket::readToDelim(std::string delim) { std::string ret; std::string part; auto it = delim.begin(); - while(1) { + while (true) { uint8_t val; int rc = receive(&val, 1); - if (rc == -1) { - return ""; - } - if (rc == 0) { - return ret+part; - } + if (rc == -1) return ""; + if (rc == 0) return ret + part; if (*it == val) { part+= val; ++it; - if (it == delim.end()) { - return ret; - } + if (it == delim.end()) return ret; } else { if (part.empty()) { ret += part; @@ -347,7 +336,6 @@ std::string Socket::readToDelim(std::string delim) { } // readToDelim - /** * @brief Receive data from the partner. * Receive data from the socket partner. If exact = false, we read as much data as @@ -360,13 +348,13 @@ std::string Socket::readToDelim(std::string delim) { */ size_t Socket::receive(uint8_t* data, size_t length, bool exact) { //ESP_LOGD(LOG_TAG, ">> receive: sockFd: %d, length: %d, exact: %d", m_sock, length, exact); - if (exact == false) { + if (!exact) { int rc; if (getSSL()) { do { rc = mbedtls_ssl_read(&m_sslContext, data, length); ESP_LOGD(LOG_TAG, "rc=%d, MBEDTLS_ERR_SSL_WANT_READ=%d", rc, MBEDTLS_ERR_SSL_WANT_READ); - } while(rc == MBEDTLS_ERR_SSL_WANT_WRITE || rc == MBEDTLS_ERR_SSL_WANT_READ); + } while (rc == MBEDTLS_ERR_SSL_WANT_WRITE || rc == MBEDTLS_ERR_SSL_WANT_READ); } else { rc = ::lwip_recv_r(m_sock, data, length, 0); if (rc == -1) { @@ -375,16 +363,16 @@ size_t Socket::receive(uint8_t* data, size_t length, bool exact) { } //GeneralUtils::hexDump(data, rc); //ESP_LOGD(LOG_TAG, "<< receive: rc: %d", rc); - return rc; + return (size_t) rc; } // Read what we can, doesn't need to be an exact amount. size_t amountToRead = length; int rc; - while(amountToRead > 0) { + while (amountToRead > 0) { if (getSSL()) { do { rc = mbedtls_ssl_read(&m_sslContext, data, amountToRead); - } while(rc == MBEDTLS_ERR_SSL_WANT_WRITE || rc == MBEDTLS_ERR_SSL_WANT_READ); + } while (rc == MBEDTLS_ERR_SSL_WANT_WRITE || rc == MBEDTLS_ERR_SSL_WANT_READ); } else { rc = ::lwip_recv_r(m_sock, data, amountToRead, 0); } @@ -392,9 +380,7 @@ size_t Socket::receive(uint8_t* data, size_t length, bool exact) { ESP_LOGE(LOG_TAG, "receive: %s", strerror(errno)); return 0; } - if (rc == 0) { - break; - } + if (rc == 0) break; amountToRead -= rc; data += rc; } @@ -411,7 +397,7 @@ size_t Socket::receive(uint8_t* data, size_t length, bool exact) { * @param [in] pAddr An area into which we can store the address of the partner. * @return The length of the data received. */ -int Socket::receiveFrom(uint8_t* data, size_t length, struct sockaddr *pAddr) { +int Socket::receiveFrom(uint8_t* data, size_t length, struct sockaddr *pAddr) { socklen_t addrLen = sizeof(struct sockaddr); int rc = ::recvfrom(m_sock, data, length, 0, pAddr, &addrLen); return rc; @@ -430,35 +416,34 @@ int Socket::send(const uint8_t* data, size_t length) const { ESP_LOGD(LOG_TAG, "send: Raw binary of length: %d", length); //GeneralUtils::hexDump(data, length); int rc = ERR_OK; - while (length > 0) - { - if (getSSL()) { - rc = mbedtls_ssl_write((mbedtls_ssl_context*)&m_sslContext, data, length); - // retry with same parameters if MBEDTLS_ERR_SSL_WANT_WRITE or MBEDTLS_ERR_SSL_WANT_READ - if ((rc != MBEDTLS_ERR_SSL_WANT_WRITE) && (rc != MBEDTLS_ERR_SSL_WANT_READ)) { - if (rc < 0) { - // no cure for other errors - log and exit - ESP_LOGE(LOG_TAG, "send: SSL write error %d", rc); - return rc; - } else { - // not all data was written, try again for the remainder - length -= rc; - data += rc; - } - } - } else { - rc = ::lwip_send_r(m_sock, data, length, 0); - if ((rc < 0) && (errno != EAGAIN)) { - // no cure for errors other than EAGAIN - log and exit - ESP_LOGE(LOG_TAG, "send: socket=%d, %s", m_sock, strerror(errno)); - return rc; - } else if (rc > 0) { - // not all data was written, try again for the remainder - length -= rc; - data += rc; - } - } - } + while (length > 0) { + if (getSSL()) { + rc = mbedtls_ssl_write((mbedtls_ssl_context*)&m_sslContext, data, length); + // retry with same parameters if MBEDTLS_ERR_SSL_WANT_WRITE or MBEDTLS_ERR_SSL_WANT_READ + if ((rc != MBEDTLS_ERR_SSL_WANT_WRITE) && (rc != MBEDTLS_ERR_SSL_WANT_READ)) { + if (rc < 0) { + // no cure for other errors - log and exit + ESP_LOGE(LOG_TAG, "send: SSL write error %d", rc); + return rc; + } else { + // not all data was written, try again for the remainder + length -= rc; + data += rc; + } + } + } else { + rc = ::lwip_send_r(m_sock, data, length, 0); + if ((rc < 0) && (errno != EAGAIN)) { + // no cure for errors other than EAGAIN - log and exit + ESP_LOGE(LOG_TAG, "send: socket=%d, %s", m_sock, strerror(errno)); + return rc; + } else if (rc > 0) { + // not all data was written, try again for the remainder + length -= rc; + data += rc; + } + } + } return rc; } // send @@ -471,19 +456,19 @@ int Socket::send(const uint8_t* data, size_t length) const { */ int Socket::send(std::string value) const { ESP_LOGD(LOG_TAG, "send: Binary of length: %d", value.length()); - return send((uint8_t *)value.data(), value.size()); + return send((uint8_t*) value.data(), value.size()); } // send int Socket::send(uint16_t value) { ESP_LOGD(LOG_TAG, "send: 16bit value: %.2x", value); - return send((uint8_t *)&value, sizeof(value)); + return send((uint8_t*) &value, sizeof(value)); } // send_cpp int Socket::send(uint32_t value) { ESP_LOGD(LOG_TAG, "send: 32bit value: %.2x", value); - return send((uint8_t *)&value, sizeof(value)); + return send((uint8_t*) &value, sizeof(value)); } // send @@ -512,7 +497,7 @@ void Socket::sendTo(const uint8_t* data, size_t length, struct sockaddr* pAddr) */ void Socket::setReuseAddress(bool value) { ESP_LOGD(LOG_TAG, ">> setReuseAddress: %d", value); - int val = value?1:0; + int val = value ? 1 : 0; setSocketOption(SO_REUSEADDR, &val, sizeof(val)); ESP_LOGD(LOG_TAG, "<< setReuseAddress"); } // setReuseAddress @@ -527,9 +512,9 @@ void Socket::setSSL(bool sslValue) { ESP_LOGD(LOG_TAG, ">> setSSL: %s", sslValue?"Yes":"No"); m_useSSL = sslValue; - if (sslValue == true) { - char* pvtKey = SSLUtils::getKey(); - char* certificate = SSLUtils::getCertificate(); + if (sslValue) { + char *pvtKey = SSLUtils::getKey(); + char *certificate = SSLUtils::getCertificate(); if (pvtKey == nullptr) { ESP_LOGE(LOG_TAG, "No private key file"); return; @@ -547,66 +532,56 @@ void Socket::setSSL(bool sslValue) { mbedtls_entropy_init(&m_entropy); mbedtls_ctr_drbg_init(&m_ctr_drbg); - int ret = mbedtls_x509_crt_parse(&m_srvcert, (unsigned char*)certificate, strlen(certificate)+1); - if( ret != 0 ) { - ESP_LOGD(LOG_TAG, "mbedtls_x509_crt_parse returned 0x%x", -ret ); + int ret = mbedtls_x509_crt_parse(&m_srvcert, (unsigned char *) certificate, strlen(certificate) + 1); + if (ret != 0) { + ESP_LOGD(LOG_TAG, "mbedtls_x509_crt_parse returned 0x%x", -ret); goto exit; } - ret = mbedtls_pk_parse_key(&m_pkey, (unsigned char*)pvtKey, strlen(pvtKey)+1, NULL, 0 ); - if( ret != 0 ) { + ret = mbedtls_pk_parse_key(&m_pkey, (unsigned char *) pvtKey, strlen(pvtKey) + 1, NULL, 0); + if (ret != 0) { ESP_LOGD(LOG_TAG, "mbedtls_pk_parse_key returned 0x%x", -ret); goto exit; } - ret = mbedtls_ctr_drbg_seed( &m_ctr_drbg, mbedtls_entropy_func, &m_entropy, (const unsigned char*) pers, strlen(pers)); - if( ret != 0 ) { - ESP_LOGD(LOG_TAG, "! mbedtls_ctr_drbg_seed returned %d\n",ret); - goto exit; - } + ret = mbedtls_ctr_drbg_seed(&m_ctr_drbg, mbedtls_entropy_func, &m_entropy, (const unsigned char*) pers, strlen(pers)); + if (ret != 0) { + ESP_LOGD(LOG_TAG, "! mbedtls_ctr_drbg_seed returned %d\n", ret); + goto exit; + } ret = mbedtls_ssl_config_defaults(&m_conf, - MBEDTLS_SSL_IS_SERVER, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT); - if(ret != 0 ) { + MBEDTLS_SSL_IS_SERVER, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { ESP_LOGD(LOG_TAG, "mbedtls_ssl_config_defaults returned %d\n\n", ret); goto exit; } mbedtls_ssl_conf_authmode(&m_conf, MBEDTLS_SSL_VERIFY_NONE); - mbedtls_ssl_conf_rng(&m_conf, mbedtls_ctr_drbg_random, &m_ctr_drbg); +// mbedtls_ssl_conf_ca_chain( &m_conf, m_srvcert.next, NULL); + ret = mbedtls_ssl_conf_own_cert(&m_conf, &m_srvcert, &m_pkey); + if (ret != 0) { + ESP_LOGD(LOG_TAG, "mbedtls_ssl_conf_own_cert returned %d\n\n", ret); + goto exit; + } -// mbedtls_ssl_conf_ca_chain( &m_conf, m_srvcert.next, NULL); - ret = mbedtls_ssl_conf_own_cert( &m_conf, &m_srvcert, &m_pkey); - if(ret != 0) { - ESP_LOGD(LOG_TAG, "mbedtls_ssl_conf_own_cert returned %d\n\n", ret); - goto exit; - } - - mbedtls_ssl_conf_dbg(&m_conf, my_debug, nullptr); + mbedtls_ssl_conf_dbg(&m_conf, my_debug, nullptr); #ifdef CONFIG_MBEDTLS_DEBUG - mbedtls_debug_set_threshold(4); + mbedtls_debug_set_threshold(4); #endif - ret = mbedtls_ssl_setup(&m_sslContext, &m_conf); - if(ret != 0) { - ESP_LOGD(LOG_TAG, "mbedtls_ssl_setup returned %d\n\n", ret ); - goto exit; - } -/* - ret = mbedtls_ssl_set_hostname(&m_sslContext, "192.168.1.99"); - if(ret != 0) { - ESP_LOGD(LOG_TAG, "mbedtls_ssl_set_hostname returned %d\n\n", ret ); - goto exit; - } - */ - - exit: - return; + ret = mbedtls_ssl_setup(&m_sslContext, &m_conf); + if (ret != 0) { + ESP_LOGD(LOG_TAG, "mbedtls_ssl_setup returned %d\n\n", ret); + goto exit; + } } +exit: + return; } // setSSL @@ -619,14 +594,12 @@ void Socket::sslHandshake() { ESP_LOGD(LOG_TAG, " - Reset complete"); mbedtls_ssl_set_bio(&m_sslContext, &m_sslSock, mbedtls_net_send, mbedtls_net_recv, NULL); - while(1) { + while (true) { int ret = mbedtls_ssl_handshake(&m_sslContext); - if (ret == 0) { - break; - } + if (ret == 0) break; - if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { - ESP_LOGD(LOG_TAG, "mbedtls_ssl_handshake returned %d\n\n", ret ); + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + ESP_LOGD(LOG_TAG, "mbedtls_ssl_handshake returned %d\n\n", ret); return; } } // End while @@ -675,13 +648,10 @@ SocketInputRecordStreambuf::~SocketInputRecordStreambuf() { * */ SocketInputRecordStreambuf::int_type SocketInputRecordStreambuf::underflow() { - if (m_sizeRead >= m_dataLength) { - return EOF; - } - int bytesRead = m_socket.receive((uint8_t*)m_buffer, m_bufferSize, true); - if (bytesRead == 0) { - return EOF; - } + if (m_sizeRead >= m_dataLength) return EOF; + int bytesRead = m_socket.receive((uint8_t*) m_buffer, m_bufferSize, true); + if (bytesRead == 0) return EOF; + m_sizeRead += bytesRead; setg(m_buffer, m_buffer, m_buffer + bytesRead); return traits_type::to_int_type(*gptr()); @@ -690,5 +660,3 @@ SocketInputRecordStreambuf::int_type SocketInputRecordStreambuf::underflow() { SocketException::SocketException(int myErrno) { m_errno = myErrno; } - - diff --git a/cpp_utils/Socket.h b/cpp_utils/Socket.h index 6804ab93..f9a2bac6 100644 --- a/cpp_utils/Socket.h +++ b/cpp_utils/Socket.h @@ -45,10 +45,13 @@ class SocketException: public std::exception { public: SocketException(int myErrno); + private: int m_errno; + }; + /** * @brief Encapsulate a socket. * @@ -75,43 +78,46 @@ class Socket { int getFD() const; bool getSSL() const; bool isValid(); - int listen(uint16_t port, bool isDatagram=false, bool reuseAddress=false); + int listen(uint16_t port, bool isDatagram = false, bool reuseAddress = false); bool operator<(const Socket& other) const; std::string readToDelim(std::string delim); - size_t receive(uint8_t* data, size_t length, bool exact=false); + size_t receive(uint8_t* data, size_t length, bool exact = false); int receiveFrom(uint8_t* data, size_t length, struct sockaddr* pAddr); int send(std::string value) const; int send(const uint8_t* data, size_t length) const; int send(uint16_t value); int send(uint32_t value); void sendTo(const uint8_t* data, size_t length, struct sockaddr* pAddr); - void setSSL(bool sslValue=true); + void setSSL(bool sslValue = true); std::string toString(); private: int m_sock; // The underlying TCP/IP socket bool m_useSSL; // Should we use SSL - mbedtls_net_context m_sslSock; - mbedtls_entropy_context m_entropy; - mbedtls_ctr_drbg_context m_ctr_drbg; - mbedtls_ssl_context m_sslContext; - mbedtls_ssl_config m_conf; - mbedtls_x509_crt m_srvcert; - mbedtls_pk_context m_pkey; - void sslHandshake(); + mbedtls_net_context m_sslSock; + mbedtls_entropy_context m_entropy; + mbedtls_ctr_drbg_context m_ctr_drbg; + mbedtls_ssl_context m_sslContext; + mbedtls_ssl_config m_conf; + mbedtls_x509_crt m_srvcert; + mbedtls_pk_context m_pkey; + void sslHandshake(); + }; class SocketInputRecordStreambuf : public std::streambuf { public: - SocketInputRecordStreambuf(Socket socket, size_t dataLength, size_t bufferSize=512); + SocketInputRecordStreambuf(Socket socket, size_t dataLength, size_t bufferSize = 512); ~SocketInputRecordStreambuf(); int_type underflow(); + private: char* m_buffer; Socket m_socket; size_t m_dataLength; size_t m_bufferSize; size_t m_sizeRead; + }; diff --git a/cpp_utils/System.cpp b/cpp_utils/System.cpp index 1993be4c..2e24f88b 100644 --- a/cpp_utils/System.cpp +++ b/cpp_utils/System.cpp @@ -7,11 +7,127 @@ #include "System.h" #include +#include +#include extern "C" { #include } +typedef volatile struct { + union { + struct { + uint32_t mcu_oe: 1; + uint32_t slp_sel: 1; + uint32_t mcu_wpd: 1; + uint32_t mcu_wpu: 1; + uint32_t mcu_ie: 1; + uint32_t mcu_drb: 2; + uint32_t func_wpd: 1; + uint32_t func_wpu: 1; + uint32_t func_ie: 1; + uint32_t func_drv: 2; + uint32_t mcu_sel: 3; + uint32_t reserved15: 17; + }; + uint32_t val; + }; +} io_mux_reg_t; + + +typedef volatile struct { + union { + struct { + uint32_t clk1: 4; + uint32_t clk2: 4; + uint32_t clk3: 4; + uint32_t reserved12: 20; + }; + uint32_t val; + } pin_ctrl; + + // The 36 exposed pads. + io_mux_reg_t pad_gpio36; // GPIO36 + io_mux_reg_t pad_gpio37; // GPIO37 + io_mux_reg_t pad_gpio38; // GPIO38 + io_mux_reg_t pad_gpio39; // GPIO39 + io_mux_reg_t pad_gpio34; // GPIO34 + io_mux_reg_t pad_gpio35; // GPIO35 + io_mux_reg_t pad_gpio32; // GPIO32 + io_mux_reg_t pad_gpio33; // GPIO33 + io_mux_reg_t pad_gpio25; // GPIO25 + io_mux_reg_t pad_gpio26; // GPIO26 + io_mux_reg_t pad_gpio27; // GPIO27 + io_mux_reg_t pad_mtms; // GPIO14 + io_mux_reg_t pad_mtdi; // GPIO12 + io_mux_reg_t pad_mtck; // GPIO13 + io_mux_reg_t pad_mtdo; // GPIO15 + io_mux_reg_t pad_gpio2; // GPIO2 + io_mux_reg_t pad_gpio0; // GPIO0 + io_mux_reg_t pad_gpio4; // GPIO4 + io_mux_reg_t pad_gpio16; // GPIO16 + io_mux_reg_t pad_gpio17; // GPIO17 + io_mux_reg_t pad_sd_data2; // GPIO9 + io_mux_reg_t pad_sd_data3; // GPIO10 + io_mux_reg_t pad_sd_cmd; // GPIO11 + io_mux_reg_t pad_sd_clk; // GPIO6 + io_mux_reg_t pad_sd_data0; // GPIO7 + io_mux_reg_t pad_sd_data1; // GPIO8 + io_mux_reg_t pad_gpio5; // GPIO5 + io_mux_reg_t pad_gpio18; // GPIO18 + io_mux_reg_t pad_gpio19; // GPIO19 + io_mux_reg_t pad_gpio20; // GPIO20 + io_mux_reg_t pad_gpio21; // GPIO21 + io_mux_reg_t pad_gpio22; // GPIO22 + io_mux_reg_t pad_u0rxd; // GPIO3 + io_mux_reg_t pad_u0txd; // GPIO1 + io_mux_reg_t pad_gpio23; // GPIO23 + io_mux_reg_t pad_gpio24; // GPIO24 +} io_mux_dev_t; + +static io_mux_dev_t* IO_MUX = (io_mux_dev_t*) 0x3ff49000; + +static const io_mux_reg_t* io_mux_translate[] = { + &IO_MUX->pad_gpio0, // 0 + &IO_MUX->pad_u0txd, // 1 + &IO_MUX->pad_gpio2, // 2 + &IO_MUX->pad_u0rxd, // 3 + &IO_MUX->pad_gpio4, // 4 + &IO_MUX->pad_gpio5, // 5 + &IO_MUX->pad_sd_clk, // 6 + &IO_MUX->pad_sd_data0, // 7 + &IO_MUX->pad_sd_data1, // 8 + &IO_MUX->pad_sd_data2, // 9 + &IO_MUX->pad_sd_data3, // 10 + &IO_MUX->pad_sd_cmd, // 11 + &IO_MUX->pad_mtdi, // 12 + &IO_MUX->pad_mtck, // 13 + &IO_MUX->pad_mtms, // 14 + &IO_MUX->pad_mtdo, // 15 + &IO_MUX->pad_gpio16, // 16 + &IO_MUX->pad_gpio17, // 17 + &IO_MUX->pad_gpio18, // 18 + &IO_MUX->pad_gpio19, // 19 + &IO_MUX->pad_gpio20, // 20 + &IO_MUX->pad_gpio21, // 21 + nullptr, // 28 + nullptr, // 29 + nullptr, // 30 + nullptr, // 31 + &IO_MUX->pad_gpio32, // 32 + &IO_MUX->pad_gpio33, // 33 + &IO_MUX->pad_gpio34, // 34 + &IO_MUX->pad_gpio35, // 35 + &IO_MUX->pad_gpio36, // 36 + &IO_MUX->pad_gpio37, // 37 + &IO_MUX->pad_gpio38, // 38 + &IO_MUX->pad_gpio39 // 39 +}; + +static const io_mux_reg_t* gpioToIoMux(int gpio) { + return io_mux_translate[gpio]; +} + System::System() { // TODO Auto-generated constructor stub @@ -21,12 +137,323 @@ System::~System() { // TODO Auto-generated destructor stub } +const static char* outSignalStrings[] = { + "SPICLK_out", // 0 + "SPIQ_out", // 1 + "SPID_out", // 2 + "SPIHD_out", //3 + "SPIWP_out", // 4 + "SPICS0_out", // 5 + "SPICS1_out", // 6 + "SPICS2_out", // 7 + "HSPICLK_out", // 8 + "HSPIQ_out", // 9 + "HSPID_out", // 10 + "HSPICS0_out", // 11 + "HSPIHD_out", // 12 + "HSPIWP_out", // 13 + "U0TXD_out", // 14 + "U0RTS_out", // 15 + "U0DTR_out", // 16 + "U1TXD_out", // 17 + "U1RTS_out", // 18 + "", // 19 + "", // 20 + "", // 21 + "", // 22 + "I2S0O_BCK_out", // 23 + "I2S1O_BCK_out", // 24 + "I2S0O_WS_out", // 25 + "I2S1O_WS_out", // 26 + "I2S0I_BCK_out", // 27 + "I2S0I_WS_out", // 28 + "I2CEXT0_SCL_out", // 29 + "I2CEXT0_SDA_out", // 30 + "sdio_tohost_int_out", // 31 + "pwm0_out0a", // 32 + "pwm0_out0b", // 33 + "pwm0_out1a", // 34 + "pwm0_out1b", // 35 + "pwm0_out2a", // 36 + "pwm0_out2b", //37 + "", // 38 + "", // 39 + "", // 40 + "", // 41 + "", // 42 + "", // 43 + "", // 44 + "", // 45 + "", // 46 + "", // 47 + "", // 48 + "", // 49 + "", // 50 + "", // 51 + "", // 52 + "", // 53 + "", // 54 + "", // 55 + "", // 56 + "", // 57 + "", // 58 + "", // 59 + "", // 60 + "HSPICS1_out", // 61 + "HSPICS2_out", // 62 + "VSPICLK_out_mux", // 63 + "VSPIQ_out", // 64 + "VSPID_out", // 65 + "VSPIHD_out", // 66 + "VSPIWP_out", // 67 + "VSPICS0_out", // 68 + "VSPICS1_out", // 69 + "VSPICS2_out", // 70 + "ledc_hs_sig_out0", // 71 + "ledc_hs_sig_out1", // 72 + "ledc_hs_sig_out2", // 73 + "ledc_hs_sig_out3", // 74 + "ledc_hs_sig_out4", // 75 + "ledc_hs_sig_out5", // 76 + "ledc_hs_sig_out6", // 77 + "ledc_hs_sig_out7", // 78 + "edc_ls_sig_out0", // 79 + "ledc_ls_sig_out1", // 80 + "ledc_ls_sig_out2", // 81 + "ledc_ls_sig_out3", // 82 + "ledc_ls_sig_out4", // 83 + "ledc_ls_sig_out5", // 84 + "ledc_ls_sig_out6", // 85 + "ledc_ls_sig_out7", // 86 + "rmt_sig_out0", // 87 + "rmt_sig_out1", // 88 + "rmt_sig_out2", // 89 + "rmt_sig_out3", // 90 + "rmt_sig_out4", // 91 + "rmt_sig_out5", // 92 + "rmt_sig_out6", // 93 + "rmt_sig_out7", // 94 + "I2CEXT1_SCL_out", // 95 + "I2CEXT1_SCL_out", // 96 + "host_ccmd_od_pullup_en_n", // 97 + "host_rst_n_1", // 98 + "host_rst_n_2", // 99 + "gpio_sd0_out", // 100 + "gpio_sd1_out", // 101 + "gpio_sd2_out", // 102 + "gpio_sd3_out", // 103 + "gpio_sd4_out", // 104 + "gpio_sd5_out", // 105 + "gpio_sd6_out", // 106 + "gpio_sd7_out", // 107 + "pwm1_out0a", // 108 + "pwm1_out0b", // 109 + "pwm1_out1a", // 110 + "pwm1_out1b", // 111 + "pwm1_out2a", // 112 + "pwm1_out2b", // 113 + "pwm2_out1h", // 114 + "pwm2_out1l", // 115 + "pwm2_out2h", // 116 + "pwm2_out2l", // 117 + "pwm2_out3h", // 118 + "pwm2_out3l", // 119 + "pwm2_out4h", // 120 + "pwm2_out4l", // 121 + "", // 122 + "", // 123 + "", // 124 + "", // 125 + "", // 126 + "", // 127 + "", // 128 + "", // 129 + "", // 130 + "", // 131 + "", // 132 + "", // 133 + "", // 134 + "", // 135 + "", // 136 + "", // 137 + "", // 138 + "", // 139 + "I2S0O_DATA_out0", // 140 + "I2S0O_DATA_out1", // 141 + "I2S0O_DATA_out2", // 142 + "I2S0O_DATA_out3", // 143 + "I2S0O_DATA_out4", // 144 + "I2S0O_DATA_out5", // 145 + "I2S0O_DATA_out6", // 146 + "I2S0O_DATA_out7", // 147 + "I2S0O_DATA_out8", // 148 + "I2S0O_DATA_out9", // 149 + "I2S0O_DATA_out10", // 150 + "I2S0O_DATA_out11", // 151 + "I2S0O_DATA_out12", // 152 + "I2S0O_DATA_out13", // 153 + "I2S0O_DATA_out14", // 154 + "I2S0O_DATA_out15", // 155 + "I2S0O_DATA_out16", // 156 + "I2S0O_DATA_out17", // 157 + "I2S0O_DATA_out18", // 158 + "I2S0O_DATA_out19", // 159 + "I2S0O_DATA_out20", // 160 + "I2S0O_DATA_out21", // 161 + "I2S0O_DATA_out22", // 162 + "I2S0O_DATA_out23", // 163 + "I2S1I_BCK_out", // 164 + "I2S1I_WS_out", // 165 + "I2S1O_DATA_out0", // 166 + "I2S1O_DATA_out1", // 167 + "I2S1O_DATA_out2", // 168 + "I2S1O_DATA_out3", // 169 + "I2S1O_DATA_out4", // 170 + "I2S1O_DATA_out5", // 171 + "I2S1O_DATA_out6", // 172 + "I2S1O_DATA_out7", // 173 + "I2S1O_DATA_out8", // 174 + "I2S1O_DATA_out9", // 175 + "I2S1O_DATA_out10", // 176 + "I2S1O_DATA_out11", // 177 + "I2S1O_DATA_out12", // 178 + "I2S1O_DATA_out13", // 179 + "I2S1O_DATA_out14", // 180 + "I2S1O_DATA_out15", // 181 + "I2S1O_DATA_out16", // 182 + "I2S1O_DATA_out17", // 183 + "I2S1O_DATA_out18", // 184 + "I2S1O_DATA_out19", // 185 + "I2S1O_DATA_out20", // 186 + "I2S1O_DATA_out21", // 187 + "I2S1O_DATA_out22", // 188 + "I2S1O_DATA_out23", // 189 + "pwm3_out1h", // 190 + "pwm3_out1l", // 191 + "pwm3_out2h", // 192 + "pwm3_out2l", // 193 + "pwm3_out3h", // 194 + "pwm3_out3l", // 195 + "pwm3_out4h", // 196 + "pwm3_out4l", // 197 + "U2TXD_out", // 198 + "U2RTS_out", // 199 + "emac_mdc_o", // 200 + "emac_mdo_o", // 201 + "emac_crs_o", // 202 + "emac_col_o", // 203 + "bt_audio0_irq", // 204 + "bt_audio1_irq", // 205 + "bt_audio2_irq", // 206 + "ble_audio0_irq", // 207 + "ble_audio1_irq", // 208 + "ble_audio2_irq", // 209 + "pcmfsync_out", // 210 + "pcmclk_out", // 211 + "pcmdout", // 212 + "ble_audio_sync0_p", // 213 + "ble_audio_sync1_p", // 214 + "ble_audio_sync2_p", // 215 + "", // 216 + "", // 217 + "", // 218 + "", // 219 + "", // 220 + "", // 221 + "", // 222 + "", // 223 + "sig_in_func224", // 224 + "sig_in_func225", // 225 + "sig_in_func226", // 226 + "sig_in_func227", // 227 + "sig_in_func228", // 228 + "", // 229 + "", // 230 + "", // 231 + "", // 232 + "", // 233 + "", // 234 + "", // 235 + "", // 236 + "", // 237 + "", // 238 + "", // 239 + "", // 240 + "", // 241 + "", // 242 + "", // 243 + "", // 244 + "", // 245 + "", // 246 + "", // 247 + "", // 248 + "", // 249 + "", // 250 + "", // 251 + "", // 252 + "", // 253 + "", // 254 + "", // 255 +}; + + +/** + * Dump the mappings for GPIO pins. + */ +/* static */ void System::dumpPinMapping() { + const int numPins = 40; + printf("GPIO_FUNCn_OUT_SEL_CFG_REG\n"); + printf("--------------------------\n"); + printf("%3s %4s\n", "Pin", "Func"); + for (uint8_t i = 0; i < numPins; i++) { + const char *signal; + if (GPIO.func_out_sel_cfg[i].func_sel == 256) { + signal = (char*) "[GPIO]"; + } else if (GPIO.func_out_sel_cfg[i].func_sel == 257) { + signal = (char*) "N/A"; + } else { + signal = outSignalStrings[GPIO.func_out_sel_cfg[i].func_sel]; + } + printf("%2d %4d %s\n", i, GPIO.func_out_sel_cfg[i].func_sel, signal); + const io_mux_reg_t* io_mux = gpioToIoMux(i); + if (GPIO.func_out_sel_cfg[i].func_sel == 256 && io_mux != nullptr) { + printf("0x%x - function: %d, ie: %d\n", (uint32_t) io_mux, io_mux->mcu_sel + 1, io_mux->func_ie); + } + } + +} // System#dumpPinMapping + + +/** + * Dump the storage stats for the heap. + */ +/* static */ void System::dumpHeapInfo() { + multi_heap_info_t heapInfo; + + printf(" %10s %10s %10s %10s %13s %11s %12s\n", "Free", "Allocated", "Largest", "Minimum", "Alloc Blocks", "Free Blocks", "Total Blocks"); + heap_caps_get_info(&heapInfo, MALLOC_CAP_EXEC); + printf("EXEC %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); + heap_caps_get_info(&heapInfo, MALLOC_CAP_32BIT); + printf("32BIT %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); + heap_caps_get_info(&heapInfo, MALLOC_CAP_8BIT); + printf("8BIT %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); + heap_caps_get_info(&heapInfo, MALLOC_CAP_DMA); + printf("DMA %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); + heap_caps_get_info(&heapInfo, MALLOC_CAP_SPIRAM); + printf("SPISRAM %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); + heap_caps_get_info(&heapInfo, MALLOC_CAP_INTERNAL); + printf("INTERNAL %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); + heap_caps_get_info(&heapInfo, MALLOC_CAP_DEFAULT); + printf("DEFAULT %10d %10d %10d %10d %13d %11d %12d\n", heapInfo.total_free_bytes, heapInfo.total_allocated_bytes, heapInfo.largest_free_block, heapInfo.minimum_free_bytes, heapInfo.allocated_blocks, heapInfo.free_blocks, heapInfo.total_blocks); +} // System#dumpHeapInfo + + /** * @brief Get the information about the device. * @param [out] info The structure to be populated on return. * @return N/A. */ -void System::getChipInfo(esp_chip_info_t *info) { +void System::getChipInfo(esp_chip_info_t* info) { ::esp_chip_info(info); } // getChipInfo @@ -58,6 +485,7 @@ size_t System::getMinimumFreeHeapSize() { return heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT); } // getMinimumFreeHeapSize + /** * @brief Restart the ESP32. */ diff --git a/cpp_utils/System.h b/cpp_utils/System.h index 6459509d..a3bed334 100644 --- a/cpp_utils/System.h +++ b/cpp_utils/System.h @@ -18,7 +18,9 @@ class System { public: System(); virtual ~System(); - static void getChipInfo(esp_chip_info_t *info); + static void dumpPinMapping(); // Dump the mappings of pins to functions. + static void dumpHeapInfo(); + static void getChipInfo(esp_chip_info_t* info); static size_t getFreeHeapSize(); static std::string getIDFVersion(); static size_t getMinimumFreeHeapSize(); diff --git a/cpp_utils/TFTP.cpp b/cpp_utils/TFTP.cpp index d2c0254b..b1591a9f 100644 --- a/cpp_utils/TFTP.cpp +++ b/cpp_utils/TFTP.cpp @@ -9,13 +9,13 @@ #include "TFTP.h" #include -#include -#include +#include "FreeRTOS.h" +#include "GeneralUtils.h" #include #include #include #include -#include +#include "Socket.h" #include "sdkconfig.h" @@ -26,7 +26,7 @@ extern "C" { extern uint32_t lwip_htonl(uint32_t); } -static char tag[] = "TFTP"; +static const char* LOG_TAG = "TFTP"; enum opcode { TFTP_OPCODE_RRQ = 1, // Read request @@ -50,7 +50,7 @@ enum ERRORCODE { /** * Size of the TFTP data payload. */ -const int TFTP_DATA_SIZE=512; +const int TFTP_DATA_SIZE = 512; struct data_packet { uint16_t blockNumber; @@ -91,15 +91,15 @@ void TFTP::TFTP_Transaction::processRRQ() { * ---------------------------------- * */ - FILE *file; + FILE* file; bool finished = false; - ESP_LOGD(tag, "Reading TFTP data from file: %s", m_filename.c_str()); + ESP_LOGD(LOG_TAG, "Reading TFTP data from file: %s", m_filename.c_str()); std::string tmpName = m_baseDir + "/" + m_filename; /* struct stat buf; if (stat(tmpName.c_str(), &buf) != 0) { - ESP_LOGE(tag, "Stat file: %s: %s", tmpName.c_str(), strerror(errno)); + ESP_LOGE(LOG_TAG, "Stat file: %s: %s", tmpName.c_str(), strerror(errno)); return; } int length = buf.st_size; @@ -109,7 +109,7 @@ void TFTP::TFTP_Transaction::processRRQ() { file = fopen(tmpName.c_str(), "r"); if (file == nullptr) { - ESP_LOGE(tag, "Failed to open file for reading: %s: %s", tmpName.c_str(), strerror(errno)); + ESP_LOGE(LOG_TAG, "Failed to open file for reading: %s: %s", tmpName.c_str(), strerror(errno)); sendError(ERROR_CODE_FILE_NOT_FOUND, tmpName); return; } @@ -122,16 +122,15 @@ void TFTP::TFTP_Transaction::processRRQ() { record.opCode = htons(TFTP_OPCODE_DATA); // Set the op code to be DATA. - while(!finished) { - + while (!finished) { record.blockNumber = htons(blockNumber); int sizeRead = fread(record.buf, 1, TFTP_DATA_SIZE, file); - ESP_LOGD(tag, "Sending data to %s, blockNumber=%d, size=%d", + ESP_LOGD(LOG_TAG, "Sending data to %s, blockNumber=%d, size=%d", Socket::addressToString(&m_partnerAddress).c_str(), blockNumber, sizeRead); - m_partnerSocket.sendTo((uint8_t*)&record, sizeRead+4, &m_partnerAddress); + m_partnerSocket.sendTo((uint8_t*) &record, sizeRead + 4, &m_partnerAddress); if (sizeRead < TFTP_DATA_SIZE) { @@ -141,7 +140,7 @@ void TFTP::TFTP_Transaction::processRRQ() { } blockNumber++; // Increment the block number. } - ESP_LOGD(tag, "File sent"); + ESP_LOGD(LOG_TAG, "File sent"); } // processRRQ @@ -167,27 +166,27 @@ void TFTP::TFTP_Transaction::processWRQ() { uint8_t dataBuffer[TFTP_DATA_SIZE + 2 + 2]; bool finished = false; - FILE *file; + FILE* file; - ESP_LOGD(tag, "Writing TFTP data to file: %s", m_filename.c_str()); + ESP_LOGD(LOG_TAG, "Writing TFTP data to file: %s", m_filename.c_str()); std::string tmpName = m_baseDir + "/" + m_filename; file = fopen(tmpName.c_str(), "w"); if (file == nullptr) { - ESP_LOGE(tag, "Failed to open file for writing: %s: %s", tmpName.c_str(), strerror(errno)); + ESP_LOGE(LOG_TAG, "Failed to open file for writing: %s: %s", tmpName.c_str(), strerror(errno)); return; } while(!finished) { - pRecv_data = (struct recv_data *)dataBuffer; + pRecv_data = (struct recv_data*) dataBuffer; int receivedSize = m_partnerSocket.receiveFrom(dataBuffer, sizeof(dataBuffer), &recvAddr); if (receivedSize == -1) { - ESP_LOGE(tag, "rc == -1 from receive_from"); + ESP_LOGE(LOG_TAG, "rc == -1 from receive_from"); } struct data_packet dp; dp.blockNumber = ntohs(pRecv_data->blockNumber); - dp.data = std::string((char *)&pRecv_data->data, receivedSize-4); + dp.data = std::string((char*) &pRecv_data->data, receivedSize - 4); fwrite(dp.data.data(), dp.data.length(), 1, file); sendAck(dp.blockNumber); - ESP_LOGD(tag, "Block size: %d", dp.data.length()); + ESP_LOGD(LOG_TAG, "Block size: %d", dp.data.length()); if (dp.data.length() < TFTP_DATA_SIZE) { finished = true; } @@ -213,8 +212,8 @@ void TFTP::TFTP_Transaction::sendAck(uint16_t blockNumber) { ackData.opCode = htons(TFTP_OPCODE_ACK); ackData.blockNumber = htons(blockNumber); - ESP_LOGD(tag, "Sending ack to %s, blockNumber=%d", Socket::addressToString(&m_partnerAddress).c_str(), blockNumber); - m_partnerSocket.sendTo((uint8_t *)&ackData, sizeof(ackData), &m_partnerAddress); + ESP_LOGD(LOG_TAG, "Sending ack to %s, blockNumber=%d", Socket::addressToString(&m_partnerAddress).c_str(), blockNumber); + m_partnerSocket.sendTo((uint8_t*) &ackData, sizeof(ackData), &m_partnerAddress); } // sendAck @@ -233,26 +232,29 @@ void TFTP::start(uint16_t port) { * or write a file to the server. Once we have received a request we then call the appropriate * handler to handle that type of request. When the request has been completed, we start again. */ - ESP_LOGD(tag, "Starting TFTP::start() on port %d", port); + ESP_LOGD(LOG_TAG, "Starting TFTP::start() on port %d", port); Socket serverSocket; serverSocket.listen(port, true); // Create a listening socket that is a datagram. - while(true) { + while (true) { // This would be a good place to start a transaction in the background. - TFTP_Transaction *pTFTPTransaction = new TFTP_Transaction(); + TFTP_Transaction* pTFTPTransaction = new TFTP_Transaction(); pTFTPTransaction->setBaseDir(m_baseDir); uint16_t receivedOpCode = pTFTPTransaction->waitForRequest(&serverSocket); - switch(receivedOpCode) { - // Handle the write request (client file upload) + switch (receivedOpCode) { + // Handle the write request (client file upload) case opcode::TFTP_OPCODE_WRQ: { pTFTPTransaction->processWRQ(); break; } - // Handle the read request (server file download) + // Handle the read request (server file download) case opcode::TFTP_OPCODE_RRQ: { pTFTPTransaction->processRRQ(); break; } + default: + ESP_LOGE(LOG_TAG, "Unknown opcode: %d", receivedOpCode); + break; } delete pTFTPTransaction; } // End while loop @@ -292,12 +294,12 @@ void TFTP::TFTP_Transaction::waitForAck(uint16_t blockNumber) { uint16_t blockNumber; } ackData; - ESP_LOGD(tag, "TFTP: Waiting for an acknowledgment request"); - int sizeRead = m_partnerSocket.receiveFrom((uint8_t *)&ackData, sizeof(ackData), &m_partnerAddress); - ESP_LOGD(tag, "TFTP: Received some data."); + ESP_LOGD(LOG_TAG, "TFTP: Waiting for an acknowledgment request"); + int sizeRead = m_partnerSocket.receiveFrom((uint8_t*) &ackData, sizeof(ackData), &m_partnerAddress); + ESP_LOGD(LOG_TAG, "TFTP: Received some data."); if (sizeRead != sizeof(ackData)) { - ESP_LOGE(tag, "waitForAck: Received %d but expected %d", sizeRead, sizeof(ackData)); + ESP_LOGE(LOG_TAG, "waitForAck: Received %d but expected %d", sizeRead, sizeof(ackData)); sendError(ERROR_CODE_NOTDEFINED, "Ack not correct size"); return; } @@ -306,12 +308,12 @@ void TFTP::TFTP_Transaction::waitForAck(uint16_t blockNumber) { ackData.blockNumber = ntohs(ackData.blockNumber); if (ackData.opCode != opcode::TFTP_OPCODE_ACK) { - ESP_LOGE(tag, "waitForAck: Received opcode %d but expected %d", ackData.opCode, opcode::TFTP_OPCODE_ACK); + ESP_LOGE(LOG_TAG, "waitForAck: Received opcode %d but expected %d", ackData.opCode, opcode::TFTP_OPCODE_ACK); return; } if (ackData.blockNumber != blockNumber) { - ESP_LOGE(tag, "waitForAck: Blocknumber received %d but expected %d", ackData.blockNumber, blockNumber); + ESP_LOGE(LOG_TAG, "waitForAck: Blocknumber received %d but expected %d", ackData.blockNumber, blockNumber); return; } } // waitForAck @@ -326,29 +328,28 @@ void TFTP::TFTP_Transaction::waitForAck(uint16_t blockNumber) { * @param pServerSocket The server socket on which to listen for client requests. * @return The op code received. */ -uint16_t TFTP::TFTP_Transaction::waitForRequest(Socket *pServerSocket) { /* * 2 bytes string 1 byte string 1 byte * ----------------------------------------------- * RRQ/ | 01/02 | Filename | 0 | Mode | 0 | * WRQ ----------------------------------------------- */ +uint16_t TFTP::TFTP_Transaction::waitForRequest(Socket* pServerSocket) { union { uint8_t buf[TFTP_DATA_SIZE]; uint16_t opCode; } record; size_t length = 100; - ESP_LOGD(tag, "TFTP: Waiting for a request"); + ESP_LOGD(LOG_TAG, "TFTP: Waiting for a request"); pServerSocket->receiveFrom(record.buf, length, &m_partnerAddress); // Save the filename, mode and op code. - m_filename = std::string((char *)(record.buf + 2)); - m_mode = std::string((char *)(record.buf + 3 + m_filename.length())); + m_filename = std::string((char*) (record.buf + 2)); + m_mode = std::string((char*) (record.buf + 3 + m_filename.length())); m_opCode = ntohs(record.opCode); - switch(m_opCode) { - + switch (m_opCode) { // Handle the Write Request command. case TFTP_OPCODE_WRQ: { m_partnerSocket.createSocket(true); @@ -357,7 +358,6 @@ uint16_t TFTP::TFTP_Transaction::waitForRequest(Socket *pServerSocket) { break; } - // Handle the Read request command. case TFTP_OPCODE_RRQ: { m_partnerSocket.createSocket(true); @@ -366,7 +366,7 @@ uint16_t TFTP::TFTP_Transaction::waitForRequest(Socket *pServerSocket) { } default: { - ESP_LOGD(tag, "Un-handled opcode: %d", m_opCode); + ESP_LOGD(LOG_TAG, "Un-handled opcode: %d", m_opCode); break; } } @@ -387,10 +387,10 @@ void TFTP::TFTP_Transaction::sendError(uint16_t code, std::string message) { * ----------------------------------------- */ int size = 2 + 2 + message.length() + 1; - uint8_t *buf = (uint8_t *)malloc(size); - *(uint16_t *)(&buf[0]) = htons(opcode::TFTP_OPCODE_ERROR); - *(uint16_t *)(&buf[2]) = htons(code); - strcpy((char *)(&buf[4]), message.c_str()); + uint8_t* buf = (uint8_t*) malloc(size); + *(uint16_t*) (&buf[0]) = htons(opcode::TFTP_OPCODE_ERROR); + *(uint16_t*) (&buf[2]) = htons(code); + strcpy((char*) (&buf[4]), message.c_str()); m_partnerSocket.sendTo(buf, size, &m_partnerAddress); free(buf); } // sendError diff --git a/cpp_utils/TFTP.h b/cpp_utils/TFTP.h index 3f40bd2b..56733598 100644 --- a/cpp_utils/TFTP.h +++ b/cpp_utils/TFTP.h @@ -36,7 +36,7 @@ class TFTP { public: TFTP(); virtual ~TFTP(); - void start(uint16_t port=TFTP_DEFAULT_PORT); + void start(uint16_t port = TFTP_DEFAULT_PORT); void setBaseDir(std::string baseDir); /** * @brief Internal class for %TFTP processing. @@ -50,7 +50,8 @@ class TFTP { void sendError(uint16_t code, std::string message); void setBaseDir(std::string baseDir); void waitForAck(uint16_t blockNumber); - uint16_t waitForRequest(Socket *pServerSocket); + uint16_t waitForRequest(Socket* pServerSocket); + private: /** * Socket on which the server will communicate with the client.. @@ -61,9 +62,12 @@ class TFTP { std::string m_filename; // The name of the file. std::string m_mode; std::string m_baseDir; // The base directory. + }; + private: std::string m_baseDir; + }; #endif /* COMPONENTS_CPP_UTILS_TFTP_H_ */ diff --git a/cpp_utils/Task.cpp b/cpp_utils/Task.cpp index a8ba9a37..43f587e2 100644 --- a/cpp_utils/Task.cpp +++ b/cpp_utils/Task.cpp @@ -14,7 +14,7 @@ #include "Task.h" #include "sdkconfig.h" -static char tag[] = "Task"; +static const char* LOG_TAG = "Task"; /** @@ -43,8 +43,8 @@ Task::~Task() { * @return N/A. */ -void Task::delay(int ms) { - ::vTaskDelay(ms/portTICK_PERIOD_MS); +/* static */ void Task::delay(int ms) { + ::vTaskDelay(ms / portTICK_PERIOD_MS); } // delay /** @@ -54,10 +54,10 @@ void Task::delay(int ms) { * @param [in] pTaskInstance The task to run. */ void Task::runTask(void* pTaskInstance) { - Task* pTask = (Task*)pTaskInstance; - ESP_LOGD(tag, ">> runTask: taskName=%s", pTask->m_taskName.c_str()); + Task* pTask = (Task*) pTaskInstance; + ESP_LOGD(LOG_TAG, ">> runTask: taskName=%s", pTask->m_taskName.c_str()); pTask->run(pTask->m_taskData); - ESP_LOGD(tag, "<< runTask: taskName=%s", pTask->m_taskName.c_str()); + ESP_LOGD(LOG_TAG, "<< runTask: taskName=%s", pTask->m_taskName.c_str()); pTask->stop(); } // runTask @@ -69,7 +69,7 @@ void Task::runTask(void* pTaskInstance) { */ void Task::start(void* taskData) { if (m_handle != nullptr) { - ESP_LOGW(tag, "Task::start - There might be a task already running!"); + ESP_LOGW(LOG_TAG, "Task::start - There might be a task already running!"); } m_taskData = taskData; ::xTaskCreatePinnedToCore(&runTask, m_taskName.c_str(), m_stackSize, this, m_priority, &m_handle, m_coreId); @@ -82,9 +82,7 @@ void Task::start(void* taskData) { * @return N/A. */ void Task::stop() { - if (m_handle == nullptr) { - return; - } + if (m_handle == nullptr) return; xTaskHandle temp = m_handle; m_handle = nullptr; ::vTaskDelete(temp); diff --git a/cpp_utils/Task.h b/cpp_utils/Task.h index 0d58f222..5eb4966b 100644 --- a/cpp_utils/Task.h +++ b/cpp_utils/Task.h @@ -33,13 +33,13 @@ */ class Task { public: - Task(std::string taskName="Task", uint16_t stackSize=10000, uint8_t priority=5); + Task(std::string taskName = "Task", uint16_t stackSize = 10000, uint8_t priority = 5); virtual ~Task(); void setStackSize(uint16_t stackSize); void setPriority(uint8_t priority); void setName(std::string name); void setCore(BaseType_t coreId); - void start(void* taskData=nullptr); + void start(void* taskData = nullptr); void stop(); /** * @brief Body of the task to execute. @@ -50,17 +50,18 @@ class Task { * * @param [in] data The data passed in to the newly started task. */ - virtual void run(void *data) = 0; // Make run pure virtual - void delay(int ms); + virtual void run(void* data) = 0; // Make run pure virtual + static void delay(int ms); private: xTaskHandle m_handle; void* m_taskData; - static void runTask(void *data); + static void runTask(void* data); std::string m_taskName; uint16_t m_stackSize; uint8_t m_priority; BaseType_t m_coreId; + }; #endif /* COMPONENTS_CPP_UTILS_TASK_H_ */ diff --git a/cpp_utils/U8G2.h b/cpp_utils/U8G2.h index db57ba64..386272fc 100644 --- a/cpp_utils/U8G2.h +++ b/cpp_utils/U8G2.h @@ -24,7 +24,7 @@ class U8G2 { u8g2_ClearBuffer(&m_u8g2); } - void drawBitmap(uint32_t x, uint32_t y, uint32_t cnt, uint32_t h, const uint8_t *bitmap) { + void drawBitmap(uint32_t x, uint32_t y, uint32_t cnt, uint32_t h, const uint8_t* bitmap) { u8g2_DrawBitmap(&m_u8g2, x, y, cnt, h, bitmap); } @@ -75,7 +75,6 @@ class U8G2 { u8g2_DrawRFrame(&m_u8g2, x, y, w, h, r); } - uint32_t drawStr(uint32_t x, uint32_t y, std::string s) { return u8g2_DrawStr(&m_u8g2, x, y, s.c_str()); } @@ -92,11 +91,11 @@ class U8G2 { u8g2_DrawVLine(&m_u8g2, x, y, h); } - int8_t getAscent(void) { + int8_t getAscent() { return u8g2_GetAscent(&m_u8g2); } - int8_t getDescent(void) { + int8_t getDescent() { return u8g2_GetDescent(&m_u8g2); } @@ -107,19 +106,23 @@ class U8G2 { void initDisplay() { u8g2_InitDisplay(&m_u8g2); } + void sendBuffer() { u8g2_SendBuffer(&m_u8g2); } - void setFont(const uint8_t *font) { + void setFont(const uint8_t* font) { u8g2_SetFont(&m_u8g2, font); } + void setPowerSave(uint8_t is_enable) { u8g2_SetPowerSave(&m_u8g2, is_enable); // wake up display } private: u8g2_t m_u8g2; + }; + #endif // CONFIG_U8G2_PRESENT #endif /* COMPONENTS_CPP_UTILS_U8G2_H_ */ diff --git a/cpp_utils/WS2812.cpp b/cpp_utils/WS2812.cpp index 624480f0..af4bc512 100644 --- a/cpp_utils/WS2812.cpp +++ b/cpp_utils/WS2812.cpp @@ -33,7 +33,7 @@ static const char* LOG_TAG = "WS2812"; * a logic 1 for 0.7us * a logic 0 for 0.6us */ -static void setItem1(rmt_item32_t *pItem) { +static void setItem1(rmt_item32_t* pItem) { assert(pItem != nullptr); pItem->level0 = 1; pItem->duration0 = 10; @@ -49,7 +49,7 @@ static void setItem1(rmt_item32_t *pItem) { * a logic 1 for 0.35us * a logic 0 for 0.8us */ -static void setItem0(rmt_item32_t *pItem) { +static void setItem0(rmt_item32_t* pItem) { assert(pItem != nullptr); pItem->level0 = 1; pItem->duration0 = 4; @@ -61,7 +61,7 @@ static void setItem0(rmt_item32_t *pItem) { /** * Add an RMT terminator into the RMT data. */ -static void setTerminator(rmt_item32_t *pItem) { +static void setTerminator(rmt_item32_t* pItem) { assert(pItem != nullptr); pItem->level0 = 0; pItem->duration0 = 0; @@ -74,7 +74,7 @@ static void setTerminator(rmt_item32_t *pItem) { * type which should be one of 'R', 'G' or 'B'. */ static uint8_t getChannelValueByType(char type, pixel_t pixel) { - switch(type) { + switch (type) { case 'r': case 'R': return pixel.red; @@ -84,13 +84,13 @@ static uint8_t getChannelValueByType(char type, pixel_t pixel) { case 'g': case 'G': return pixel.green; + default: + ESP_LOGW(LOG_TAG, "Unknown color channel 0x%2x", type); + return 0; } - ESP_LOGW(LOG_TAG, "Unknown color channel 0x%2x", type); - return 0; } // getChannelValueByType - /** * @brief Construct a wrapper for the pixels. * @@ -113,7 +113,7 @@ WS2812::WS2812(gpio_num_t dinPin, uint16_t pixelCount, int channel) { assert(ESP32CPP::GPIO::inRange(dinPin)); this->pixelCount = pixelCount; - this->channel = (rmt_channel_t)channel; + this->channel = (rmt_channel_t) channel; // The number of items is number of pixels * 24 bits per pixel + the terminator. // Remember that an item is TWO RMT output bits ... for NeoPixels this is correct because @@ -121,24 +121,23 @@ WS2812::WS2812(gpio_num_t dinPin, uint16_t pixelCount, int channel) { this->items = new rmt_item32_t[pixelCount * 24 + 1]; this->pixels = new pixel_t[pixelCount]; - this->colorOrder = (char *)"GRB"; + this->colorOrder = (char*) "GRB"; clear(); rmt_config_t config; config.rmt_mode = RMT_MODE_TX; config.channel = this->channel; config.gpio_num = dinPin; - config.mem_block_num = 8-this->channel; + config.mem_block_num = 8 - this->channel; config.clk_div = 8; config.tx_config.loop_en = 0; config.tx_config.carrier_en = 0; config.tx_config.idle_output_en = 1; - config.tx_config.idle_level = (rmt_idle_level_t)0; + config.tx_config.idle_level = (rmt_idle_level_t) 0; config.tx_config.carrier_freq_hz = 10000; config.tx_config.carrier_level = (rmt_carrier_level_t)1; config.tx_config.carrier_duty_percent = 50; - ESP_ERROR_CHECK(rmt_config(&config)); ESP_ERROR_CHECK(rmt_driver_install(this->channel, 0, 0)); } // WS2812 @@ -152,19 +151,19 @@ WS2812::WS2812(gpio_num_t dinPin, uint16_t pixelCount, int channel) { void WS2812::show() { auto pCurrentItem = this->items; - for (auto i=0; ipixelCount; i++) { + for (uint16_t i = 0; i < this->pixelCount; i++) { uint32_t currentPixel = (getChannelValueByType(this->colorOrder[0], this->pixels[i]) << 16) | (getChannelValueByType(this->colorOrder[1], this->pixels[i]) << 8) | (getChannelValueByType(this->colorOrder[2], this->pixels[i])); ESP_LOGD(LOG_TAG, "Pixel value: %x", currentPixel); - for (int j=23; j>=0; j--) { + for (int8_t j = 23; j >= 0; j--) { // We have 24 bits of data representing the red, green amd blue channels. The value of the // 24 bits to output is in the variable current_pixel. We now need to stream this value // through RMT in most significant bit first. To do this, we iterate through each of the 24 // bits from MSB to LSB. - if (currentPixel & (1<channel, this->items, this->pixelCount*24, 1 /* wait till done */)); + ESP_ERROR_CHECK(rmt_write_items(this->channel, this->items, this->pixelCount * 24, 1 /* wait till done */)); } // show @@ -191,7 +190,7 @@ void WS2812::show() { * an alternate order by supply an alternate three character string made up of 'R', 'G' and 'B' * for example "RGB". */ -void WS2812::setColorOrder(char *colorOrder) { +void WS2812::setColorOrder(char* colorOrder) { if (colorOrder != nullptr && strlen(colorOrder) == 3) { this->colorOrder = colorOrder; } @@ -208,14 +207,14 @@ void WS2812::setColorOrder(char *colorOrder) { * @param [in] green The amount of green in the pixel. * @param [in] blue The amount of blue in the pixel. */ -void WS2812::setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue) { +void WS2812::setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue) { assert(index < pixelCount); - this->pixels[index].red = red; this->pixels[index].green = green; this->pixels[index].blue = blue; } // setPixel + /** * @brief Set the given pixel to the specified color. * @@ -240,7 +239,6 @@ void WS2812::setPixel(uint16_t index, pixel_t pixel) { */ void WS2812::setPixel(uint16_t index, uint32_t pixel) { assert(index < pixelCount); - this->pixels[index].red = pixel & 0xff; this->pixels[index].green = (pixel & 0xff00) >> 8; this->pixels[index].blue = (pixel & 0xff0000) >> 16; @@ -256,64 +254,65 @@ void WS2812::setPixel(uint16_t index, uint32_t pixel) { * @param [in] saturation The amount of saturation in the pixel (0-255). * @param [in] brightness The amount of brightness in the pixel (0-255). */ -void WS2812::setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8_t brightness) { - double sat_red; - double sat_green; - double sat_blue; - double ctmp_red; - double ctmp_green; - double ctmp_blue; - double new_red; - double new_green; - double new_blue; - double dSaturation=(double)saturation/255; - double dBrightness=(double)brightness/255; - - assert(index < pixelCount); - - if (hue < 120) { - sat_red = (120 - hue) / 60.0; - sat_green = hue / 60.0; - sat_blue = 0; - } else if (hue < 240) { - sat_red = 0; - sat_green = (240 - hue) / 60.0; - sat_blue = (hue - 120) / 60.0; - } else { - sat_red = (hue - 240) / 60.0; - sat_green = 0; - sat_blue = (360 - hue) / 60.0; - } - - if (sat_red>1.0) { - sat_red=1.0; - } - if (sat_green>1.0) { - sat_green=1.0; - } - if (sat_blue>1.0) { - sat_blue=1.0; - } - - ctmp_red = 2 * dSaturation * sat_red + (1 - dSaturation); - ctmp_green = 2 * dSaturation * sat_green + (1 - dSaturation); - ctmp_blue = 2 * dSaturation * sat_blue + (1 - dSaturation); - - if (dBrightness < 0.5) { - new_red = dBrightness * ctmp_red; - new_green = dBrightness * ctmp_green; - new_blue = dBrightness * ctmp_blue; - } else { - new_red = (1 - dBrightness) * ctmp_red + 2 * dBrightness - 1; - new_green = (1 - dBrightness) * ctmp_green + 2 * dBrightness - 1; - new_blue = (1 - dBrightness) * ctmp_blue + 2 * dBrightness - 1; - } - - this->pixels[index].red = (uint8_t)(new_red*255); - this->pixels[index].green = (uint8_t)(new_green*255); - this->pixels[index].blue = (uint8_t)(new_blue*255); +void WS2812::setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8_t brightness) { + double sat_red; + double sat_green; + double sat_blue; + double ctmp_red; + double ctmp_green; + double ctmp_blue; + double new_red; + double new_green; + double new_blue; + double dSaturation = (double) saturation / 255; + double dBrightness = (double) brightness / 255; + + assert(index < pixelCount); + + if (hue < 120) { + sat_red = (120 - hue) / 60.0; + sat_green = hue / 60.0; + sat_blue = 0; + } else if (hue < 240) { + sat_red = 0; + sat_green = (240 - hue) / 60.0; + sat_blue = (hue - 120) / 60.0; + } else { + sat_red = (hue - 240) / 60.0; + sat_green = 0; + sat_blue = (360 - hue) / 60.0; + } + + if (sat_red > 1.0) { + sat_red = 1.0; + } + if (sat_green > 1.0) { + sat_green = 1.0; + } + if (sat_blue > 1.0) { + sat_blue = 1.0; + } + + ctmp_red = 2 * dSaturation * sat_red + (1 - dSaturation); + ctmp_green = 2 * dSaturation * sat_green + (1 - dSaturation); + ctmp_blue = 2 * dSaturation * sat_blue + (1 - dSaturation); + + if (dBrightness < 0.5) { + new_red = dBrightness * ctmp_red; + new_green = dBrightness * ctmp_green; + new_blue = dBrightness * ctmp_blue; + } else { + new_red = (1 - dBrightness) * ctmp_red + 2 * dBrightness - 1; + new_green = (1 - dBrightness) * ctmp_green + 2 * dBrightness - 1; + new_blue = (1 - dBrightness) * ctmp_blue + 2 * dBrightness - 1; + } + + this->pixels[index].red = (uint8_t)(new_red * 255); + this->pixels[index].green = (uint8_t)(new_green * 255); + this->pixels[index].blue = (uint8_t)(new_blue * 255); } // setHSBPixel + /** * @brief Clear all the pixel colors. * @@ -321,13 +320,14 @@ void WS2812::setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8 * The LEDs are not actually updated until a call to show(). */ void WS2812::clear() { - for (auto i=0; ipixelCount; i++) { + for (uint16_t i = 0; i < this->pixelCount; i++) { this->pixels[i].red = 0; this->pixels[i].green = 0; this->pixels[i].blue = 0; } } // clear + /** * @brief Class instance destructor. */ diff --git a/cpp_utils/WS2812.h b/cpp_utils/WS2812.h index f599c1b7..f11cbc89 100644 --- a/cpp_utils/WS2812.h +++ b/cpp_utils/WS2812.h @@ -48,21 +48,23 @@ typedef struct { */ class WS2812 { public: - WS2812(gpio_num_t gpioNum, uint16_t pixelCount, int channel=RMT_CHANNEL_0); + WS2812(gpio_num_t gpioNum, uint16_t pixelCount, int channel = RMT_CHANNEL_0); void show(); - void setColorOrder(char *order); + void setColorOrder(char* order); void setPixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue); void setPixel(uint16_t index, pixel_t pixel); void setPixel(uint16_t index, uint32_t pixel); void setHSBPixel(uint16_t index, uint16_t hue, uint8_t saturation, uint8_t brightness); void clear(); virtual ~WS2812(); + private: - char *colorOrder; + char* colorOrder; uint16_t pixelCount; rmt_channel_t channel; - rmt_item32_t *items; - pixel_t *pixels; + rmt_item32_t* items; + pixel_t* pixels; + }; #endif /* MAIN_WS2812_H_ */ diff --git a/cpp_utils/WebServer.cpp b/cpp_utils/WebServer.cpp index c250a4d5..0fc666af 100644 --- a/cpp_utils/WebServer.cpp +++ b/cpp_utils/WebServer.cpp @@ -18,107 +18,113 @@ #include #include -static char tag[] = "WebServer"; +#define STATE_NAME 0 +#define STATE_VALUE 1 + +static const char* LOG_TAG = "WebServer"; struct WebServerUserData { - WebServer *pWebServer; - WebServer::HTTPMultiPart *pMultiPart; - WebServer::WebSocketHandler *pWebSocketHandler; - void *originalUserData; + WebServer* pWebServer; + WebServer::HTTPMultiPart* pMultiPart; + WebServer::WebSocketHandler* pWebSocketHandler; + void* originalUserData; }; + /** * @brief Convert a Mongoose event type to a string. * @param [in] event The received event type. * @return The string representation of the event. */ static std::string mongoose_eventToString(int event) { - switch (event) { - case MG_EV_CONNECT: - return "MG_EV_CONNECT"; - case MG_EV_ACCEPT: - return "MG_EV_ACCEPT"; - case MG_EV_CLOSE: - return "MG_EV_CLOSE"; - case MG_EV_SEND: - return "MG_EV_SEND"; - case MG_EV_RECV: - return "MG_EV_RECV"; - case MG_EV_POLL: - return "MG_EV_POLL"; - case MG_EV_TIMER: - return "MG_EV_TIMER"; - case MG_EV_HTTP_PART_DATA: - return "MG_EV_HTTP_PART_DATA"; - case MG_EV_HTTP_MULTIPART_REQUEST: - return "MG_EV_HTTP_MULTIPART_REQUEST"; - case MG_EV_HTTP_PART_BEGIN: - return "MG_EV_HTTP_PART_BEGIN"; - case MG_EV_HTTP_PART_END: - return "MG_EV_HTTP_PART_END"; - case MG_EV_HTTP_MULTIPART_REQUEST_END: - return "MG_EV_HTTP_MULTIPART_REQUEST_END"; - case MG_EV_HTTP_REQUEST: - return "MG_EV_HTTP_REQUEST"; - case MG_EV_HTTP_REPLY: - return "MG_EV_HTTP_REPLY"; - case MG_EV_HTTP_CHUNK: - return "MG_EV_HTTP_CHUNK"; - case MG_EV_MQTT_CONNACK: - return "MG_EV_MQTT_CONNACK"; - case MG_EV_MQTT_CONNECT: - return "MG_EV_MQTT_CONNECT"; - case MG_EV_MQTT_DISCONNECT: - return "MG_EV_MQTT_DISCONNECT"; - case MG_EV_MQTT_PINGREQ: - return "MG_EV_MQTT_PINGREQ"; - case MG_EV_MQTT_PINGRESP: - return "MG_EV_MQTT_PINGRESP"; - case MG_EV_MQTT_PUBACK: - return "MG_EV_MQTT_PUBACK"; - case MG_EV_MQTT_PUBCOMP: - return "MG_EV_MQTT_PUBCOMP"; - case MG_EV_MQTT_PUBLISH: - return "MG_EV_MQTT_PUBLISH"; - case MG_EV_MQTT_PUBREC: - return "MG_EV_MQTT_PUBREC"; - case MG_EV_MQTT_PUBREL: - return "MG_EV_MQTT_PUBREL"; - case MG_EV_MQTT_SUBACK: - return "MG_EV_MQTT_SUBACK"; - case MG_EV_MQTT_SUBSCRIBE: - return "MG_EV_MQTT_SUBSCRIBE"; - case MG_EV_MQTT_UNSUBACK: - return "MG_EV_MQTT_UNSUBACK"; - case MG_EV_MQTT_UNSUBSCRIBE: - return "MG_EV_MQTT_UNSUBSCRIBE"; - case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: - return "MG_EV_WEBSOCKET_HANDSHAKE_REQUEST"; - case MG_EV_WEBSOCKET_HANDSHAKE_DONE: - return "MG_EV_WEBSOCKET_HANDSHAKE_DONE"; - case MG_EV_WEBSOCKET_FRAME: - return "MG_EV_WEBSOCKET_FRAME"; - case MG_EV_WEBSOCKET_CONTROL_FRAME: - return "MG_EV_WEBSOCKET_CONTROL_FRAME"; - } - std::string s; - s += "Unknown event: "; - s += event; - return s; + switch (event) { + case MG_EV_CONNECT: + return "MG_EV_CONNECT"; + case MG_EV_ACCEPT: + return "MG_EV_ACCEPT"; + case MG_EV_CLOSE: + return "MG_EV_CLOSE"; + case MG_EV_SEND: + return "MG_EV_SEND"; + case MG_EV_RECV: + return "MG_EV_RECV"; + case MG_EV_POLL: + return "MG_EV_POLL"; + case MG_EV_TIMER: + return "MG_EV_TIMER"; + case MG_EV_HTTP_PART_DATA: + return "MG_EV_HTTP_PART_DATA"; + case MG_EV_HTTP_MULTIPART_REQUEST: + return "MG_EV_HTTP_MULTIPART_REQUEST"; + case MG_EV_HTTP_PART_BEGIN: + return "MG_EV_HTTP_PART_BEGIN"; + case MG_EV_HTTP_PART_END: + return "MG_EV_HTTP_PART_END"; + case MG_EV_HTTP_MULTIPART_REQUEST_END: + return "MG_EV_HTTP_MULTIPART_REQUEST_END"; + case MG_EV_HTTP_REQUEST: + return "MG_EV_HTTP_REQUEST"; + case MG_EV_HTTP_REPLY: + return "MG_EV_HTTP_REPLY"; + case MG_EV_HTTP_CHUNK: + return "MG_EV_HTTP_CHUNK"; + case MG_EV_MQTT_CONNACK: + return "MG_EV_MQTT_CONNACK"; + case MG_EV_MQTT_CONNECT: + return "MG_EV_MQTT_CONNECT"; + case MG_EV_MQTT_DISCONNECT: + return "MG_EV_MQTT_DISCONNECT"; + case MG_EV_MQTT_PINGREQ: + return "MG_EV_MQTT_PINGREQ"; + case MG_EV_MQTT_PINGRESP: + return "MG_EV_MQTT_PINGRESP"; + case MG_EV_MQTT_PUBACK: + return "MG_EV_MQTT_PUBACK"; + case MG_EV_MQTT_PUBCOMP: + return "MG_EV_MQTT_PUBCOMP"; + case MG_EV_MQTT_PUBLISH: + return "MG_EV_MQTT_PUBLISH"; + case MG_EV_MQTT_PUBREC: + return "MG_EV_MQTT_PUBREC"; + case MG_EV_MQTT_PUBREL: + return "MG_EV_MQTT_PUBREL"; + case MG_EV_MQTT_SUBACK: + return "MG_EV_MQTT_SUBACK"; + case MG_EV_MQTT_SUBSCRIBE: + return "MG_EV_MQTT_SUBSCRIBE"; + case MG_EV_MQTT_UNSUBACK: + return "MG_EV_MQTT_UNSUBACK"; + case MG_EV_MQTT_UNSUBSCRIBE: + return "MG_EV_MQTT_UNSUBSCRIBE"; + case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: + return "MG_EV_WEBSOCKET_HANDSHAKE_REQUEST"; + case MG_EV_WEBSOCKET_HANDSHAKE_DONE: + return "MG_EV_WEBSOCKET_HANDSHAKE_DONE"; + case MG_EV_WEBSOCKET_FRAME: + return "MG_EV_WEBSOCKET_FRAME"; + case MG_EV_WEBSOCKET_CONTROL_FRAME: + return "MG_EV_WEBSOCKET_CONTROL_FRAME"; + } + std::string s; + s += "Unknown event: "; + s += event; + return s; } //eventToString -static void dumpHttpMessage(struct http_message *pHttpMessage) { - ESP_LOGD(tag, "HTTP Message"); - ESP_LOGD(tag, "Message: %.*s", (int)pHttpMessage->message.len, pHttpMessage->message.p); + +static void dumpHttpMessage(struct http_message* pHttpMessage) { + ESP_LOGD(LOG_TAG, "HTTP Message"); + ESP_LOGD(LOG_TAG, "Message: %.*s", (int) pHttpMessage->message.len, pHttpMessage->message.p); } /* -static struct mg_str uploadFileNameHandler(struct mg_connection *mgConnection, struct mg_str fname) { - ESP_LOGD(tag, "uploadFileNameHandler: %s", mgStrToString(fname).c_str()); - return fname; +static struct mg_str uploadFileNameHandler(struct mg_connection* mgConnection, struct mg_str fname) { + ESP_LOGD(LOG_TAG, "uploadFileNameHandler: %s", mgStrToString(fname).c_str()); + return fname; } */ + /** * @brief Mongoose event handler. * The event handler is called when an event occurs associated with the WebServer @@ -129,147 +135,139 @@ static struct mg_str uploadFileNameHandler(struct mg_connection *mgConnection, s * @param [in] eventData Data associated with the event. * @return N/A. */ -static void mongoose_event_handler_web_server( - struct mg_connection *mgConnection, // The network connection associated with the event. - int event, // The type of event. - void *eventData // Data associated with the event. -) { - if (event == MG_EV_POLL) { - return; - } - ESP_LOGD(tag, "Event: %s [%d]", mongoose_eventToString(event).c_str(), mgConnection->sock); - switch (event) { - case MG_EV_SEND: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - WebServer *pWebServer = pWebServerUserData->pWebServer; - pWebServer->continueConnection(mgConnection); - break; - } - - case MG_EV_HTTP_REQUEST: { - struct http_message *message = (struct http_message *) eventData; - dumpHttpMessage(message); - - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - WebServer *pWebServer = pWebServerUserData->pWebServer; - pWebServer->processRequest(mgConnection, message); - break; - } // MG_EV_HTTP_REQUEST - - case MG_EV_HTTP_MULTIPART_REQUEST: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - ESP_LOGD(tag, "User_data address 0x%d", (uint32_t)pWebServerUserData); - WebServer *pWebServer = pWebServerUserData->pWebServer; - if (pWebServer->m_pMultiPartFactory == nullptr) { - return; - } - WebServer::HTTPMultiPart *pMultiPart = pWebServer->m_pMultiPartFactory->newInstance(); - struct WebServerUserData *p2 = new WebServerUserData(); - ESP_LOGD(tag, "New User_data address 0x%d", (uint32_t)p2); - p2->originalUserData = pWebServerUserData; - p2->pWebServer = pWebServerUserData->pWebServer; - p2->pMultiPart = pMultiPart; - p2->pWebSocketHandler = nullptr; - mgConnection->user_data = p2; - //struct http_message *message = (struct http_message *) eventData; - //dumpHttpMessage(message); - break; - } // MG_EV_HTTP_MULTIPART_REQUEST - - case MG_EV_HTTP_MULTIPART_REQUEST_END: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - if (pWebServerUserData->pMultiPart != nullptr) { - delete pWebServerUserData->pMultiPart; - pWebServerUserData->pMultiPart = nullptr; - } - mgConnection->user_data = pWebServerUserData->originalUserData; - delete pWebServerUserData; - WebServer::HTTPResponse httpResponse = WebServer::HTTPResponse(mgConnection); - httpResponse.setStatus(200); - httpResponse.sendData(""); - break; - } // MG_EV_HTTP_MULTIPART_REQUEST_END - - case MG_EV_HTTP_PART_BEGIN: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - struct mg_http_multipart_part *part = (struct mg_http_multipart_part *)eventData; - ESP_LOGD(tag, "file_name: \"%s\", var_name: \"%s\", status: %d, user_data: 0x%d", - part->file_name, part->var_name, part->status, (uint32_t)part->user_data); - if (pWebServerUserData->pMultiPart != nullptr) { - pWebServerUserData->pMultiPart->begin(std::string(part->var_name), std::string(part->file_name)); - } - break; - } // MG_EV_HTTP_PART_BEGIN - - case MG_EV_HTTP_PART_DATA: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - struct mg_http_multipart_part *part = (struct mg_http_multipart_part *)eventData; - ESP_LOGD(tag, "file_name: \"%s\", var_name: \"%s\", status: %d, user_data: 0x%d", - part->file_name, part->var_name, part->status, (uint32_t)part->user_data); - if (pWebServerUserData->pMultiPart != nullptr) { - pWebServerUserData->pMultiPart->data(std::string(part->data.p, part->data.len)); - } - break; - } // MG_EV_HTTP_PART_DATA - - case MG_EV_HTTP_PART_END: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - struct mg_http_multipart_part *part = (struct mg_http_multipart_part *)eventData; - ESP_LOGD(tag, "file_name: \"%s\", var_name: \"%s\", status: %d, user_data: 0x%d", - part->file_name, part->var_name, part->status, (uint32_t)part->user_data); - if (pWebServerUserData->pMultiPart != nullptr) { - pWebServerUserData->pMultiPart->end(); - } - break; - } // MG_EV_HTTP_PART_END - - case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - WebServer *pWebServer = pWebServerUserData->pWebServer; - if (pWebServer->m_pWebSocketHandlerFactory != nullptr) { - if (pWebServerUserData->pWebSocketHandler != nullptr) { - ESP_LOGD(tag, "Warning: MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: pWebSocketHandler was NOT null"); - } - struct WebServerUserData *p2 = new WebServerUserData(); - ESP_LOGD(tag, "New User_data address 0x%d", (uint32_t)p2); - p2->originalUserData = pWebServerUserData; - p2->pWebServer = pWebServerUserData->pWebServer; - p2->pWebSocketHandler = pWebServer->m_pWebSocketHandlerFactory->newInstance(); - mgConnection->user_data = p2; - } else { - ESP_LOGD(tag, "We received a WebSocket request but we have no handler factory!"); - } - break; - } // MG_EV_WEBSOCKET_HANDSHAKE_REQUEST - - case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - if (pWebServerUserData->pWebSocketHandler == nullptr) { - ESP_LOGE(tag, "Error: MG_EV_WEBSOCKET_FRAME: pWebSocketHandler is null"); - return; - } - pWebServerUserData->pWebSocketHandler->onCreated(); - break; - } // MG_EV_WEBSOCKET_HANDSHAKE_DONE - - - /* - * When we receive a MG_EV_WEBSOCKET_FRAME then we have received a chunk of data over the network. - * Our goal will be to send this to the web socket handler (if one exists). - */ - case MG_EV_WEBSOCKET_FRAME: { - struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data; - if (pWebServerUserData->pWebSocketHandler == nullptr) { - ESP_LOGE(tag, "Error: MG_EV_WEBSOCKET_FRAME: pWebSocketHandler is null"); - return; - } - struct websocket_message *ws_message = (websocket_message *)eventData; - ESP_LOGD(tag, "Received data length: %d", ws_message->size); - pWebServerUserData->pWebSocketHandler->onMessage(std::string((char *)ws_message->data, ws_message->size)); - break; - } // MG_EV_WEBSOCKET_FRAME - - } // End of switch +static void mongoose_event_handler_web_server(struct mg_connection* mgConnection, int event, void* eventData) { + if (event == MG_EV_POLL) return; + ESP_LOGD(LOG_TAG, "Event: %s [%d]", mongoose_eventToString(event).c_str(), mgConnection->sock); + switch (event) { + case MG_EV_SEND: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + WebServer* pWebServer = pWebServerUserData->pWebServer; + pWebServer->continueConnection(mgConnection); + break; + } + + case MG_EV_HTTP_REQUEST: { + struct http_message* message = (struct http_message*) eventData; + dumpHttpMessage(message); + + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + WebServer* pWebServer = pWebServerUserData->pWebServer; + pWebServer->processRequest(mgConnection, message); + break; + } // MG_EV_HTTP_REQUEST + + case MG_EV_HTTP_MULTIPART_REQUEST: { + struct WebServerUserData *pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + ESP_LOGD(LOG_TAG, "User_data address 0x%d", (uint32_t) pWebServerUserData); + WebServer* pWebServer = pWebServerUserData->pWebServer; + if (pWebServer->m_pMultiPartFactory == nullptr) return; + WebServer::HTTPMultiPart* pMultiPart = pWebServer->m_pMultiPartFactory->newInstance(); + struct WebServerUserData* p2 = new WebServerUserData(); + ESP_LOGD(LOG_TAG, "New User_data address 0x%d", (uint32_t) p2); + p2->originalUserData = pWebServerUserData; + p2->pWebServer = pWebServerUserData->pWebServer; + p2->pMultiPart = pMultiPart; + p2->pWebSocketHandler = nullptr; + mgConnection->user_data = p2; + //struct http_message* message = (struct http_message*) eventData; + //dumpHttpMessage(message); + break; + } // MG_EV_HTTP_MULTIPART_REQUEST + + case MG_EV_HTTP_MULTIPART_REQUEST_END: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + if (pWebServerUserData->pMultiPart != nullptr) { + delete pWebServerUserData->pMultiPart; + pWebServerUserData->pMultiPart = nullptr; + } + mgConnection->user_data = pWebServerUserData->originalUserData; + delete pWebServerUserData; + WebServer::HTTPResponse httpResponse = WebServer::HTTPResponse(mgConnection); + httpResponse.setStatus(200); + httpResponse.sendData(""); + break; + } // MG_EV_HTTP_MULTIPART_REQUEST_END + + case MG_EV_HTTP_PART_BEGIN: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + struct mg_http_multipart_part* part = (struct mg_http_multipart_part*) eventData; + ESP_LOGD(LOG_TAG, "file_name: \"%s\", var_name: \"%s\", status: %d, user_data: 0x%d", + part->file_name, part->var_name, part->status, (uint32_t) part->user_data); + if (pWebServerUserData->pMultiPart != nullptr) { + pWebServerUserData->pMultiPart->begin(std::string(part->var_name), std::string(part->file_name)); + } + break; + } // MG_EV_HTTP_PART_BEGIN + + case MG_EV_HTTP_PART_DATA: { + struct WebServerUserData *pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + struct mg_http_multipart_part* part = (struct mg_http_multipart_part*) eventData; + ESP_LOGD(LOG_TAG, "file_name: \"%s\", var_name: \"%s\", status: %d, user_data: 0x%d", + part->file_name, part->var_name, part->status, (uint32_t) part->user_data); + if (pWebServerUserData->pMultiPart != nullptr) { + pWebServerUserData->pMultiPart->data(std::string(part->data.p, part->data.len)); + } + break; + } // MG_EV_HTTP_PART_DATA + + case MG_EV_HTTP_PART_END: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + struct mg_http_multipart_part* part = (struct mg_http_multipart_part*) eventData; + ESP_LOGD(LOG_TAG, "file_name: \"%s\", var_name: \"%s\", status: %d, user_data: 0x%d", + part->file_name, part->var_name, part->status, (uint32_t)part->user_data); + if (pWebServerUserData->pMultiPart != nullptr) { + pWebServerUserData->pMultiPart->end(); + } + break; + } // MG_EV_HTTP_PART_END + + case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + WebServer* pWebServer = pWebServerUserData->pWebServer; + if (pWebServer->m_pWebSocketHandlerFactory != nullptr) { + if (pWebServerUserData->pWebSocketHandler != nullptr) { + ESP_LOGD(LOG_TAG, "Warning: MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: pWebSocketHandler was NOT null"); + } + struct WebServerUserData* p2 = new WebServerUserData(); + ESP_LOGD(LOG_TAG, "New User_data address 0x%d", (uint32_t) p2); + p2->originalUserData = pWebServerUserData; + p2->pWebServer = pWebServerUserData->pWebServer; + p2->pWebSocketHandler = pWebServer->m_pWebSocketHandlerFactory->newInstance(); + mgConnection->user_data = p2; + } else { + ESP_LOGD(LOG_TAG, "We received a WebSocket request but we have no handler factory!"); + } + break; + } // MG_EV_WEBSOCKET_HANDSHAKE_REQUEST + + case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + if (pWebServerUserData->pWebSocketHandler == nullptr) { + ESP_LOGE(LOG_TAG, "Error: MG_EV_WEBSOCKET_FRAME: pWebSocketHandler is null"); + return; + } + pWebServerUserData->pWebSocketHandler->onCreated(); + break; + } // MG_EV_WEBSOCKET_HANDSHAKE_DONE + + + /* + * When we receive a MG_EV_WEBSOCKET_FRAME then we have received a chunk of data over the network. + * Our goal will be to send this to the web socket handler (if one exists). + */ + case MG_EV_WEBSOCKET_FRAME: { + struct WebServerUserData* pWebServerUserData = (struct WebServerUserData*) mgConnection->user_data; + if (pWebServerUserData->pWebSocketHandler == nullptr) { + ESP_LOGE(LOG_TAG, "Error: MG_EV_WEBSOCKET_FRAME: pWebSocketHandler is null"); + return; + } + struct websocket_message* ws_message = (websocket_message*) eventData; + ESP_LOGD(LOG_TAG, "Received data length: %d", ws_message->size); + pWebServerUserData->pWebSocketHandler->onMessage(std::string((char*) ws_message->data, ws_message->size)); + break; + } // MG_EV_WEBSOCKET_FRAME + + } // End of switch } // End of mongoose_event_handler @@ -277,9 +275,9 @@ static void mongoose_event_handler_web_server( * @brief Constructor. */ WebServer::WebServer() { - m_rootPath = ""; - m_pMultiPartFactory = nullptr; - m_pWebSocketHandlerFactory = nullptr; + m_rootPath = ""; + m_pMultiPartFactory = nullptr; + m_pWebSocketHandlerFactory = nullptr; } // WebServer @@ -292,7 +290,7 @@ WebServer::~WebServer() { * @return The current root path. */ const std::string& WebServer::getRootPath() { - return m_rootPath; + return m_rootPath; } // getRootPath @@ -317,15 +315,17 @@ const std::string& WebServer::getRootPath() { * @param [in] handler The callback function to be invoked when a request arrives. */ void WebServer::addPathHandler(const std::string& method, const std::string& pathExpr, - void (* handler)(WebServer::HTTPRequest* pHttpRequest, + void (*handler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { - m_pathHandlers.push_back(PathHandler(method, pathExpr, handler)); + m_pathHandlers.push_back(PathHandler(method, pathExpr, handler)); } // addPathHandler -void WebServer::addPathHandler(std::string&& method, const std::string& pathExpr, void (* handler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { - m_pathHandlers.push_back(PathHandler(std::move(method), pathExpr, handler)); + +void WebServer::addPathHandler(std::string&& method, const std::string& pathExpr, void (*handler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { + m_pathHandlers.push_back(PathHandler(std::move(method), pathExpr, handler)); } // addPathHandler + /** * @brief Run the web server listening at the given port. * @@ -335,31 +335,31 @@ void WebServer::addPathHandler(std::string&& method, const std::string& pathExpr * @return N/A. */ void WebServer::start(uint16_t port) { - ESP_LOGD(tag, "WebServer task starting"); - struct mg_mgr mgr; - mg_mgr_init(&mgr, NULL); - - std::stringstream stringStream; - stringStream << ':' << port; - struct mg_connection *mgConnection = mg_bind(&mgr, stringStream.str().c_str(), mongoose_event_handler_web_server); - - if (mgConnection == NULL) { - ESP_LOGE(tag, "No connection from the mg_bind()"); - vTaskDelete(NULL); - return; - } - - struct WebServerUserData *pWebServerUserData = new WebServerUserData(); - pWebServerUserData->pWebServer = this; - pWebServerUserData->pMultiPart = nullptr; - mgConnection->user_data = pWebServerUserData; // Save the WebServer instance reference in user_data. - ESP_LOGD(tag, "start: User_data address 0x%d", (uint32_t)pWebServerUserData); - mg_set_protocol_http_websocket(mgConnection); - - ESP_LOGD(tag, "WebServer listening on port %d", port); - while (1) { - mg_mgr_poll(&mgr, 2000); - } + ESP_LOGD(LOG_TAG, "WebServer task starting"); + struct mg_mgr mgr; + mg_mgr_init(&mgr, NULL); + + std::stringstream stringStream; + stringStream << ':' << port; + struct mg_connection *mgConnection = mg_bind(&mgr, stringStream.str().c_str(), mongoose_event_handler_web_server); + + if (mgConnection == NULL) { + ESP_LOGE(LOG_TAG, "No connection from the mg_bind()"); + vTaskDelete(NULL); + return; + } + + struct WebServerUserData* pWebServerUserData = new WebServerUserData(); + pWebServerUserData->pWebServer = this; + pWebServerUserData->pMultiPart = nullptr; + mgConnection->user_data = pWebServerUserData; // Save the WebServer instance reference in user_data. + ESP_LOGD(LOG_TAG, "start: User_data address 0x%d", (uint32_t)pWebServerUserData); + mg_set_protocol_http_websocket(mgConnection); + + ESP_LOGD(LOG_TAG, "WebServer listening on port %d", port); + while (true) { + mg_mgr_poll(&mgr, 2000); + } } // run @@ -368,7 +368,7 @@ void WebServer::start(uint16_t port) { * @param [in] pMultiPart A pointer to the multi part factory. */ void WebServer::setMultiPartFactory(HTTPMultiPartFactory *pMultiPartFactory) { - m_pMultiPartFactory = pMultiPartFactory; + m_pMultiPartFactory = pMultiPartFactory; } @@ -390,11 +390,12 @@ void WebServer::setMultiPartFactory(HTTPMultiPartFactory *pMultiPartFactory) { * @return N/A. */ void WebServer::setRootPath(const std::string& path) { - m_rootPath = path; + m_rootPath = path; } // setRootPath + void WebServer::setRootPath(std::string&& path) { - m_rootPath = std::move(path); + m_rootPath = std::move(path); } // setRootPath @@ -405,7 +406,7 @@ void WebServer::setRootPath(std::string&& path) { * @return N/A. */ void WebServer::setWebSocketHandlerFactory(WebSocketHandlerFactory* pWebSocketHandlerFactory) { - m_pWebSocketHandlerFactory = pWebSocketHandlerFactory; + m_pWebSocketHandlerFactory = pWebSocketHandlerFactory; } // setWebSocketHandlerFactory @@ -414,9 +415,9 @@ void WebServer::setWebSocketHandlerFactory(WebSocketHandlerFactory* pWebSocketHa * @param [in] nc The network connection for the response. */ WebServer::HTTPResponse::HTTPResponse(struct mg_connection* nc) { - m_nc = nc; - m_status = 200; - m_dataSent = false; + m_nc = nc; + m_status = 200; + m_dataSent = false; } // HTTPResponse @@ -426,11 +427,11 @@ WebServer::HTTPResponse::HTTPResponse(struct mg_connection* nc) { * @param [in] value The value of the header. */ void WebServer::HTTPResponse::addHeader(const std::string& name, const std::string& value) { - m_headers[name] = value; + m_headers[name] = value; } // addHeader void WebServer::HTTPResponse::addHeader(std::string&& name, std::string&& value) { - m_headers[std::move(name)] = std::move(value); + m_headers[std::move(name)] = std::move(value); } // addHeader @@ -442,9 +443,10 @@ std::string WebServer::HTTPResponse::buildHeaders() { std::string headers; unsigned long headers_len = 0; - for(auto iter = m_headers.begin(); iter != m_headers.end(); iter++) { - if(iter != m_headers.begin()) - headers_len += 2; + for (auto iter = m_headers.begin(); iter != m_headers.end(); iter++) { + if (iter != m_headers.begin()) { + headers_len += 2; + } headers_len += iter->first.length(); headers_len += 2; headers_len += iter->second.length(); @@ -453,8 +455,9 @@ std::string WebServer::HTTPResponse::buildHeaders() { headers.resize(headers_len); // Will not have to resize and recopy during the next loop, we have 2 loops but it still ends up being faster for (auto iter = m_headers.begin(); iter != m_headers.end(); iter++) { - if(iter != m_headers.begin()) - headers += "\r\n"; + if (iter != m_headers.begin()) { + headers += "\r\n"; + } headers += iter->first; headers += ": "; headers += iter->second; @@ -462,6 +465,7 @@ std::string WebServer::HTTPResponse::buildHeaders() { return headers; } // buildHeaders + /** * @brief Send data to the HTTP caller. * Send the data to the HTTP caller. No further data should be sent after this call. @@ -469,13 +473,10 @@ std::string WebServer::HTTPResponse::buildHeaders() { * @return N/A. */ void WebServer::HTTPResponse::sendData(const std::string& data) { - sendData((uint8_t *)data.data(), data.length()); + sendData((uint8_t*) data.data(), data.length()); } // sendData - - - /** * @brief Send data to the HTTP caller. * Send the data to the HTTP caller. No further data should be sent after this call. @@ -484,15 +485,15 @@ void WebServer::HTTPResponse::sendData(const std::string& data) { * @return N/A. */ void WebServer::HTTPResponse::sendData(const uint8_t* pData, size_t length) { - if (m_dataSent) { - ESP_LOGE(tag, "HTTPResponse: Data already sent! Attempt to send again/more."); - return; - } - m_dataSent = true; - - mg_send_head(m_nc, m_status, length, buildHeaders().c_str()); - mg_send(m_nc, pData, length); - m_nc->flags |= MG_F_SEND_AND_CLOSE; + if (m_dataSent) { + ESP_LOGE(LOG_TAG, "HTTPResponse: Data already sent! Attempt to send again/more."); + return; + } + m_dataSent = true; + + mg_send_head(m_nc, m_status, length, buildHeaders().c_str()); + mg_send(m_nc, pData, length); + m_nc->flags |= MG_F_SEND_AND_CLOSE; } // sendData @@ -500,7 +501,7 @@ void WebServer::HTTPResponse::sendData(const uint8_t* pData, size_t length) { * */ void WebServer::HTTPResponse::sendData(const char* pData, size_t length) { - sendData((uint8_t*) pData, length); + sendData((uint8_t*) pData, length); } // sendData @@ -508,11 +509,11 @@ void WebServer::HTTPResponse::sendData(const char* pData, size_t length) { * */ void WebServer::HTTPResponse::sendChunkHead() { - if(m_dataSent) { - ESP_LOGE(tag, "HTTPResponse: Chunk headers already sent! Attempt to send again/more."); - } - m_dataSent = true; - mg_send_head(m_nc, m_status, -1, buildHeaders().c_str()); + if (m_dataSent) { + ESP_LOGE(LOG_TAG, "HTTPResponse: Chunk headers already sent! Attempt to send again/more."); + } + m_dataSent = true; + mg_send_head(m_nc, m_status, -1, buildHeaders().c_str()); } // sendChunkHead @@ -520,7 +521,7 @@ void WebServer::HTTPResponse::sendChunkHead() { * */ void WebServer::HTTPResponse::sendChunk(const char* pData, size_t length) { - mg_send_http_chunk(m_nc, pData, length); + mg_send_http_chunk(m_nc, pData, length); } // sendChunkHead @@ -528,7 +529,7 @@ void WebServer::HTTPResponse::sendChunk(const char* pData, size_t length) { * */ void WebServer::HTTPResponse::closeConnection() { - m_nc->flags |= MG_F_SEND_AND_CLOSE; + m_nc->flags |= MG_F_SEND_AND_CLOSE; } // closeConnection @@ -538,11 +539,12 @@ void WebServer::HTTPResponse::closeConnection() { * @return N/A. */ void WebServer::HTTPResponse::setHeaders(const std::map& headers) { - m_headers = headers; + m_headers = headers; } // setHeaders + void WebServer::HTTPResponse::setHeaders(std::map&& headers) { - m_headers = std::move(headers); + m_headers = std::move(headers); } // setHeaders @@ -551,7 +553,7 @@ void WebServer::HTTPResponse::setHeaders(std::map&& he * @return The current root path. */ const std::string& WebServer::HTTPResponse::getRootPath() const { - return m_rootPath; + return m_rootPath; } // getRootPath @@ -561,13 +563,15 @@ const std::string& WebServer::HTTPResponse::getRootPath() const { * @return N/A. */ void WebServer::HTTPResponse::setRootPath(const std::string& path) { - m_rootPath = path; + m_rootPath = path; } // setRootPath + void WebServer::HTTPResponse::setRootPath(std::string&& path) { - m_rootPath = std::move(path); + m_rootPath = std::move(path); } // setRootPath + /** * @brief Set the status value in the HTTP response. * @@ -576,7 +580,7 @@ void WebServer::HTTPResponse::setRootPath(std::string&& path) { * @return N/A. */ void WebServer::HTTPResponse::setStatus(int status) { - m_status = status; + m_status = status; } // setStatus @@ -590,74 +594,73 @@ void WebServer::HTTPResponse::setStatus(int status) { * @param [in] mgConnection The network connection on which the request was received. * @param [in] message The message representing the request. */ -void WebServer::processRequest(struct mg_connection *mgConnection, struct http_message* message) { - ESP_LOGD(tag, "WebServer::processRequest: Matching: %.*s", (int)message->uri.len, message->uri.p); - HTTPResponse httpResponse = HTTPResponse(mgConnection); - - /* - * Iterate through each of the path handlers looking for a match with the method and specified path. - */ - std::vector::iterator it; - for (it = m_pathHandlers.begin(); it != m_pathHandlers.end(); ++it) { - if ((*it).match(message->method.p, message->method.len, message->uri.p)) { - HTTPRequest httpRequest(message); - (*it).invoke(&httpRequest, &httpResponse); - ESP_LOGD(tag, "Found a match!!"); - return; - } - } // End of examine path handlers. - - // Because we reached here, it means that we did NOT match a handler. Now we want to attempt - // to retrieve the corresponding file content. - std::string filePath; - filePath.reserve(httpResponse.getRootPath().length() + message->uri.len + 1); - filePath += httpResponse.getRootPath(); - filePath.append(message->uri.p, message->uri.len); - ESP_LOGD(tag, "Opening file: %s", filePath.c_str()); - FILE* file = nullptr; - - if(strcmp(filePath.c_str(), "/") != 0) - file = fopen(filePath.c_str(), "rb"); - if (file != nullptr) { - auto pData = (uint8_t*)malloc(MAX_CHUNK_LENGTH); - size_t read = fread(pData, 1, MAX_CHUNK_LENGTH, file); - - if(read >= MAX_CHUNK_LENGTH) { - httpResponse.sendChunkHead(); - httpResponse.sendChunk((char*)pData, read); - fclose(unfinishedConnection[mgConnection->sock]); - unfinishedConnection[mgConnection->sock] = file; - } else { - fclose(file); - httpResponse.sendData(pData, read); - } - free(pData); - } else { - // Handle unable to open file - httpResponse.setStatus(404); // Not found - httpResponse.sendData(""); - } +void WebServer::processRequest(struct mg_connection* mgConnection, struct http_message* message) { + ESP_LOGD(LOG_TAG, "WebServer::processRequest: Matching: %.*s", (int) message->uri.len, message->uri.p); + HTTPResponse httpResponse = HTTPResponse(mgConnection); + + /* + * Iterate through each of the path handlers looking for a match with the method and specified path. + */ + std::vector::iterator it; + for (it = m_pathHandlers.begin(); it != m_pathHandlers.end(); ++it) { + if ((*it).match(message->method.p, message->method.len, message->uri.p)) { + HTTPRequest httpRequest(message); + (*it).invoke(&httpRequest, &httpResponse); + ESP_LOGD(LOG_TAG, "Found a match!!"); + return; + } + } // End of examine path handlers. + + // Because we reached here, it means that we did NOT match a handler. Now we want to attempt + // to retrieve the corresponding file content. + std::string filePath; + filePath.reserve(httpResponse.getRootPath().length() + message->uri.len + 1); + filePath += httpResponse.getRootPath(); + filePath.append(message->uri.p, message->uri.len); + ESP_LOGD(LOG_TAG, "Opening file: %s", filePath.c_str()); + FILE* file = nullptr; + + if (strcmp(filePath.c_str(), "/") != 0) { + file = fopen(filePath.c_str(), "rb"); + } + if (file != nullptr) { + auto pData = (uint8_t*)malloc(MAX_CHUNK_LENGTH); + size_t read = fread(pData, 1, MAX_CHUNK_LENGTH, file); + + if (read >= MAX_CHUNK_LENGTH) { + httpResponse.sendChunkHead(); + httpResponse.sendChunk((char*) pData, read); + fclose(unfinishedConnection[mgConnection->sock]); + unfinishedConnection[mgConnection->sock] = file; + } else { + fclose(file); + httpResponse.sendData(pData, read); + } + free(pData); + } else { + // Handle unable to open file + httpResponse.setStatus(404); // Not found + httpResponse.sendData(""); + } } // processRequest void WebServer::continueConnection(struct mg_connection* mgConnection) { - if(unfinishedConnection.count(mgConnection->sock) == 0) { - return; - } - - HTTPResponse httpResponse = HTTPResponse(mgConnection); - - FILE* file = unfinishedConnection[mgConnection->sock]; - auto pData = (char*) malloc(MAX_CHUNK_LENGTH); - size_t length = fread(pData, 1, MAX_CHUNK_LENGTH, file); - - httpResponse.sendChunk(pData, length); - if(length < MAX_CHUNK_LENGTH) { - fclose(file); - httpResponse.closeConnection(); - unfinishedConnection.erase(mgConnection->sock); - httpResponse.sendChunk("", 0); - } - free(pData); + if (unfinishedConnection.count(mgConnection->sock) == 0) return; + + HTTPResponse httpResponse = HTTPResponse(mgConnection); + + FILE* file = unfinishedConnection[mgConnection->sock]; + auto pData = (char*) malloc(MAX_CHUNK_LENGTH); + size_t length = fread(pData, 1, MAX_CHUNK_LENGTH, file); + + httpResponse.sendChunk(pData, length); + if (length < MAX_CHUNK_LENGTH) { + fclose(file); + httpResponse.closeConnection(); + unfinishedConnection.erase(mgConnection->sock); + httpResponse.sendChunk("", 0); + } + free(pData); } @@ -668,16 +671,16 @@ void WebServer::continueConnection(struct mg_connection* mgConnection) { * @param [in] pathPattern The path pattern to be matched. * @param [in] webServerRequestHandler The request handler to be called. */ -WebServer::PathHandler::PathHandler(const std::string& method, const std::string& pathPattern, void (* webServerRequestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { - m_method = method; - m_pattern = std::regex(pathPattern); - m_requestHandler = webServerRequestHandler; +WebServer::PathHandler::PathHandler(const std::string& method, const std::string& pathPattern, void (*webServerRequestHandler) (WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { + m_method = method; + m_pattern = std::regex(pathPattern); + m_requestHandler = webServerRequestHandler; } // PathHandler -WebServer::PathHandler::PathHandler(std::string&& method, const std::string& pathPattern, void (* webServerRequestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { - m_method = std::move(method); - m_pattern = std::regex(pathPattern); - m_requestHandler = webServerRequestHandler; +WebServer::PathHandler::PathHandler(std::string&& method, const std::string& pathPattern, void (*webServerRequestHandler) (WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) { + m_method = std::move(method); + m_pattern = std::regex(pathPattern); + m_requestHandler = webServerRequestHandler; } // PathHandler @@ -689,13 +692,12 @@ WebServer::PathHandler::PathHandler(std::string&& method, const std::string& pat * @param [in] path The path to be matched. * @return True if the path matches. */ - bool WebServer::PathHandler::match(const char* method, size_t method_len, const char* path) { - //ESP_LOGD(tag, "match: %s with %s", m_pattern.c_str(), path.c_str()); - if (method_len != m_method.length() || strncmp(method, m_method.c_str(), method_len) != 0) { - return false; - } - return std::regex_search(path, m_pattern); + //ESP_LOGD(LOG_TAG, "match: %s with %s", m_pattern.c_str(), path.c_str()); + if (method_len != m_method.length() || strncmp(method, m_method.c_str(), method_len) != 0) { + return false; + } + return std::regex_search(path, m_pattern); } // match @@ -705,8 +707,8 @@ bool WebServer::PathHandler::match(const char* method, size_t method_len, const * @param [in] response An object representing the response. * @return N/A. */ -void WebServer::PathHandler::invoke(WebServer::HTTPRequest* request, WebServer::HTTPResponse *response) { - m_requestHandler(request, response); +void WebServer::PathHandler::invoke(WebServer::HTTPRequest* request, WebServer::HTTPResponse* response) { + m_requestHandler(request, response); } // invoke @@ -717,7 +719,7 @@ void WebServer::PathHandler::invoke(WebServer::HTTPRequest* request, WebServer:: * @param [in] message The description of the underlying Mongoose message. */ WebServer::HTTPRequest::HTTPRequest(struct http_message* message) { - m_message = message; + m_message = message; } // HTTPRequest @@ -729,9 +731,10 @@ WebServer::HTTPRequest::HTTPRequest(struct http_message* message) { * @return The body of the request. */ const char* WebServer::HTTPRequest::getBody() const { - return m_message->body.p; + return m_message->body.p; } // getBody + /** * @brief Get the length of the body of the request. * When an HTTP request is either PUT or POST then it may contain a payload that is also @@ -739,7 +742,7 @@ const char* WebServer::HTTPRequest::getBody() const { * @return The length of the body of the request. */ size_t WebServer::HTTPRequest::getBodyLen() const { - return m_message->body.len; + return m_message->body.len; } // getBodyLen @@ -751,16 +754,17 @@ size_t WebServer::HTTPRequest::getBodyLen() const { * @return The body of the request. */ const char* WebServer::HTTPRequest::getMethod() const { - return m_message->method.p; + return m_message->method.p; } // getMethod + /** * @brief Get the length of the method of the request. * An HTTP request contains a request method which is one of GET, PUT, POST, etc. * @return The length of the method of the request. */ size_t WebServer::HTTPRequest::getMethodLen() const { - return m_message->method.len; + return m_message->method.len; } // getMethodLen @@ -773,9 +777,10 @@ size_t WebServer::HTTPRequest::getMethodLen() const { * @return The path of the request. */ const char* WebServer::HTTPRequest::getPath() const { - return m_message->uri.p; + return m_message->uri.p; } // getPath + /** * @brief Get the path of the request. * The path of an HTTP request is the portion of the URL that follows the hostname/port pair @@ -783,11 +788,10 @@ const char* WebServer::HTTPRequest::getPath() const { * @return The path of the request. */ size_t WebServer::HTTPRequest::getPathLen() const { - return m_message->uri.len; + return m_message->uri.len; } // getPath -#define STATE_NAME 0 -#define STATE_VALUE 1 + /** * @brief Get the query part of the request. * The query is a set of name = value pairs. The return is a map keyed by the name items. @@ -795,48 +799,47 @@ size_t WebServer::HTTPRequest::getPathLen() const { * @return The query part of the request. */ std::map WebServer::HTTPRequest::getQuery() const { - // Walk through all the characters in the query string maintaining a simple state machine - // that lets us know what we are parsing. - std::map queryMap; - const char* queryString = m_message->query_string.p; - size_t queryStringLen = m_message->query_string.len; - int i=0; - - /* - * We maintain a simple state machine with states of: - * * STATE_NAME - We are parsing a name. - * * STATE_VALUE - We are parsing a value. - */ - int state = STATE_NAME; - std::string name = ""; - std::string value; - // Loop through each character in the query string. - for (i=0; i queryMap; + const char* queryString = m_message->query_string.p; + size_t queryStringLen = m_message->query_string.len; + + /* + * We maintain a simple state machine with states of: + * * STATE_NAME - We are parsing a name. + * * STATE_VALUE - We are parsing a value. + */ + int state = STATE_NAME; + std::string name = ""; + std::string value; + // Loop through each character in the query string. + for (size_t i = 0; i < queryStringLen; i++) { + char currentChar = queryString[i]; + if (state == STATE_NAME) { + if (currentChar != '=') { + name += currentChar; + } else { + state = STATE_VALUE; + value = ""; + } + } // End state = STATE_NAME + else { // if (state == STATE_VALUE) + if (currentChar != '&') { + value += currentChar; + } else { + //ESP_LOGD(LOG_TAG, "name=%s, value=%s", name.c_str(), value.c_str()); + queryMap[name] = value; + state = STATE_NAME; + name = ""; + } + } // End state = STATE_VALUE + } // End for loop + if (state == STATE_VALUE) { + //ESP_LOGD(LOG_TAG, "name=%s, value=%s", name.c_str(), value.c_str()); + queryMap[name] = value; + } + return queryMap; } // getQuery @@ -860,17 +863,17 @@ std::map WebServer::HTTPRequest::getQuery() const { * @return A vector of the constituent parts of the path. */ std::vector WebServer::HTTPRequest::pathSplit() const { - std::istringstream stream(std::string(getPath(), getPathLen())); // I don't know if there's a better istringstream constructor for this - std::vector ret; - std::string pathPart; - while(std::getline(stream, pathPart, '/')) { - ret.push_back(pathPart); - } - // Debug - for (int i=0; i ret; + std::string pathPart; + while (std::getline(stream, pathPart, '/')) { + ret.push_back(pathPart); + } + // Debug + for (int i = 0; i < ret.size(); i++) { + ESP_LOGD(LOG_TAG, "part[%d]: %s", i, ret[i].c_str()); + } + return ret; } // pathSplit /** @@ -882,8 +885,8 @@ std::vector WebServer::HTTPRequest::pathSplit() const { * @return N/A. */ void WebServer::HTTPMultiPart::begin(const std::string& varName, const std::string& fileName) { - ESP_LOGD(tag, "WebServer::HTTPMultiPart::begin(varName=\"%s\", fileName=\"%s\")", - varName.c_str(), fileName.c_str()); + ESP_LOGD(LOG_TAG, "WebServer::HTTPMultiPart::begin(varName=\"%s\", fileName=\"%s\")", + varName.c_str(), fileName.c_str()); } // WebServer::HTTPMultiPart::begin @@ -893,7 +896,7 @@ void WebServer::HTTPMultiPart::begin(const std::string& varName, const std::stri * @return N/A. */ void WebServer::HTTPMultiPart::end() { - ESP_LOGD(tag, "WebServer::HTTPMultiPart::end()"); + ESP_LOGD(LOG_TAG, "WebServer::HTTPMultiPart::end()"); } // WebServer::HTTPMultiPart::end @@ -905,7 +908,7 @@ void WebServer::HTTPMultiPart::end() { * @return N/A. */ void WebServer::HTTPMultiPart::data(const std::string& data) { - ESP_LOGD(tag, "WebServer::HTTPMultiPart::data(), length=%d", data.length()); + ESP_LOGD(LOG_TAG, "WebServer::HTTPMultiPart::data(), length=%d", data.length()); } // WebServer::HTTPMultiPart::data @@ -914,7 +917,7 @@ void WebServer::HTTPMultiPart::data(const std::string& data) { * @return N/A. */ void WebServer::HTTPMultiPart::multipartEnd() { - ESP_LOGD(tag, "WebServer::HTTPMultiPart::multipartEnd()"); + ESP_LOGD(LOG_TAG, "WebServer::HTTPMultiPart::multipartEnd()"); } // WebServer::HTTPMultiPart::multipartEnd @@ -923,7 +926,7 @@ void WebServer::HTTPMultiPart::multipartEnd() { * @return N/A. */ void WebServer::HTTPMultiPart::multipartStart() { - ESP_LOGD(tag, "WebServer::HTTPMultiPart::multipartStart()"); + ESP_LOGD(LOG_TAG, "WebServer::HTTPMultiPart::multipartStart()"); } // WebServer::HTTPMultiPart::multipartStart @@ -932,7 +935,6 @@ void WebServer::HTTPMultiPart::multipartStart() { * @return N/A. */ void WebServer::WebSocketHandler::onCreated() { - } // onCreated @@ -942,7 +944,6 @@ void WebServer::WebSocketHandler::onCreated() { * @return N/A. */ void WebServer::WebSocketHandler::onMessage(const std::string& message){ - } // onMessage /** @@ -950,7 +951,6 @@ void WebServer::WebSocketHandler::onMessage(const std::string& message){ * @return N/A */ void WebServer::WebSocketHandler::onClosed() { - } // onClosed @@ -960,12 +960,13 @@ void WebServer::WebSocketHandler::onClosed() { * @return N/A. */ void WebServer::WebSocketHandler::sendData(const std::string& message) { - ESP_LOGD(tag, "WebSocketHandler::sendData(length=%d)", message.length()); - mg_send_websocket_frame(m_mgConnection, - WEBSOCKET_OP_BINARY | WEBSOCKET_OP_CONTINUE, - message.data(), message.length()); + ESP_LOGD(LOG_TAG, "WebSocketHandler::sendData(length=%d)", message.length()); + mg_send_websocket_frame(m_mgConnection, + WEBSOCKET_OP_BINARY | WEBSOCKET_OP_CONTINUE, + message.data(), message.length()); } // sendData + /** * @brief Send data down the WebSocket * @param [in] data The message to send down the socket. @@ -973,9 +974,9 @@ void WebServer::WebSocketHandler::sendData(const std::string& message) { * @return N/A. */ void WebServer::WebSocketHandler::sendData(const uint8_t* data, uint32_t size) { - mg_send_websocket_frame(m_mgConnection, - WEBSOCKET_OP_BINARY | WEBSOCKET_OP_CONTINUE, - data, size); + mg_send_websocket_frame(m_mgConnection, + WEBSOCKET_OP_BINARY | WEBSOCKET_OP_CONTINUE, + data, size); } // sendData @@ -986,9 +987,7 @@ void WebServer::WebSocketHandler::sendData(const uint8_t* data, uint32_t size) { * @return N/A. */ void WebServer::WebSocketHandler::close() { - mg_send_websocket_frame(m_mgConnection, WEBSOCKET_OP_CLOSE, nullptr, 0); + mg_send_websocket_frame(m_mgConnection, WEBSOCKET_OP_CLOSE, nullptr, 0); } // close - - #endif // CONFIG_MONGOOSE_PRESENT diff --git a/cpp_utils/WebServer.h b/cpp_utils/WebServer.h index ae06647b..961b6662 100644 --- a/cpp_utils/WebServer.h +++ b/cpp_utils/WebServer.h @@ -27,183 +27,196 @@ class WebServer; */ class WebServer { public: - /** - * @brief Request wrapper for an HTTP request. - */ - class HTTPRequest { - public: - HTTPRequest(struct http_message* message); - const char* getMethod() const; - const char* getPath() const; - const char* getBody() const; - size_t getMethodLen() const; - size_t getPathLen() const; - size_t getBodyLen() const; - std::map getQuery() const; - std::vector pathSplit() const; - private: - struct http_message* m_message; - }; // HTTPRequest - - /** - * @brief Response wrapper for an HTTP response. - */ - class HTTPResponse { - public: - HTTPResponse(struct mg_connection *nc); - void addHeader(const std::string& name, const std::string& value); - void addHeader(std::string&& name, std::string&& value); - void setStatus(int status); - void setHeaders(const std::map& headers); - void setHeaders(std::map&& headers); - void sendData(const std::string& data); - void sendData(const uint8_t* pData, size_t length); - void sendData(const char* pData, size_t length); - const std::string& getRootPath() const; - void setRootPath(const std::string& path); - void setRootPath(std::string&& path); - void sendChunkHead(); - void sendChunk(const char* pData, size_t length); - void closeConnection(); - private: - struct mg_connection *m_nc; - std::string m_rootPath; - int m_status; - std::map m_headers; - bool m_dataSent; - std::string buildHeaders(); - }; // HTTPResponse - - /** - * @brief Handler for a Multipart. - * - * This class is usually subclassed to provide your own implementation. Typically - * a factory is implemented based on HTTPMultiPartFactory that creates instances. This - * is then registered with the WebServer. When done, when ever the WebServer receives multi - * part requests, this handler for Multipart is called. The call sequence is usually: - * ~~~ - * multipartStart - * begin - * data* - * end - * begin - * data* - * end - * ... - * multipartEnd - * ~~~ - * - * There can be multiple begin, data, data, ..., end groups. - */ - class HTTPMultiPart { - public: - virtual ~HTTPMultiPart() = default; - virtual void begin(const std::string& varName, const std::string& fileName); - virtual void end(); - virtual void data(const std::string& data); - virtual void multipartEnd(); - virtual void multipartStart(); - }; // HTTPMultiPart - - /** - * @brief Factory for creating Multipart instances. - * This class is meant to be implemented to provide a constructor for a custom - * HTTPMultiPart instance. - * @code{.cpp} - * class MyMultiPart : public WebServer::HTTPMultiPart { - * public: - * void begin(std::string varName, std::string fileName) { - * ESP_LOGD(tag, "MyMultiPart begin(): varName=%s, fileName=%s", - * varName.c_str(), fileName.c_str()); - * } - * - * void end() { - * ESP_LOGD(tag, "MyMultiPart end()"); - * } - * - * void data(std::string data) { - * ESP_LOGD(tag, "MyMultiPart data(): length=%d", data.length()); - * } - * - * void multipartEnd() { - * ESP_LOGD(tag, "MyMultiPart multipartEnd()"); - * } - * - * void multipartStart() { - * ESP_LOGD(tag, "MyMultiPart multipartStart()"); - * } - * }; - * - * class MyMultiPartFactory : public WebServer::HTTPMultiPartFactory { - * WebServer::HTTPMultiPart *createNew() { - * return new MyMultiPart(); - * } - * }; - * @endcode - */ - class HTTPMultiPartFactory { - public: - /** - * @brief Create a new HTTPMultiPart instance. - * @return A new HTTPMultiPart instance. - */ - virtual HTTPMultiPart *newInstance() = 0; - }; - - /** - * @brief The handler for path matching. - * - */ - class PathHandler { - public: - PathHandler(const std::string& method, const std::string& pathPattern, void (* webServerRequestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); - PathHandler(std::string&& method, const std::string& pathPattern, void (* webServerRequestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); - bool match(const char* method, size_t method_len, const char* path); - void invoke(HTTPRequest *request, HTTPResponse *response); - private: - std::string m_method; - std::regex m_pattern; - void (*m_requestHandler)(WebServer::HTTPRequest *pHttpRequest, WebServer::HTTPResponse *pHttpResponse); - }; // PathHandler - - /** - * @brief A WebSocket handler for handling WebSockets. - */ - class WebSocketHandler { - public: - void onCreated(); - virtual void onMessage(const std::string& message); - void onClosed(); - void sendData(const std::string& message); - void sendData(const uint8_t* data, uint32_t size); - void close(); - private: - struct mg_connection *m_mgConnection; - }; - - class WebSocketHandlerFactory { - public: - virtual WebSocketHandler *newInstance() = 0; - }; - - WebServer(); - virtual ~WebServer(); - void addPathHandler(const std::string& method, const std::string& pathExpr, void (* webServerRequestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); - void addPathHandler(std::string&& method, const std::string& pathExpr, void (* webServerRequestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); - const std::string& getRootPath(); - void setMultiPartFactory(HTTPMultiPartFactory *pMultiPartFactory); - void setRootPath(const std::string& path); - void setRootPath(std::string&& path); - void setWebSocketHandlerFactory(WebSocketHandlerFactory *pWebSocketHandlerFactory); - void start(unsigned short port = 80); - void processRequest(struct mg_connection *mgConnection, struct http_message *message); - void continueConnection(struct mg_connection* mgConnection); - HTTPMultiPartFactory *m_pMultiPartFactory; - WebSocketHandlerFactory *m_pWebSocketHandlerFactory; + /** + * @brief Request wrapper for an HTTP request. + */ + class HTTPRequest { + public: + HTTPRequest(struct http_message* message); + const char* getMethod() const; + const char* getPath() const; + const char* getBody() const; + size_t getMethodLen() const; + size_t getPathLen() const; + size_t getBodyLen() const; + std::map getQuery() const; + std::vector pathSplit() const; + + private: + struct http_message* m_message; + + }; // HTTPRequest + + /** + * @brief Response wrapper for an HTTP response. + */ + class HTTPResponse { + public: + HTTPResponse(struct mg_connection* nc); + void addHeader(const std::string& name, const std::string& value); + void addHeader(std::string&& name, std::string&& value); + void setStatus(int status); + void setHeaders(const std::map& headers); + void setHeaders(std::map&& headers); + void sendData(const std::string& data); + void sendData(const uint8_t* pData, size_t length); + void sendData(const char* pData, size_t length); + const std::string& getRootPath() const; + void setRootPath(const std::string& path); + void setRootPath(std::string&& path); + void sendChunkHead(); + void sendChunk(const char* pData, size_t length); + void closeConnection(); + + private: + struct mg_connection* m_nc; + std::string m_rootPath; + int m_status; + std::map m_headers; + bool m_dataSent; + std::string buildHeaders(); + + }; // HTTPResponse + + /** + * @brief Handler for a Multipart. + * + * This class is usually subclassed to provide your own implementation. Typically + * a factory is implemented based on HTTPMultiPartFactory that creates instances. This + * is then registered with the WebServer. When done, when ever the WebServer receives multi + * part requests, this handler for Multipart is called. The call sequence is usually: + * ~~~ + * multipartStart + * begin + * data* + * end + * begin + * data* + * end + * ... + * multipartEnd + * ~~~ + * + * There can be multiple begin, data, data, ..., end groups. + */ + class HTTPMultiPart { + public: + virtual ~HTTPMultiPart() = default; + virtual void begin(const std::string& varName, const std::string& fileName); + virtual void end(); + virtual void data(const std::string& data); + virtual void multipartEnd(); + virtual void multipartStart(); + + }; // HTTPMultiPart + + /** + * @brief Factory for creating Multipart instances. + * This class is meant to be implemented to provide a constructor for a custom + * HTTPMultiPart instance. + * @code{.cpp} + * class MyMultiPart : public WebServer::HTTPMultiPart { + * public: + * void begin(std::string varName, std::string fileName) { + * ESP_LOGD(tag, "MyMultiPart begin(): varName=%s, fileName=%s", + * varName.c_str(), fileName.c_str()); + * } + * + * void end() { + * ESP_LOGD(tag, "MyMultiPart end()"); + * } + * + * void data(std::string data) { + * ESP_LOGD(tag, "MyMultiPart data(): length=%d", data.length()); + * } + * + * void multipartEnd() { + * ESP_LOGD(tag, "MyMultiPart multipartEnd()"); + * } + * + * void multipartStart() { + * ESP_LOGD(tag, "MyMultiPart multipartStart()"); + * } + * }; + * + * class MyMultiPartFactory : public WebServer::HTTPMultiPartFactory { + * WebServer::HTTPMultiPart *createNew() { + * return new MyMultiPart(); + * } + * }; + * @endcode + */ + class HTTPMultiPartFactory { + public: + /** + * @brief Create a new HTTPMultiPart instance. + * @return A new HTTPMultiPart instance. + */ + virtual HTTPMultiPart* newInstance() = 0; + + }; + + /** + * @brief The handler for path matching. + * + */ + class PathHandler { + public: + PathHandler(const std::string& method, const std::string& pathPattern, void (*webServerRequestHandler) (WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); + PathHandler(std::string&& method, const std::string& pathPattern, void (*webServerRequestHandler) (WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); + bool match(const char* method, size_t method_len, const char* path); + void invoke(HTTPRequest* request, HTTPResponse* response); + + private: + std::string m_method; + std::regex m_pattern; + void (*m_requestHandler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse); + + }; // PathHandler + + /** + * @brief A WebSocket handler for handling WebSockets. + */ + class WebSocketHandler { + public: + void onCreated(); + virtual void onMessage(const std::string& message); + void onClosed(); + void sendData(const std::string& message); + void sendData(const uint8_t* data, uint32_t size); + void close(); + + private: + struct mg_connection* m_mgConnection; + + }; + + class WebSocketHandlerFactory { + public: + virtual WebSocketHandler* newInstance() = 0; + + }; + + WebServer(); + virtual ~WebServer(); + void addPathHandler(const std::string& method, const std::string& pathExpr, void (*webServerRequestHandler) (WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); + void addPathHandler(std::string&& method, const std::string& pathExpr, void (*webServerRequestHandler) (WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)); + const std::string& getRootPath(); + void setMultiPartFactory(HTTPMultiPartFactory* pMultiPartFactory); + void setRootPath(const std::string& path); + void setRootPath(std::string&& path); + void setWebSocketHandlerFactory(WebSocketHandlerFactory* pWebSocketHandlerFactory); + void start(unsigned short port = 80); + void processRequest(struct mg_connection* mgConnection, struct http_message* message); + void continueConnection(struct mg_connection* mgConnection); + HTTPMultiPartFactory* m_pMultiPartFactory; + WebSocketHandlerFactory* m_pWebSocketHandlerFactory; + private: - std::string m_rootPath; - std::vector m_pathHandlers; - std::map unfinishedConnection; + std::string m_rootPath; + std::vector m_pathHandlers; + std::map unfinishedConnection; + }; #endif // CONFIG_MONGOOSE_PRESENT diff --git a/cpp_utils/WebSocket.cpp b/cpp_utils/WebSocket.cpp index e7fc05fb..6930f3b6 100644 --- a/cpp_utils/WebSocket.cpp +++ b/cpp_utils/WebSocket.cpp @@ -21,12 +21,12 @@ extern "C" { static const char* LOG_TAG = "WebSocket"; // WebSocket op codes as found in a WebSocket frame. -static const int OPCODE_CONTINUE = 0x00; -static const int OPCODE_TEXT = 0x01; -static const int OPCODE_BINARY = 0x02; -static const int OPCODE_CLOSE = 0x08; -static const int OPCODE_PING = 0x09; -static const int OPCODE_PONG = 0x0a; +static const uint8_t OPCODE_CONTINUE = 0x00; +static const uint8_t OPCODE_TEXT = 0x01; +static const uint8_t OPCODE_BINARY = 0x02; +static const uint8_t OPCODE_CLOSE = 0x08; +static const uint8_t OPCODE_PING = 0x09; +static const uint8_t OPCODE_PONG = 0x0a; // Structure definition for the WebSocket frame. @@ -50,8 +50,8 @@ struct Frame { */ static void dumpFrame(Frame frame) { std::ostringstream oss; - oss << "Fin: " << (int)frame.fin << ", OpCode: " << (int)frame.opCode; - switch(frame.opCode) { + oss << "Fin: " << (int) frame.fin << ", OpCode: " << (int) frame.opCode; + switch (frame.opCode) { case OPCODE_BINARY: { oss << " BINARY"; break; @@ -81,7 +81,7 @@ static void dumpFrame(Frame frame) { break; } } - oss << ", Mask: " << (int)frame.mask << ", len: " << (int)frame.len; + oss << ", Mask: " << (int) frame.mask << ", len: " << (int) frame.len; ESP_LOGD(LOG_TAG, "WebSocket frame: %s", oss.str().c_str()); } // dumpFrame @@ -101,6 +101,7 @@ class WebSocketReader: public Task { void end() { m_end = true; } + private: bool m_end; /** @@ -114,14 +115,12 @@ class WebSocketReader: public Task { Socket peerSocket = pWebSocket->getSocket(); Frame frame; - while(1) { - if (m_end) { - break; - } + while (true) { + if (m_end) break; ESP_LOGD("WebSocketReader", "Waiting on socket data for socket %s", peerSocket.toString().c_str()); - int length = peerSocket.receive((uint8_t*)&frame, sizeof(frame), true); // Read exact + int length = peerSocket.receive((uint8_t*) &frame, sizeof(frame), true); // Read exact if (length != sizeof(frame)) { - ESP_LOGD(LOG_TAG, "Socket read error"); + ESP_LOGD("WebSocketReader", "Socket read error"); pWebSocket->close(); return; } @@ -135,12 +134,12 @@ class WebSocketReader: public Task { payloadLen = frame.len; } else if (frame.len == 126) { uint16_t tempLen; - peerSocket.receive((uint8_t*)&tempLen, sizeof(tempLen), true); + peerSocket.receive((uint8_t*) &tempLen, sizeof(tempLen), true); payloadLen = ntohs(tempLen); } else if (frame.len == 127) { uint64_t tempLen; - peerSocket.receive((uint8_t*)&tempLen, sizeof(tempLen), true); - payloadLen = ntohl((uint32_t)tempLen); + peerSocket.receive((uint8_t*) &tempLen, sizeof(tempLen), true); + payloadLen = ntohl((uint32_t) tempLen); } if (frame.mask == 1) { peerSocket.receive(mask, sizeof(mask), true); @@ -152,12 +151,12 @@ class WebSocketReader: public Task { ESP_LOGD("WebSocketReader", "Web socket payload, length=%d:", payloadLen); } - WebSocketHandler *pWebSocketHandler = pWebSocket->getHandler(); - switch(frame.opCode) { + WebSocketHandler* pWebSocketHandler = pWebSocket->getHandler(); + switch (frame.opCode) { case OPCODE_TEXT: case OPCODE_BINARY: { if (pWebSocketHandler != nullptr) { - WebSocketInputStreambuf streambuf(pWebSocket->getSocket(), payloadLen, frame.mask==1?mask:nullptr); + WebSocketInputStreambuf streambuf(pWebSocket->getSocket(), payloadLen, (frame.mask == 1) ? mask : nullptr); pWebSocketHandler->onMessage(&streambuf, pWebSocket); //streambuf.discard(); } @@ -187,12 +186,12 @@ class WebSocketReader: public Task { } default: { - ESP_LOGD("WebSocketReader", "Unknown opcode: %d", frame.opCode); + ESP_LOGD("WebSocketReader", "Unknown opcode: %d", frame.opCode); break; } } // Switch opCode - } // While (1) + } // while (true) ESP_LOGD("WebSocketReader", "<< run"); } // run }; // WebSocketReader @@ -218,7 +217,7 @@ void WebSocketHandler::onClose() { * ``` * This will read the whole message into the string stream. */ -void WebSocketHandler::onMessage(WebSocketInputStreambuf* pWebSocketInputStreambuf, WebSocket *pWebSocket) { +void WebSocketHandler::onMessage(WebSocketInputStreambuf* pWebSocketInputStreambuf, WebSocket* pWebSocket) { ESP_LOGD("WebSocketHandler", ">> onMessage"); ESP_LOGD("WebSocketHandler", "<< onMessage"); } // onData @@ -279,7 +278,7 @@ void WebSocket::close(uint16_t status, std::string message) { frame.opCode = OPCODE_CLOSE; frame.mask = 0; frame.len = message.length() + 2; - int rc = m_socket.send((uint8_t *)&frame, sizeof(frame)); + int rc = m_socket.send((uint8_t*) &frame, sizeof(frame)); if (rc > 0) { rc = m_socket.send(status); @@ -329,15 +328,15 @@ void WebSocket::send(std::string data, uint8_t sendType) { frame.rsv1 = 0; frame.rsv2 = 0; frame.rsv3 = 0; - frame.opCode = sendType==SEND_TYPE_TEXT?OPCODE_TEXT:OPCODE_BINARY; + frame.opCode = (sendType == SEND_TYPE_TEXT) ? OPCODE_TEXT : OPCODE_BINARY; frame.mask = 0; if (data.length() < 126) { frame.len = data.length(); - m_socket.send((uint8_t *)&frame, sizeof(frame)); + m_socket.send((uint8_t*) &frame, sizeof(frame)); } else { frame.len = 126; - m_socket.send((uint8_t *)&frame, sizeof(frame)); - m_socket.send(htons((uint16_t)data.length())); // Convert to network byte order from host byte order + m_socket.send((uint8_t*) &frame, sizeof(frame)); + m_socket.send(htons((uint16_t) data.length())); // Convert to network byte order from host byte order } m_socket.send((uint8_t*)data.data(), data.length()); ESP_LOGD(LOG_TAG, "<< send"); @@ -358,14 +357,14 @@ void WebSocket::send(uint8_t* data, uint16_t length, uint8_t sendType) { frame.rsv1 = 0; frame.rsv2 = 0; frame.rsv3 = 0; - frame.opCode = sendType==SEND_TYPE_TEXT?OPCODE_TEXT:OPCODE_BINARY; + frame.opCode = (sendType==SEND_TYPE_TEXT) ? OPCODE_TEXT : OPCODE_BINARY; frame.mask = 0; if (length < 126) { frame.len = length; - m_socket.send((uint8_t *)&frame, sizeof(frame)); + m_socket.send((uint8_t*) &frame, sizeof(frame)); } else { frame.len = 126; - m_socket.send((uint8_t *)&frame, sizeof(frame)); + m_socket.send((uint8_t*) &frame, sizeof(frame)); m_socket.send(htons(length)); // Convert to network byte order from host byte order } m_socket.send(data, length); @@ -405,7 +404,7 @@ void WebSocket::startReader() { WebSocketInputStreambuf::WebSocketInputStreambuf( Socket socket, size_t dataLength, - uint8_t *pMask, + uint8_t* pMask, size_t bufferSize) { m_socket = socket; // The socket we will be reading from m_dataLength = dataLength; // The size of the record we wish to read. @@ -476,7 +475,7 @@ WebSocketInputStreambuf::int_type WebSocketInputStreambuf::underflow() { // We wish to refill the buffer. We want to read data from the socket. We want to read either // the size of the buffer to fill it or the maximum number of bytes remaining to be read. // We will choose which ever is smaller as the number of bytes to read into the buffer. - int remainingBytes = getRecordSize()-m_sizeRead; + size_t remainingBytes = getRecordSize() - m_sizeRead; size_t sizeToRead; if (remainingBytes < m_bufferSize) { sizeToRead = remainingBytes; @@ -485,7 +484,7 @@ WebSocketInputStreambuf::int_type WebSocketInputStreambuf::underflow() { } ESP_LOGD("WebSocketInputRecordStreambuf", "- getting next buffer of data; size request: %d", sizeToRead); - int bytesRead = m_socket.receive((uint8_t*)m_buffer, sizeToRead, true); + size_t bytesRead = m_socket.receive((uint8_t*) m_buffer, sizeToRead, true); if (bytesRead == 0) { ESP_LOGD("WebSocketInputRecordStreambuf", "<< underflow: Read 0 bytes"); return EOF; @@ -493,8 +492,8 @@ WebSocketInputStreambuf::int_type WebSocketInputStreambuf::underflow() { // If the WebSocket frame shows that we have a mask bit set then we have to unmask the data. if (m_pMask != nullptr) { - for (int i=0; i> onMessage"); // Test to see if we are currently active. If not, this is the start of a transfer. if (!m_active) { - ESP_LOGD("FileTransferWebSocketHandler", "Not yet active!"); // Read a chunk of data into memory. std::stringstream buffer; @@ -82,7 +71,7 @@ class FileTransferWebSocketHandler : public WebSocketHandler { // "length": // Length of file. Optional. // } JsonObject jo = JSON::parseObject(buffer.str()); - m_fileName = jo.getString("name"); + m_fileName = jo.getString("name"); assert(m_fileName.length() > 0); // Doesn't make any sense to receive a zero length file name. if (jo.hasItem("length")) { m_fileLength = jo.getInt("length"); @@ -91,9 +80,9 @@ class FileTransferWebSocketHandler : public WebSocketHandler { ESP_LOGD("FileTransferWebSocketHandler", "Target file is %s", fileName.c_str()); // If the file to create ends in a "/" then we are being asked to create a directory. - if (m_fileName.substr(m_fileName.size()-1)=="/") { + if (m_fileName.substr(m_fileName.size() - 1) == "/") { ESP_LOGD("FileTransferWebSocketHandler", "Is a directory!!"); - fileName = fileName.substr(0, fileName.size()-1); // Remove the trailing slash + fileName = fileName.substr(0, fileName.size() - 1); // Remove the trailing slash struct stat statbuf; if (stat(fileName.c_str(), &statbuf) == 0) { if (S_ISREG(statbuf.st_mode)) { @@ -114,7 +103,7 @@ class FileTransferWebSocketHandler : public WebSocketHandler { return; } } - m_active = true; + m_active = true; ESP_LOGD("FileTransferWebSocketHandler", "Filename: %s, length: %d", fileName.c_str(), m_fileLength); } // !active --- Not active else { @@ -133,7 +122,6 @@ class FileTransferWebSocketHandler : public WebSocketHandler { } } // onMessage - /** * @brief Handle a close event on the web socket. */ @@ -146,8 +134,17 @@ class FileTransferWebSocketHandler : public WebSocketHandler { if (m_ofStream.is_open()) { m_ofStream.close(); // Close the file now that we have finished writing to it. } - delete this; // Delete ourself. + delete this; // Delete ourselves. } // onClose + +private: + std::string m_fileName; // The name of the file we are receiving. + uint32_t m_fileLength; // We may optionally receive a file length. + uint32_t m_sizeReceived; // The size of the data actually received so far. + bool m_active; // Are we actively processing a file. + std::ofstream m_ofStream; // The file stream we are writing to when active. + std::string m_rootPath; // The root path for file names. + }; // FileTransferWebSocketHandler } // End un-named namespace diff --git a/cpp_utils/WebSocketFileTransfer.h b/cpp_utils/WebSocketFileTransfer.h index 98cbda9b..6eb8de43 100644 --- a/cpp_utils/WebSocketFileTransfer.h +++ b/cpp_utils/WebSocketFileTransfer.h @@ -17,7 +17,7 @@ class WebSocketFileTransfer { public: WebSocketFileTransfer(std::string rootPath); - void start(WebSocket *pWebSocket); + void start(WebSocket* pWebSocket); }; #endif /* COMPONENTS_CPP_UTILS_WEBSOCKETFILETRANSFER_H_ */ diff --git a/cpp_utils/WiFi.cpp b/cpp_utils/WiFi.cpp index 503e9235..3c6d4112 100644 --- a/cpp_utils/WiFi.cpp +++ b/cpp_utils/WiFi.cpp @@ -47,10 +47,10 @@ static void setDNSServer(char *ip) { * @brief Creates and uses a default event handler */ WiFi::WiFi() - : ip(0) - , gw(0) - , netmask(0) - , m_pWifiEventHandler(nullptr) + : ip(0) + , gw(0) + , netmask(0) + , m_pWifiEventHandler(nullptr) { m_eventLoopStarted = false; m_initCalled = false; @@ -94,14 +94,14 @@ void WiFi::addDNSServer(const std::string& ip) { void WiFi::addDNSServer(const char* ip) { ip_addr_t dns_server; - if(inet_pton(AF_INET, ip, &dns_server)) { + if (inet_pton(AF_INET, ip, &dns_server)) { addDNSServer(ip); } } // addDNSServer void WiFi::addDNSServer(ip_addr_t ip) { - ESP_LOGD(LOG_TAG, "Setting DNS[%d] to %d.%d.%d.%d", m_dnsCount, ((uint8_t*)(&ip))[0], ((uint8_t*)(&ip))[1], ((uint8_t*)(&ip))[2], ((uint8_t*)(&ip))[3]); + ESP_LOGD(LOG_TAG, "Setting DNS[%d] to %d.%d.%d.%d", m_dnsCount, ((uint8_t*) (&ip))[0], ((uint8_t*) (&ip))[1], ((uint8_t*) (&ip))[2], ((uint8_t*) (&ip))[3]); init(); ::dns_setserver(m_dnsCount, &ip); m_dnsCount++; @@ -132,14 +132,14 @@ void WiFi::setDNSServer(int numdns, const std::string& ip) { void WiFi::setDNSServer(int numdns, const char* ip) { ip_addr_t dns_server; - if(inet_pton(AF_INET, ip, &dns_server)) { + if (inet_pton(AF_INET, ip, &dns_server)) { setDNSServer(numdns, dns_server); } } // setDNSServer void WiFi::setDNSServer(int numdns, ip_addr_t ip) { - ESP_LOGD(LOG_TAG, "Setting DNS[%d] to %d.%d.%d.%d", m_dnsCount, ((uint8_t*)(&ip))[0], ((uint8_t*)(&ip))[1], ((uint8_t*)(&ip))[2], ((uint8_t*)(&ip))[3]); + ESP_LOGD(LOG_TAG, "Setting DNS[%d] to %d.%d.%d.%d", m_dnsCount, ((uint8_t*) (&ip))[0], ((uint8_t*) (&ip))[1], ((uint8_t*) (&ip))[2], ((uint8_t*) (&ip))[3]); init(); ::dns_setserver(numdns, &ip); } // setDNSServer @@ -153,26 +153,27 @@ void WiFi::setDNSServer(int numdns, ip_addr_t ip) { * @param [in] ssid The network SSID of the access point to which we wish to connect. * @param [in] password The password of the access point to which we wish to connect. * @param [in] waitForConnection Block until the connection has an outcome. - * @returns ESP_OK if successfully receives a SYSTEM_EVENT_STA_GOT_IP event. Otherwise returns wifi_err_reason_t - use GeneralUtils::wifiErrorToString(uint8_t errCode) to print the error. + * @param [in] mode WIFI_MODE_AP for normal or WIFI_MODE_APSTA if you want to keep an Access Point running while you connect + * @return ESP_OK if we are now connected and wifi_err_reason_t if not. */ -uint8_t WiFi::connectAP(const std::string& ssid, const std::string& password, bool waitForConnection){ +uint8_t WiFi::connectAP(const std::string& ssid, const std::string& password, bool waitForConnection, wifi_mode_t mode){ ESP_LOGD(LOG_TAG, ">> connectAP"); m_apConnectionStatus = UINT8_MAX; init(); if (ip != 0 && gw != 0 && netmask != 0) { - ::tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); // Don't run a DHCP client + ::tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); // Don't run a DHCP client - tcpip_adapter_ip_info_t ipInfo; - ipInfo.ip.addr = ip; - ipInfo.gw.addr = gw; - ipInfo.netmask.addr = netmask; + tcpip_adapter_ip_info_t ipInfo; + ipInfo.ip.addr = ip; + ipInfo.gw.addr = gw; + ipInfo.netmask.addr = netmask; - ::tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo); + ::tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo); } - esp_err_t errRc = ::esp_wifi_set_mode(WIFI_MODE_STA); + esp_err_t errRc = ::esp_wifi_set_mode(mode); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_wifi_set_mode: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); abort(); @@ -194,23 +195,22 @@ uint8_t WiFi::connectAP(const std::string& ssid, const std::string& password, bo } m_connectFinished.take("connectAP"); // Take the semaphore to wait for a connection. - do { - ESP_LOGD(LOG_TAG, "esp_wifi_connect"); - errRc = ::esp_wifi_connect(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_wifi_connect: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - abort(); - } - } - while (!m_connectFinished.take(5000, "connectAP")); // retry if not connected within 5s - m_connectFinished.give(); + do { + ESP_LOGD(LOG_TAG, "esp_wifi_connect"); + errRc = ::esp_wifi_connect(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_wifi_connect: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + abort(); + } + } + while (!m_connectFinished.take(5000, "connectAP")); // retry if not connected within 5s + m_connectFinished.give(); ESP_LOGD(LOG_TAG, "<< connectAP"); return m_apConnectionStatus; // Return ESP_OK if we are now connected and wifi_err_reason_t if not. } // connectAP - /** * @brief Dump diagnostics to the log. */ @@ -232,7 +232,6 @@ bool WiFi::isConnectedToAP() { } // isConnected - /** * @brief Primary event handler interface. */ @@ -242,7 +241,7 @@ bool WiFi::isConnectedToAP() { // processing. We can then retrieve the specific/custom event handler from within it and invoke that. This then makes this // an indirection vector to the real caller. - WiFi *pWiFi = (WiFi *)ctx; // retrieve the WiFi object from the passed in context. + WiFi* pWiFi = (WiFi*) ctx; // retrieve the WiFi object from the passed in context. // Invoke the event handler. esp_err_t rc; @@ -255,7 +254,6 @@ bool WiFi::isConnectedToAP() { // If the event we received indicates that we now have an IP address or that a connection was disconnected then unlock the mutex that // indicates we are waiting for a connection complete. if (event->event_id == SYSTEM_EVENT_STA_GOT_IP || event->event_id == SYSTEM_EVENT_STA_DISCONNECTED) { - if (event->event_id == SYSTEM_EVENT_STA_GOT_IP) { // If we connected and have an IP, change the status to ESP_OK. Otherwise, change it to the reason code. pWiFi->m_apConnectionStatus = ESP_OK; } else { @@ -302,14 +300,15 @@ std::string WiFi::getApSSID() { wifi_config_t conf; //init(); esp_wifi_get_config(WIFI_IF_AP, &conf); - return std::string((char *)conf.sta.ssid); + return std::string((char*) conf.sta.ssid); } // getApSSID + /** * @brief Get the current ESP32 IP form AP. * @return The ESP32 IP. */ -std::string WiFi::getApIp(){ +std::string WiFi::getApIp() { tcpip_adapter_ip_info_t ipInfo = getApIpInfo(); char ipAddrStr[30]; inet_ntop(AF_INET, &ipInfo.ip.addr, ipAddrStr, sizeof(ipAddrStr)); @@ -320,7 +319,7 @@ std::string WiFi::getApIp(){ * @brief Get the current AP netmask. * @return The Netmask IP. */ -std::string WiFi::getApNetmask(){ +std::string WiFi::getApNetmask() { tcpip_adapter_ip_info_t ipInfo = getApIpInfo(); char ipAddrStr[30]; inet_ntop(AF_INET, &ipInfo.netmask.addr, ipAddrStr, sizeof(ipAddrStr)); @@ -331,7 +330,7 @@ std::string WiFi::getApNetmask(){ * @brief Get the current AP Gateway IP. * @return The Gateway IP. */ -std::string WiFi::getApGateway(){ +std::string WiFi::getApGateway() { tcpip_adapter_ip_info_t ipInfo = getApIpInfo(); char ipAddrStr[30]; inet_ntop(AF_INET, &ipInfo.gw.addr, ipAddrStr, sizeof(ipAddrStr)); @@ -352,13 +351,13 @@ struct in_addr WiFi::getHostByName(const std::string& hostName) { struct in_addr WiFi::getHostByName(const char* hostName) { struct in_addr retAddr; - struct hostent *he = gethostbyname(hostName); + struct hostent* he = gethostbyname(hostName); if (he == nullptr) { retAddr.s_addr = 0; ESP_LOGD(LOG_TAG, "Unable to resolve %s - %d", hostName, h_errno); } else { - retAddr = *(struct in_addr *)(he->h_addr_list[0]); - ESP_LOGD(LOG_TAG, "resolved %s to %.8x", hostName, *(uint32_t *)&retAddr); + retAddr = *(struct in_addr*) (he->h_addr_list[0]); + ESP_LOGD(LOG_TAG, "resolved %s to %.8x", hostName, *(uint32_t*) &retAddr); } return retAddr; } // getHostByName @@ -371,7 +370,7 @@ struct in_addr WiFi::getHostByName(const char* hostName) { std::string WiFi::getMode() { wifi_mode_t mode; esp_wifi_get_mode(&mode); - switch(mode) { + switch (mode) { case WIFI_MODE_NULL: return "WIFI_MODE_NULL"; case WIFI_MODE_STA: @@ -396,11 +395,12 @@ tcpip_adapter_ip_info_t WiFi::getStaIpInfo() { return ipInfo; } // getStaIpInfo + /** * @brief Get the current ESP32 IP form STA. * @return The ESP32 IP. */ -std::string WiFi::getStaIp(){ +std::string WiFi::getStaIp() { tcpip_adapter_ip_info_t ipInfo = getStaIpInfo(); char ipAddrStr[30]; inet_ntop(AF_INET, &ipInfo.ip.addr, ipAddrStr, sizeof(ipAddrStr)); @@ -412,7 +412,7 @@ std::string WiFi::getStaIp(){ * @brief Get the current STA netmask. * @return The Netmask IP. */ -std::string WiFi::getStaNetmask(){ +std::string WiFi::getStaNetmask() { tcpip_adapter_ip_info_t ipInfo = getStaIpInfo(); char ipAddrStr[30]; inet_ntop(AF_INET, &ipInfo.netmask.addr, ipAddrStr, sizeof(ipAddrStr)); @@ -424,13 +424,14 @@ std::string WiFi::getStaNetmask(){ * @brief Get the current STA Gateway IP. * @return The Gateway IP. */ -std::string WiFi::getStaGateway(){ +std::string WiFi::getStaGateway() { tcpip_adapter_ip_info_t ipInfo = getStaIpInfo(); char ipAddrStr[30]; inet_ntop(AF_INET, &ipInfo.gw.addr, ipAddrStr, sizeof(ipAddrStr)); return std::string(ipAddrStr); } // getStaGateway + /** * @brief Get the MAC address of the STA interface. * @return The MAC address of the STA interface. @@ -451,7 +452,7 @@ std::string WiFi::getStaMac() { std::string WiFi::getStaSSID() { wifi_config_t conf; esp_wifi_get_config(WIFI_IF_STA, &conf); - return std::string((char *)conf.ap.ssid); + return std::string((char*) conf.ap.ssid); } // getStaSSID @@ -459,7 +460,6 @@ std::string WiFi::getStaSSID() { * @brief Initialize WiFi. */ /* PRIVATE */ void WiFi::init() { - // If we have already started the event loop, then change the handler otherwise // start the event loop. if (m_eventLoopStarted) { @@ -529,15 +529,20 @@ std::vector WiFi::scan() { esp_err_t rc = ::esp_wifi_scan_start(&conf, true); if (rc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_wifi_scan_start: %d", rc); - return apRecords; + ESP_LOGE(LOG_TAG, "esp_wifi_scan_start: %d", rc); + return apRecords; } uint16_t apCount; // Number of access points available. rc = ::esp_wifi_scan_get_ap_num(&apCount); - ESP_LOGD(LOG_TAG, "Count of found access points: %d", apCount); + if (rc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_wifi_scan_get_ap_num: %d", rc); + return apRecords; + } else { + ESP_LOGD(LOG_TAG, "Count of found access points: %d", apCount); + } - wifi_ap_record_t* list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount); + wifi_ap_record_t* list = (wifi_ap_record_t*) malloc(sizeof(wifi_ap_record_t) * apCount); if (list == nullptr) { ESP_LOGE(LOG_TAG, "Failed to allocate memory"); return apRecords; @@ -549,18 +554,18 @@ std::vector WiFi::scan() { abort(); } - for (auto i=0; i rhs.m_rssi;}); + [](const WiFiAPRecord& lhs, const WiFiAPRecord& rhs){ return lhs.m_rssi > rhs.m_rssi; }); return apRecords; } // scan @@ -583,6 +588,7 @@ void WiFi::startAP(const std::string& ssid, const std::string& password, wifi_au startAP(ssid, password, auth, 0, false, 4); } // startAP + /** * @brief Start being an access point. * @@ -648,9 +654,9 @@ void WiFi::startAP(const std::string& ssid, const std::string& password, wifi_au * @param[in] wifiEventHandler The class that will be used to process events. */ void WiFi::setWifiEventHandler(WiFiEventHandler* wifiEventHandler) { - ESP_LOGD(LOG_TAG, ">> setWifiEventHandler: 0x%d", (uint32_t)wifiEventHandler); - this->m_pWifiEventHandler = wifiEventHandler; - ESP_LOGD(LOG_TAG, "<< setWifiEventHandler"); + ESP_LOGD(LOG_TAG, ">> setWifiEventHandler: 0x%d", (uint32_t) wifiEventHandler); + this->m_pWifiEventHandler = wifiEventHandler; + ESP_LOGD(LOG_TAG, "<< setWifiEventHandler"); } // setWifiEventHandler @@ -676,19 +682,16 @@ void WiFi::setIPInfo(const std::string& ip, const std::string& gw, const std::st } // setIPInfo - void WiFi::setIPInfo(const char* ip, const char* gw, const char* netmask) { uint32_t new_ip; uint32_t new_gw; uint32_t new_netmask; - auto success = (bool)inet_pton(AF_INET, ip, &new_ip); + auto success = (bool) inet_pton(AF_INET, ip, &new_ip); success = success && inet_pton(AF_INET, gw, &new_gw); success = success && inet_pton(AF_INET, netmask, &new_netmask); - if(!success) { - return; - } + if (!success) return; setIPInfo(new_ip, new_gw, new_netmask); } // setIPInfo @@ -707,7 +710,7 @@ void WiFi::setIPInfo(uint32_t ip, uint32_t gw, uint32_t netmask) { this->gw = gw; this->netmask = netmask; - if(ip != 0 && gw != 0 && netmask != 0) { + if (ip != 0 && gw != 0 && netmask != 0) { tcpip_adapter_ip_info_t ipInfo; ipInfo.ip.addr = ip; ipInfo.gw.addr = gw; @@ -728,7 +731,7 @@ void WiFi::setIPInfo(uint32_t ip, uint32_t gw, uint32_t netmask) { */ std::string WiFiAPRecord::toString() { std::string auth; - switch(getAuthMode()) { + switch (getAuthMode()) { case WIFI_AUTH_OPEN: auth = "WIFI_AUTH_OPEN"; break; @@ -744,17 +747,18 @@ std::string WiFiAPRecord::toString() { case WIFI_AUTH_WPA_WPA2_PSK: auth = "WIFI_AUTH_WPA_WPA2_PSK"; break; - default: - auth = ""; - break; - } -// std::stringstream s; -// s<< "ssid: " << m_ssid << ", auth: " << auth << ", rssi: " << m_rssi; - auto info_str = (char*) malloc(6 + 32 + 8 + 22 + 8 + 3 + 1); - sprintf(info_str, "ssid: %s, auth: %s, rssi: %d", m_ssid.c_str(), auth.c_str(), (int) m_rssi); - return std::string(std::move(info_str)); + default: + auth = ""; + break; + } +// std::stringstream s; +// s<< "ssid: " << m_ssid << ", auth: " << auth << ", rssi: " << m_rssi; + auto info_str = (char*) malloc(6 + 32 + 8 + 22 + 8 + 3 + 1); + sprintf(info_str, "ssid: %s, auth: %s, rssi: %d", m_ssid.c_str(), auth.c_str(), (int) m_rssi); + return std::string(std::move(info_str)); } // toString + /* MDNS::MDNS() { esp_err_t errRc = ::mdns_init(TCPIP_ADAPTER_IF_STA, &m_mdns_server); @@ -764,6 +768,7 @@ MDNS::MDNS() { } } + MDNS::~MDNS() { if (m_mdns_server != nullptr) { mdns_free(m_mdns_server); @@ -772,6 +777,7 @@ MDNS::~MDNS() { } */ + /** * @brief Define the service for mDNS. * @@ -782,25 +788,26 @@ MDNS::~MDNS() { */ /* void MDNS::serviceAdd(const std::string& service, const std::string& proto, uint16_t port) { - serviceAdd(service.c_str(), proto.c_str(), port); + serviceAdd(service.c_str(), proto.c_str(), port); } // serviceAdd void MDNS::serviceInstanceSet(const std::string& service, const std::string& proto, const std::string& instance) { - serviceInstanceSet(service.c_str(), proto.c_str(), instance.c_str()); + serviceInstanceSet(service.c_str(), proto.c_str(), instance.c_str()); } // serviceInstanceSet void MDNS::servicePortSet(const std::string& service, const std::string& proto, uint16_t port) { - servicePortSet(service.c_str(), proto.c_str(), port); + servicePortSet(service.c_str(), proto.c_str(), port); } // servicePortSet void MDNS::serviceRemove(const std::string& service, const std::string& proto) { - serviceRemove(service.c_str(), proto.c_str()); + serviceRemove(service.c_str(), proto.c_str()); } // serviceRemove */ + /** * @brief Set the mDNS hostname. * @@ -809,10 +816,11 @@ void MDNS::serviceRemove(const std::string& service, const std::string& proto) { */ /* void MDNS::setHostname(const std::string& hostname) { - setHostname(hostname.c_str()); + setHostname(hostname.c_str()); } // setHostname */ + /** * @brief Set the mDNS instance. * @@ -821,10 +829,11 @@ void MDNS::setHostname(const std::string& hostname) { */ /* void MDNS::setInstance(const std::string& instance) { - setInstance(instance.c_str()); + setInstance(instance.c_str()); } // setInstance */ + /** * @brief Define the service for mDNS. * @@ -862,14 +871,15 @@ void MDNS::servicePortSet(const char* service, const char* proto, uint16_t port) void MDNS::serviceRemove(const char* service, const char* proto) { - esp_err_t errRc = ::mdns_service_remove(m_mdns_server, service, proto); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "mdns_service_remove: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - abort(); - } + esp_err_t errRc = ::mdns_service_remove(m_mdns_server, service, proto); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "mdns_service_remove: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + abort(); + } } // serviceRemove - */ + + /** * @brief Set the mDNS hostname. * @@ -879,13 +889,14 @@ void MDNS::serviceRemove(const char* service, const char* proto) { /* void MDNS::setHostname(const char* hostname) { esp_err_t errRc = ::mdns_set_hostname(m_mdns_server,hostname); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "mdns_set_hostname: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - abort(); - } + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "mdns_set_hostname: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + abort(); + } } // setHostname */ + /** * @brief Set the mDNS instance. * @@ -894,10 +905,10 @@ void MDNS::setHostname(const char* hostname) { */ /* void MDNS::setInstance(const char* instance) { - esp_err_t errRc = ::mdns_set_instance(m_mdns_server, instance); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "mdns_set_instance: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - abort(); - } + esp_err_t errRc = ::mdns_set_instance(m_mdns_server, instance); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "mdns_set_instance: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + abort(); + } } // setInstance */ diff --git a/cpp_utils/WiFi.h b/cpp_utils/WiFi.h index a57360ca..c0bfa07a 100644 --- a/cpp_utils/WiFi.h +++ b/cpp_utils/WiFi.h @@ -22,62 +22,65 @@ /* class MDNS { public: - MDNS(); - ~MDNS(); - void serviceAdd(const std::string& service, const std::string& proto, uint16_t port); - void serviceInstanceSet(const std::string& service, const std::string& proto, const std::string& instance); - void servicePortSet(const std::string& service, const std::string& proto, uint16_t port); - void serviceRemove(const std::string& service, const std::string& proto); - void setHostname(const std::string& hostname); - void setInstance(const std::string& instance); - // If we the above functions with a basic char*, a copy would be created into an std::string, - // making the whole thing require twice as much processing power and speed - void serviceAdd(const char* service, const char* proto, uint16_t port); - void serviceInstanceSet(const char* service, const char* proto, const char* instance); - void servicePortSet(const char* service, const char* proto, uint16_t port); - void serviceRemove(const char* service, const char* proto); - void setHostname(const char* hostname); - void setInstance(const char* instance); + MDNS(); + ~MDNS(); + void serviceAdd(const std::string& service, const std::string& proto, uint16_t port); + void serviceInstanceSet(const std::string& service, const std::string& proto, const std::string& instance); + void servicePortSet(const std::string& service, const std::string& proto, uint16_t port); + void serviceRemove(const std::string& service, const std::string& proto); + void setHostname(const std::string& hostname); + void setInstance(const std::string& instance); + // If we the above functions with a basic char*, a copy would be created into an std::string, + // making the whole thing require twice as much processing power and speed + void serviceAdd(const char* service, const char* proto, uint16_t port); + void serviceInstanceSet(const char* service, const char* proto, const char* instance); + void servicePortSet(const char* service, const char* proto, uint16_t port); + void serviceRemove(const char* service, const char* proto); + void setHostname(const char* hostname); + void setInstance(const char* instance); + private: - mdns_server_t *m_mdns_server = nullptr; + mdns_server_t* m_mdns_server = nullptr; + }; */ class WiFiAPRecord { public: - friend class WiFi; - - /** - * @brief Get the auth mode. - * @return The auth mode. - */ - wifi_auth_mode_t getAuthMode() { - return m_authMode; - } - - /** - * @brief Get the RSSI. - * @return the RSSI. - */ - int8_t getRSSI() { - return m_rssi; - } - - /** - * @brief Get the SSID. - * @return the SSID. - */ - std::string getSSID() { - return m_ssid; - } - - std::string toString(); + friend class WiFi; + + /** + * @brief Get the auth mode. + * @return The auth mode. + */ + wifi_auth_mode_t getAuthMode() { + return m_authMode; + } + + /** + * @brief Get the RSSI. + * @return the RSSI. + */ + int8_t getRSSI() { + return m_rssi; + } + + /** + * @brief Get the SSID. + * @return the SSID. + */ + std::string getSSID() { + return m_ssid; + } + + std::string toString(); private: - uint8_t m_bssid[6]; - int8_t m_rssi; - std::string m_ssid; - wifi_auth_mode_t m_authMode; + uint8_t m_bssid[6]; + int8_t m_rssi; + std::string m_ssid; + wifi_auth_mode_t m_authMode; + }; /** @@ -107,52 +110,53 @@ class WiFiAPRecord { */ class WiFi { private: - static esp_err_t eventHandler(void* ctx, system_event_t* event); - void init(); - uint32_t ip; - uint32_t gw; - uint32_t netmask; - WiFiEventHandler* m_pWifiEventHandler; - uint8_t m_dnsCount=0; - bool m_eventLoopStarted; - bool m_initCalled; - uint8_t m_apConnectionStatus; // ESP_OK = we are connected to an access point. Otherwise receives wifi_err_reason_t. + static esp_err_t eventHandler(void* ctx, system_event_t* event); + void init(); + uint32_t ip; + uint32_t gw; + uint32_t netmask; + WiFiEventHandler* m_pWifiEventHandler; + uint8_t m_dnsCount = 0; + bool m_eventLoopStarted; + bool m_initCalled; + uint8_t m_apConnectionStatus; // ESP_OK = we are connected to an access point. Otherwise receives wifi_err_reason_t. FreeRTOS::Semaphore m_connectFinished = FreeRTOS::Semaphore("ConnectFinished"); public: - WiFi(); - ~WiFi(); - void addDNSServer(const std::string& ip); - void addDNSServer(const char* ip); - void addDNSServer(ip_addr_t ip); - void setDNSServer(int numdns, const std::string& ip); - void setDNSServer(int numdns, const char* ip); - void setDNSServer(int numdns, ip_addr_t ip); - struct in_addr getHostByName(const std::string& hostName); - struct in_addr getHostByName(const char* hostName); - uint8_t connectAP(const std::string& ssid, const std::string& password, bool waitForConnection=true); - void dump(); - bool isConnectedToAP(); - static std::string getApMac(); - static tcpip_adapter_ip_info_t getApIpInfo(); - static std::string getApSSID(); + WiFi(); + ~WiFi(); + void addDNSServer(const std::string& ip); + void addDNSServer(const char* ip); + void addDNSServer(ip_addr_t ip); + void setDNSServer(int numdns, const std::string& ip); + void setDNSServer(int numdns, const char* ip); + void setDNSServer(int numdns, ip_addr_t ip); + struct in_addr getHostByName(const std::string& hostName); + struct in_addr getHostByName(const char* hostName); + uint8_t connectAP(const std::string& ssid, const std::string& password, bool waitForConnection = true, wifi_mode_t mode = WIFI_MODE_STA); + void dump(); + bool isConnectedToAP(); + static std::string getApMac(); + static tcpip_adapter_ip_info_t getApIpInfo(); + static std::string getApSSID(); static std::string getApIp(); static std::string getApNetmask(); static std::string getApGateway(); - static std::string getMode(); - static tcpip_adapter_ip_info_t getStaIpInfo(); - static std::string getStaMac(); - static std::string getStaSSID(); + static std::string getMode(); + static tcpip_adapter_ip_info_t getStaIpInfo(); + static std::string getStaMac(); + static std::string getStaSSID(); static std::string getStaIp(); static std::string getStaNetmask(); static std::string getStaGateway(); - std::vector scan(); - void startAP(const std::string& ssid, const std::string& passwd, wifi_auth_mode_t auth = WIFI_AUTH_OPEN); - void startAP(const std::string& ssid, const std::string& passwd, wifi_auth_mode_t auth, uint8_t channel, bool ssid_hidden, uint8_t max_connection); - void setIPInfo(const std::string& ip, const std::string& gw, const std::string& netmask); - void setIPInfo(const char* ip, const char* gw, const char* netmask); - void setIPInfo(uint32_t ip, uint32_t gw, uint32_t netmask); - void setWifiEventHandler(WiFiEventHandler *wifiEventHandler); + std::vector scan(); + void startAP(const std::string& ssid, const std::string& passwd, wifi_auth_mode_t auth = WIFI_AUTH_OPEN); + void startAP(const std::string& ssid, const std::string& passwd, wifi_auth_mode_t auth, uint8_t channel, bool ssid_hidden, uint8_t max_connection); + void setIPInfo(const std::string& ip, const std::string& gw, const std::string& netmask); + void setIPInfo(const char* ip, const char* gw, const char* netmask); + void setIPInfo(uint32_t ip, uint32_t gw, uint32_t netmask); + void setWifiEventHandler(WiFiEventHandler* wifiEventHandler); + }; #endif /* MAIN_WIFI_H_ */ diff --git a/cpp_utils/WiFiEventHandler.cpp b/cpp_utils/WiFiEventHandler.cpp index c5a4fa2f..204a0661 100644 --- a/cpp_utils/WiFiEventHandler.cpp +++ b/cpp_utils/WiFiEventHandler.cpp @@ -24,15 +24,15 @@ static const char* LOG_TAG = "WiFiEventHandler"; * @return ESP_OK if the event was handled otherwise an error. */ esp_err_t WiFiEventHandler::eventHandler(void* ctx, system_event_t* event) { - ESP_LOGD(LOG_TAG, ">> eventHandler called: ctx=0x%x, event=0x%x", (uint32_t)ctx, (uint32_t)event); - WiFiEventHandler *pWiFiEventHandler = (WiFiEventHandler *)ctx; + ESP_LOGD(LOG_TAG, ">> eventHandler called: ctx=0x%x, event=0x%x", (uint32_t) ctx, (uint32_t) event); + WiFiEventHandler* pWiFiEventHandler = (WiFiEventHandler*) ctx; if (ctx == nullptr) { ESP_LOGD(LOG_TAG, "No context"); return ESP_OK; } esp_err_t rc = ESP_OK; - switch(event->event_id) { + switch (event->event_id) { case SYSTEM_EVENT_AP_START: { rc = pWiFiEventHandler->apStart(); break; @@ -95,15 +95,15 @@ esp_err_t WiFiEventHandler::eventHandler(void* ctx, system_event_t* event) { default: break; - } - - if (pWiFiEventHandler->m_nextHandler != nullptr) { - printf("Found a next handler\n"); - rc = eventHandler(pWiFiEventHandler->m_nextHandler, event); - } else { - //printf("NOT Found a next handler\n"); - } - return rc; + } + + if (pWiFiEventHandler->m_nextHandler != nullptr) { + ESP_LOGD(LOG_TAG, "Found a next handler"); + rc = eventHandler(pWiFiEventHandler->m_nextHandler, event); + } else { + //ESP_LOGD(LOG_TAG, "NOT Found a next handler"); + } + return rc; } // eventHandler @@ -134,8 +134,8 @@ system_event_cb_t WiFiEventHandler::getEventHandler() { * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::staGotIp(system_event_sta_got_ip_t info) { - ESP_LOGD(LOG_TAG, "default staGotIp"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staGotIp"); + return ESP_OK; } // staGotIp @@ -145,8 +145,8 @@ esp_err_t WiFiEventHandler::staGotIp(system_event_sta_got_ip_t info) { * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::apStart() { - ESP_LOGD(LOG_TAG, "default apStart"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default apStart"); + return ESP_OK; } // apStart @@ -156,26 +156,26 @@ esp_err_t WiFiEventHandler::apStart() { * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::apStop() { - ESP_LOGD(LOG_TAG, "default apStop"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default apStop"); + return ESP_OK; } // apStop esp_err_t WiFiEventHandler::wifiReady() { - ESP_LOGD(LOG_TAG, "default wifiReady"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default wifiReady"); + return ESP_OK; } // wifiReady esp_err_t WiFiEventHandler::staStart() { - ESP_LOGD(LOG_TAG, "default staStart"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staStart"); + return ESP_OK; } // staStart esp_err_t WiFiEventHandler::staStop() { - ESP_LOGD(LOG_TAG, "default staStop"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staStop"); + return ESP_OK; } // staStop @@ -186,8 +186,8 @@ esp_err_t WiFiEventHandler::staStop() { * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::staConnected(system_event_sta_connected_t info) { - ESP_LOGD(LOG_TAG, "default staConnected"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staConnected"); + return ESP_OK; } // staConnected @@ -198,8 +198,8 @@ esp_err_t WiFiEventHandler::staConnected(system_event_sta_connected_t info) { * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::staDisconnected(system_event_sta_disconnected_t info) { - ESP_LOGD(LOG_TAG, "default staDisconnected"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staDisconnected"); + return ESP_OK; } // staDisconnected @@ -210,8 +210,8 @@ esp_err_t WiFiEventHandler::staDisconnected(system_event_sta_disconnected_t info * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::apStaConnected(system_event_ap_staconnected_t info) { - ESP_LOGD(LOG_TAG, "default apStaConnected"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default apStaConnected"); + return ESP_OK; } // apStaConnected @@ -222,8 +222,8 @@ esp_err_t WiFiEventHandler::apStaConnected(system_event_ap_staconnected_t info) * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::apStaDisconnected(system_event_ap_stadisconnected_t info) { - ESP_LOGD(LOG_TAG, "default apStaDisconnected"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default apStaDisconnected"); + return ESP_OK; } // apStaDisconnected @@ -234,8 +234,8 @@ esp_err_t WiFiEventHandler::apStaDisconnected(system_event_ap_stadisconnected_t * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::staScanDone(system_event_sta_scan_done_t info) { - ESP_LOGD(LOG_TAG, "default staScanDone"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staScanDone"); + return ESP_OK; } // staScanDone @@ -246,8 +246,8 @@ esp_err_t WiFiEventHandler::staScanDone(system_event_sta_scan_done_t info) { * @return An indication of whether or not we processed the event successfully. */ esp_err_t WiFiEventHandler::staAuthChange(system_event_sta_authmode_change_t info) { - ESP_LOGD(LOG_TAG, "default staAuthChange"); - return ESP_OK; + ESP_LOGD(LOG_TAG, "default staAuthChange"); + return ESP_OK; } // staAuthChange diff --git a/cpp_utils/WiFiEventHandler.h b/cpp_utils/WiFiEventHandler.h index 4dd46dba..9efb837f 100644 --- a/cpp_utils/WiFiEventHandler.h +++ b/cpp_utils/WiFiEventHandler.h @@ -117,9 +117,10 @@ class WiFiEventHandler { * Get the next WiFi event handler in the chain, if there is one. * @return The next WiFi event handler in the chain or nullptr if there is none. */ - WiFiEventHandler *getNextHandler() { + WiFiEventHandler* getNextHandler() { return m_nextHandler; } + /** * Set the next WiFi event handler in the chain. * @param [in] nextHandler The next WiFi event handler in the chain. @@ -132,6 +133,7 @@ class WiFiEventHandler { friend class WiFi; WiFiEventHandler *m_nextHandler; static esp_err_t eventHandler(void* ctx, system_event_t* event); + }; #endif /* MAIN_WIFIEVENTHANDLER_H_ */ diff --git a/cpp_utils/mainpage.dox b/cpp_utils/mainpage.dox index 3597471d..5701909e 100644 --- a/cpp_utils/mainpage.dox +++ b/cpp_utils/mainpage.dox @@ -5,4 +5,4 @@ * functions. * * The Github repository is [https://github.com/nkolban/esp32-snippets](https://github.com/nkolban/esp32-snippets). - */ \ No newline at end of file + */ diff --git a/cpp_utils/onhold/BLEEddystoneURL.cpp b/cpp_utils/onhold/BLEEddystoneURL.cpp deleted file mode 100644 index 6c12b246..00000000 --- a/cpp_utils/onhold/BLEEddystoneURL.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * BLEEddystoneURL.cpp - * - * Created on: Mar 12, 2018 - * Author: pcbreflux - */ -#include "sdkconfig.h" -#if defined(CONFIG_BT_ENABLED) -#include -#include -#include "BLEEddystoneURL.h" - -static const char LOG_TAG[] = "BLEEddystoneURL"; - -BLEEddystoneURL::BLEEddystoneURL() { - beconUUID = 0xFEAA; - lengthURL = 0; - m_eddystoneData.frameType = EDDYSTONE_URL_FRAME_TYPE; - m_eddystoneData.advertisedTxPower = 0; - memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); -} // BLEEddystoneURL - -std::string BLEEddystoneURL::getData() { - return std::string((char*)&m_eddystoneData, sizeof(m_eddystoneData)); -} // getData - -BLEUUID BLEEddystoneURL::getUUID() { - return BLEUUID(beconUUID); -} // getUUID - -int8_t BLEEddystoneURL::getPower() { - return m_eddystoneData.advertisedTxPower; -} // getPower - -std::string BLEEddystoneURL::getURL() { - return std::string((char*)&m_eddystoneData.url, sizeof(m_eddystoneData.url)); -} // getURL - -std::string BLEEddystoneURL::getDecodedURL() { - std::string decodedURL = ""; - - switch (m_eddystoneData.url[0]) { - case 0x00: - decodedURL += "http://www."; - break; - case 0x01: - decodedURL += "https://www."; - break; - case 0x02: - decodedURL += "http://"; - break; - case 0x03: - decodedURL += "https://"; - break; - default: - decodedURL += m_eddystoneData.url[0]; - } - - for (int i=1;i33&&m_eddystoneData.url[i]<127) { - decodedURL += m_eddystoneData.url[i]; - } else { - switch (m_eddystoneData.url[i]) { - case 0x00: - decodedURL += ".com/"; - break; - case 0x01: - decodedURL += ".org/"; - break; - case 0x02: - decodedURL += ".edu/"; - break; - case 0x03: - decodedURL += ".net/"; - break; - case 0x04: - decodedURL += ".info/"; - break; - case 0x05: - decodedURL += ".biz/"; - break; - case 0x06: - decodedURL += ".gov/"; - break; - case 0x07: - decodedURL += ".com"; - break; - case 0x08: - decodedURL += ".org"; - break; - case 0x09: - decodedURL += ".edu"; - break; - case 0x0A: - decodedURL += ".net"; - break; - case 0x0B: - decodedURL += ".info"; - break; - case 0x0C: - decodedURL += ".biz"; - break; - case 0x0D: - decodedURL += ".gov"; - break; - } - } - } - - - return decodedURL; -} // getDecodedURL - - - -/** - * Set the raw data for the beacon record. - */ -void BLEEddystoneURL::setData(std::string data) { - if (data.length() > sizeof(m_eddystoneData)) { - ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d", data.length(), sizeof(m_eddystoneData)); - return; - } - memset(&m_eddystoneData, 0, sizeof(m_eddystoneData)); - memcpy(&m_eddystoneData, data.data(), data.length()); - lengthURL=data.length()-(sizeof(m_eddystoneData)-sizeof(m_eddystoneData.url)); - -} // setData - -void BLEEddystoneURL::setUUID(BLEUUID l_uuid) { - beconUUID = l_uuid.getNative()->uuid.uuid16; -} // setUUID - -void BLEEddystoneURL::setPower(int8_t advertisedTxPower) { - m_eddystoneData.advertisedTxPower = advertisedTxPower; -} // setPower - -void BLEEddystoneURL::setURL(std::string url) { - if (url.length() > sizeof(m_eddystoneData.url)) { - ESP_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d", url.length(), sizeof(m_eddystoneData.url)); - return; - } - memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); - memcpy(m_eddystoneData.url, url.data(), url.length()); - lengthURL=url.length(); -} // setURL - - -#endif diff --git a/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino b/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino index c0b6163c..7bce73f1 100644 --- a/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino +++ b/cpp_utils/tests/BLETests/Arduino/BLE_client/BLE_client.ino @@ -6,9 +6,9 @@ //#include "BLEScan.h" // The remote service we wish to connect to. -static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); +static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); // The characteristic of the remote service we are interested in. -static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); +static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8"); static BLEAddress *pServerAddress; static boolean doConnect = false; @@ -62,6 +62,8 @@ bool connectToServer(BLEAddress pAddress) { Serial.println(value.c_str()); pRemoteCharacteristic->registerForNotify(notifyCallback); + + return true; } /** * Scan for BLE servers and find the first one that advertises the service we are looking for. diff --git a/cpp_utils/tests/BLETests/Arduino/BLE_iBeacon/BLE_iBeacon.ino b/cpp_utils/tests/BLETests/Arduino/BLE_iBeacon/BLE_iBeacon.ino index 5f6ed002..2c2ec6a3 100644 --- a/cpp_utils/tests/BLETests/Arduino/BLE_iBeacon/BLE_iBeacon.ino +++ b/cpp_utils/tests/BLETests/Arduino/BLE_iBeacon/BLE_iBeacon.ino @@ -49,7 +49,7 @@ void setBeacon() { BLEBeacon oBeacon = BLEBeacon(); oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) - oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); + oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16); oBeacon.setMinor(bootcount&0xFFFF); BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); @@ -84,10 +84,10 @@ void setup() { // Create the BLE Device BLEDevice::init(""); - // Create the BLE Server - BLEServer *pServer = BLEDevice::createServer(); + // Create the BLE Server is no longer required to crete beacon + // BLEServer *pServer = BLEDevice::createServer(); - pAdvertising = pServer->getAdvertising(); + pAdvertising = BLEDevice::getAdvertising(); setBeacon(); // Start advertising diff --git a/cpp_utils/tests/BLETests/Arduino/BLE_server/BLE_server.ino b/cpp_utils/tests/BLETests/Arduino/BLE_server/BLE_server.ino index 38224a67..79793975 100644 --- a/cpp_utils/tests/BLETests/Arduino/BLE_server/BLE_server.ino +++ b/cpp_utils/tests/BLETests/Arduino/BLE_server/BLE_server.ino @@ -29,6 +29,7 @@ void setup() { pCharacteristic->setValue("Hello World says Neil"); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); pAdvertising->start(); Serial.println("Characteristic defined! Now you can read it in your phone!"); } @@ -36,4 +37,4 @@ void setup() { void loop() { // put your main code here, to run repeatedly: delay(2000); -} \ No newline at end of file +} diff --git a/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_encrypted.ino b/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_encrypted.ino deleted file mode 100644 index e77d774f..00000000 --- a/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_encrypted.ino +++ /dev/null @@ -1,138 +0,0 @@ -/** - * A BLE client example that is rich in capabilities. - */ - -#include "BLEDevice.h" -//#include "BLEScan.h" - -// The remote service we wish to connect to. -static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); -// The characteristic of the remote service we are interested in. -static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); - -static BLEAddress *pServerAddress; -static boolean doConnect = false; -static boolean connected = false; -static BLERemoteCharacteristic* pRemoteCharacteristic; - -static void notifyCallback( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify) { - Serial.print("Notify callback for characteristic "); - Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); - Serial.print(" of data length "); - Serial.println(length); -} - -bool connectToServer(BLEAddress pAddress) { - Serial.print("Forming a connection to "); - Serial.println(pAddress.toString().c_str()); - - /* - * Here we have implemented simplest security. This kind security does not provide authentication - */ - BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); - BLEClient* pClient = BLEDevice::createClient(); - Serial.println(" - Created client"); - - // Connect to the remove BLE Server. - pClient->connect(pAddress); - Serial.println(" - Connected to server"); - - // Obtain a reference to the service we are after in the remote BLE server. - BLERemoteService* pRemoteService = pClient->getService(serviceUUID); - if (pRemoteService == nullptr) { - Serial.print("Failed to find our service UUID: "); - Serial.println(serviceUUID.toString().c_str()); - return false; - } - Serial.println(" - Found our service"); - - - // Obtain a reference to the characteristic in the service of the remote BLE server. - pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); - if (pRemoteCharacteristic == nullptr) { - Serial.print("Failed to find our characteristic UUID: "); - Serial.println(charUUID.toString().c_str()); - return false; - } - Serial.println(" - Found our characteristic"); - - // Read the value of the characteristic. - std::string value = pRemoteCharacteristic->readValue(); - Serial.print("The characteristic value was: "); - Serial.println(value.c_str()); - - pRemoteCharacteristic->registerForNotify(notifyCallback); -} -/** - * Scan for BLE servers and find the first one that advertises the service we are looking for. - */ -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - /** - * Called for each advertising BLE server. - */ - void onResult(BLEAdvertisedDevice advertisedDevice) { - Serial.print("BLE Advertised Device found: "); - Serial.println(advertisedDevice.toString().c_str()); - - // We have found a device, let us now see if it contains the service we are looking for. - if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) { - - // - Serial.print("Found our device! address: "); - advertisedDevice.getScan()->stop(); - - pServerAddress = new BLEAddress(advertisedDevice.getAddress()); - doConnect = true; - - } // Found our server - } // onResult -}; // MyAdvertisedDeviceCallbacks - - -void setup() { - Serial.begin(115200); - Serial.println("Starting Arduino BLE Client application..."); - BLEDevice::init(""); - - // Retrieve a Scanner and set the callback we want to use to be informed when we - // have detected a new device. Specify that we want active scanning and start the - // scan to run for 30 seconds. - BLEScan* pBLEScan = BLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); - pBLEScan->start(30); -} // End of setup. - - -// This is the Arduino main loop function. -void loop() { - - // If the flag "doConnect" is true then we have scanned for and found the desired - // BLE Server with which we wish to connect. Now we connect to it. Once we are - // connected we set the connected flag to be true. - if (doConnect == true) { - if (connectToServer(*pServerAddress)) { - Serial.println("We are now connected to the BLE Server."); - connected = true; - } else { - Serial.println("We have failed to connect to the server; there is nothin more we will do."); - } - doConnect = false; - } - - // If we are connected to a peer BLE Server, update the characteristic each time we are reached - // with the current time since boot. - if (connected) { - String newValue = "Time since boot: " + String(millis()/1000); - Serial.println("Setting new characteristic value to \"" + newValue + "\""); - - // Set the characteristic's value to be the array of bytes that is actually a string. - pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); - } - - delay(1000); // Delay a second between loops. -} // End of loop diff --git a/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_numeric_confirmation.ino b/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_numeric_confirmation.ino deleted file mode 100644 index 846a664b..00000000 --- a/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_numeric_confirmation.ino +++ /dev/null @@ -1,169 +0,0 @@ -/** - * A BLE client example that is rich in capabilities. - */ - -#include "BLEDevice.h" -//#include "BLEScan.h" - -// The remote service we wish to connect to. -static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); -// The characteristic of the remote service we are interested in. -static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); - -static BLEAddress *pServerAddress; -static boolean doConnect = false; -static boolean connected = false; -static BLERemoteCharacteristic* pRemoteCharacteristic; - -class MySecurity : public BLESecurityCallbacks { - - uint32_t onPassKeyRequest(){ - return 123456; - } - void onPassKeyNotify(uint32_t pass_key){ - ESP_LOGE(LOG_TAG, "The passkey Notify number:%d", pass_key); - } - bool onConfirmPIN(uint32_t pass_key){ - ESP_LOGI(LOG_TAG, "The passkey YES/NO number:%d", pass_key); - vTaskDelay(5000); - return true; - } - bool onSecurityRequest(){ - ESP_LOGI(LOG_TAG, "Security Request"); - return true; - } - void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl){ - if(auth_cmpl.success){ - ESP_LOGI(LOG_TAG, "remote BD_ADDR:"); - esp_log_buffer_hex(LOG_TAG, auth_cmpl.bd_addr, sizeof(auth_cmpl.bd_addr)); - ESP_LOGI(LOG_TAG, "address type = %d", auth_cmpl.addr_type); - } - ESP_LOGI(LOG_TAG, "pair status = %s", auth_cmpl.success ? "success" : "fail"); - } -}; - -static void notifyCallback( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify) { - Serial.print("Notify callback for characteristic "); - Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); - Serial.print(" of data length "); - Serial.println(length); -} - -bool connectToServer(BLEAddress pAddress) { - Serial.print("Forming a connection to "); - Serial.println(pAddress.toString().c_str()); - - BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); - BLEDevice::setSecurityCallbacks(new MySecurity()); - - BLESecurity *pSecurity = new BLESecurity(); - pSecurity->setKeySize(); - pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY); - pSecurity->setCapability(ESP_IO_CAP_IO); - pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); - BLEClient* pClient = BLEDevice::createClient(); - Serial.println(" - Created client"); - - // Connect to the remove BLE Server. - pClient->connect(pAddress); - Serial.println(" - Connected to server"); - - // Obtain a reference to the service we are after in the remote BLE server. - BLERemoteService* pRemoteService = pClient->getService(serviceUUID); - if (pRemoteService == nullptr) { - Serial.print("Failed to find our service UUID: "); - Serial.println(serviceUUID.toString().c_str()); - return false; - } - Serial.println(" - Found our service"); - - - // Obtain a reference to the characteristic in the service of the remote BLE server. - pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); - if (pRemoteCharacteristic == nullptr) { - Serial.print("Failed to find our characteristic UUID: "); - Serial.println(charUUID.toString().c_str()); - return false; - } - Serial.println(" - Found our characteristic"); - - // Read the value of the characteristic. - std::string value = pRemoteCharacteristic->readValue(); - Serial.print("The characteristic value was: "); - Serial.println(value.c_str()); - - pRemoteCharacteristic->registerForNotify(notifyCallback); -} -/** - * Scan for BLE servers and find the first one that advertises the service we are looking for. - */ -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - /** - * Called for each advertising BLE server. - */ - void onResult(BLEAdvertisedDevice advertisedDevice) { - Serial.print("BLE Advertised Device found: "); - Serial.println(advertisedDevice.toString().c_str()); - - // We have found a device, let us now see if it contains the service we are looking for. - if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) { - - // - Serial.print("Found our device! address: "); - advertisedDevice.getScan()->stop(); - - pServerAddress = new BLEAddress(advertisedDevice.getAddress()); - doConnect = true; - - } // Found our server - } // onResult -}; // MyAdvertisedDeviceCallbacks - - -void setup() { - Serial.begin(115200); - Serial.println("Starting Arduino BLE Client application..."); - BLEDevice::init(""); - - // Retrieve a Scanner and set the callback we want to use to be informed when we - // have detected a new device. Specify that we want active scanning and start the - // scan to run for 30 seconds. - BLEScan* pBLEScan = BLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); - pBLEScan->start(30); -} // End of setup. - - -// This is the Arduino main loop function. -void loop() { - - // If the flag "doConnect" is true then we have scanned for and found the desired - // BLE Server with which we wish to connect. Now we connect to it. Once we are - // connected we set the connected flag to be true. - if (doConnect == true) { - if (connectToServer(*pServerAddress)) { - Serial.println("We are now connected to the BLE Server."); - connected = true; - } else { - Serial.println("We have failed to connect to the server; there is nothin more we will do."); - } - doConnect = false; - } - - // If we are connected to a peer BLE Server, update the characteristic each time we are reached - // with the current time since boot. - if (connected) { - String newValue = "Time since boot: " + String(millis()/1000); - Serial.println("Setting new characteristic value to \"" + newValue + "\""); - - // Set the characteristic's value to be the array of bytes that is actually a string. - pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); - } - - delay(1000); // Delay a second between loops. -} // End of loop diff --git a/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_passkey.ino b/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_passkey.ino deleted file mode 100644 index 763a87d2..00000000 --- a/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_passkey.ino +++ /dev/null @@ -1,168 +0,0 @@ -/** - * A BLE client example that is rich in capabilities. - */ - -#include "BLEDevice.h" -//#include "BLEScan.h" - -// The remote service we wish to connect to. -static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); -// The characteristic of the remote service we are interested in. -static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); - -static BLEAddress *pServerAddress; -static boolean doConnect = false; -static boolean connected = false; -static BLERemoteCharacteristic* pRemoteCharacteristic; - -class MySecurity : public BLESecurityCallbacks { - - uint32_t onPassKeyRequest(){ - return 123456; - } - void onPassKeyNotify(uint32_t pass_key){ - ESP_LOGE(LOG_TAG, "The passkey Notify number:%d", pass_key); - } - bool onConfirmPIN(uint32_t pass_key){ - ESP_LOGI(LOG_TAG, "The passkey YES/NO number:%d", pass_key); - vTaskDelay(5000); - return true; - } - bool onSecurityRequest(){ - ESP_LOGI(LOG_TAG, "Security Request"); - return true; - } - void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl){ - if(auth_cmpl.success){ - ESP_LOGI(LOG_TAG, "remote BD_ADDR:"); - esp_log_buffer_hex(LOG_TAG, auth_cmpl.bd_addr, sizeof(auth_cmpl.bd_addr)); - ESP_LOGI(LOG_TAG, "address type = %d", auth_cmpl.addr_type); - } - ESP_LOGI(LOG_TAG, "pair status = %s", auth_cmpl.success ? "success" : "fail"); - } -}; - -static void notifyCallback( - BLERemoteCharacteristic* pBLERemoteCharacteristic, - uint8_t* pData, - size_t length, - bool isNotify) { - Serial.print("Notify callback for characteristic "); - Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); - Serial.print(" of data length "); - Serial.println(length); -} - -bool connectToServer(BLEAddress pAddress) { - Serial.print("Forming a connection to "); - Serial.println(pAddress.toString().c_str()); - - BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); - BLEDevice::setSecurityCallbacks(new MySecurity()); - - BLESecurity *pSecurity = new BLESecurity(); - pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY); - pSecurity->setCapability(ESP_IO_CAP_OUT); - pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); - BLEClient* pClient = BLEDevice::createClient(); - Serial.println(" - Created client"); - - // Connect to the remove BLE Server. - pClient->connect(pAddress); - Serial.println(" - Connected to server"); - - // Obtain a reference to the service we are after in the remote BLE server. - BLERemoteService* pRemoteService = pClient->getService(serviceUUID); - if (pRemoteService == nullptr) { - Serial.print("Failed to find our service UUID: "); - Serial.println(serviceUUID.toString().c_str()); - return false; - } - Serial.println(" - Found our service"); - - - // Obtain a reference to the characteristic in the service of the remote BLE server. - pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); - if (pRemoteCharacteristic == nullptr) { - Serial.print("Failed to find our characteristic UUID: "); - Serial.println(charUUID.toString().c_str()); - return false; - } - Serial.println(" - Found our characteristic"); - - // Read the value of the characteristic. - std::string value = pRemoteCharacteristic->readValue(); - Serial.print("The characteristic value was: "); - Serial.println(value.c_str()); - - pRemoteCharacteristic->registerForNotify(notifyCallback); -} -/** - * Scan for BLE servers and find the first one that advertises the service we are looking for. - */ -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - /** - * Called for each advertising BLE server. - */ - void onResult(BLEAdvertisedDevice advertisedDevice) { - Serial.print("BLE Advertised Device found: "); - Serial.println(advertisedDevice.toString().c_str()); - - // We have found a device, let us now see if it contains the service we are looking for. - if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) { - - // - Serial.print("Found our device! address: "); - advertisedDevice.getScan()->stop(); - - pServerAddress = new BLEAddress(advertisedDevice.getAddress()); - doConnect = true; - - } // Found our server - } // onResult -}; // MyAdvertisedDeviceCallbacks - - -void setup() { - Serial.begin(115200); - Serial.println("Starting Arduino BLE Client application..."); - BLEDevice::init(""); - - // Retrieve a Scanner and set the callback we want to use to be informed when we - // have detected a new device. Specify that we want active scanning and start the - // scan to run for 30 seconds. - BLEScan* pBLEScan = BLEDevice::getScan(); - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(true); - pBLEScan->start(30); -} // End of setup. - - -// This is the Arduino main loop function. -void loop() { - - // If the flag "doConnect" is true then we have scanned for and found the desired - // BLE Server with which we wish to connect. Now we connect to it. Once we are - // connected we set the connected flag to be true. - if (doConnect == true) { - if (connectToServer(*pServerAddress)) { - Serial.println("We are now connected to the BLE Server."); - connected = true; - } else { - Serial.println("We have failed to connect to the server; there is nothin more we will do."); - } - doConnect = false; - } - - // If we are connected to a peer BLE Server, update the characteristic each time we are reached - // with the current time since boot. - if (connected) { - String newValue = "Time since boot: " + String(millis()/1000); - Serial.println("Setting new characteristic value to \"" + newValue + "\""); - - // Set the characteristic's value to be the array of bytes that is actually a string. - pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length()); - } - - delay(1000); // Delay a second between loops. -} // End of loop diff --git a/cpp_utils/tests/BLETests/Arduino/security/BLE_server/BLE_server_passkey/BLE_server_passkey.ino b/cpp_utils/tests/BLETests/Arduino/security/BLE_server/BLE_server_passkey/BLE_server_passkey.ino index a48ad482..93f8c89f 100644 --- a/cpp_utils/tests/BLETests/Arduino/security/BLE_server/BLE_server_passkey/BLE_server_passkey.ino +++ b/cpp_utils/tests/BLETests/Arduino/security/BLE_server/BLE_server_passkey/BLE_server_passkey.ino @@ -14,7 +14,11 @@ #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" class MySecurity : public BLESecurityCallbacks { - + + bool onConfirmPIN(uint32_t pin){ + return false; + } + uint32_t onPassKeyRequest(){ ESP_LOGI(LOG_TAG, "PassKeyRequest"); return 123456; diff --git a/cpp_utils/tests/BLETests/Arduino/security/StaticPIN/StaticPIN.ino b/cpp_utils/tests/BLETests/Arduino/security/StaticPIN/StaticPIN.ino new file mode 100644 index 00000000..d89c14f9 --- /dev/null +++ b/cpp_utils/tests/BLETests/Arduino/security/StaticPIN/StaticPIN.ino @@ -0,0 +1,47 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp + Ported to Arduino ESP32 by Evandro Copercini +*/ + +#include +#include +#include + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + + BLEDevice::init("ESP32"); + /* + * Required in authentication process to provide displaying and/or input passkey or yes/no butttons confirmation + */ + BLEServer *pServer = BLEDevice::createServer(); + BLEService *pService = pServer->createService(SERVICE_UUID); + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE + ); + pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + pCharacteristic->setValue("Hello World says Neil"); + pService->start(); + BLEAdvertising *pAdvertising = pServer->getAdvertising(); + pAdvertising->start(); + + BLESecurity *pSecurity = new BLESecurity(); + pSecurity->setStaticPIN(123456); + + //set static passkey + Serial.println("Characteristic defined! Now you can read it in your phone!"); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} diff --git a/cpp_utils/tests/task_i2c_scanner.cpp b/cpp_utils/tests/task_i2c_scanner.cpp index b1bde2e0..061c3b08 100644 --- a/cpp_utils/tests/task_i2c_scanner.cpp +++ b/cpp_utils/tests/task_i2c_scanner.cpp @@ -6,6 +6,7 @@ #include "sdkconfig.h" +#define DEVICE_ADDRESS 0 #define SDA_PIN 25 #define SCL_PIN 26 @@ -14,7 +15,7 @@ class I2CScanner: public Task { void run(void *data) override { I2C i2c; - i2c.init((gpio_num_t)SDA_PIN, (gpio_num_t)SCL_PIN); + i2c.init((uint8_t)DEVICE_ADDRESS, (gpio_num_t)SDA_PIN, (gpio_num_t)SCL_PIN); i2c.scan(); } // End run }; diff --git a/eclipse/c_includes.xml b/eclipse/c_includes.xml index eaa53ba2..60400ad5 100644 --- a/eclipse/c_includes.xml +++ b/eclipse/c_includes.xml @@ -50,7 +50,6 @@ ${IDF_PATH}/components/spi_flash/include ${IDF_PATH}/components/mbedtls/include ${IDF_PATH}/components/mdns/include -${IDF_PATH}/components/json/include ${IDF_PATH}/components/bt/include ${IDF_PATH}/components/bt/bluedroid/bta/include ${IDF_PATH}/components/bt/bluedroid/bta/sys/include @@ -128,18 +127,36 @@ ESP_PLATFORM1 + +PLATFORM_ID11 + + +DEBUG_BUILD1 + ESP_PLATFORM1 + +PLATFORM_ID11 + + +DEBUG_BUILD1 + ESP_PLATFORM1 + +PLATFORM_ID11 + + +DEBUG_BUILD1 + diff --git a/hardware/displays/U8G2/u8g2_esp32_hal.c b/hardware/displays/U8G2/u8g2_esp32_hal.c index fdab51a3..caaa78d9 100644 --- a/hardware/displays/U8G2/u8g2_esp32_hal.c +++ b/hardware/displays/U8G2/u8g2_esp32_hal.c @@ -47,6 +47,7 @@ uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void } spi_bus_config_t bus_config; + memset(&bus_config, 0, sizeof(spi_bus_config_t)); bus_config.sclk_io_num = u8g2_esp32_hal.clk; // CLK bus_config.mosi_io_num = u8g2_esp32_hal.mosi; // MOSI bus_config.miso_io_num = -1; // MISO diff --git a/hardware/rtc/pcf8523.c b/hardware/rtc/pcf8523.c new file mode 100644 index 00000000..2d1e310e --- /dev/null +++ b/hardware/rtc/pcf8523.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "errorhandle_func.h" + +#include "sdkconfig.h" + +#define SDA_PIN 23 +#define SCL_PIN 22 +#define RTC_ADDRESS 0x68 // most I2C rtcs have their address on 0x68. any doubt check with i2c scanner snippet + +static char tag[] = "RTC"; + +static uint8_t intToBCD(uint8_t num) { + return ((num / 10) << 4) | (num%10); +} + +static uint8_t bcdToInt(uint8_t bcd) { + // 0x10 + return ((bcd >> 4) * 10) + (bcd & 0x0f);; +} + + +void initI2C() { + i2c_config_t conf; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = SDA_PIN; + conf.scl_io_num = SCL_PIN; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = 100000; + ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf)); + ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0)); +} + +/* + * PCF8523 slightly changed its 7 bytes encoded in BCD: + * 03h - Seconds - 00-59 + * 04h - Minutes - 00-59 + * 05h - Hours - 00-23 + * 06h - monthday - 01-31 + * 07h - weekday - 00-06 + * 08h - Month - 01-12 + * 09h - Year - 00-99 + * + */ +time_t rtc_readValue() { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + ESP_ERROR_CHECK(i2c_master_start(cmd)); + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (RTC_ADDRESS << 1) | I2C_MASTER_WRITE, true /* expect ack */)); + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, 0x03, 1)); // start address + ESP_ERROR_CHECK(i2c_master_start(cmd)); + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (RTC_ADDRESS << 1) | I2C_MASTER_READ, true /* expect ack */)); + uint8_t data[7]; + ESP_ERROR_CHECK(i2c_master_read(cmd, data, 7, false)); + ESP_ERROR_CHECK(i2c_master_stop(cmd)); + COMMANDCHECKOKERR(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS),"RTC COMMAND"); + i2c_cmd_link_delete(cmd); + + int i; + for (i=0; i<7; i++) { + ESP_LOGD(tag, "%d: 0x%.2x", i, data[i]); + } + + struct tm tm; + tm.tm_sec = bcdToInt(data[0]); + tm.tm_min = bcdToInt(data[1]); + tm.tm_hour = bcdToInt(data[2]); + tm.tm_mday = bcdToInt(data[3]); + tm.tm_mon = bcdToInt(data[5]) - 1; // 0-11 - Note: The month on the PCF8523 is 1-12. + tm.tm_year = bcdToInt(data[6]) + 100; // Years since 1900 + time_t readTime = mktime(&tm); + return readTime; +} + +void rtc_writeValue(time_t newTime) { + ESP_LOGD(tag, ">> writeValue: %ld", newTime); + struct tm tm; + gmtime_r(&newTime, &tm); + char buf[30]; + ESP_LOGD(tag, " - %s", asctime_r(&tm, buf)); + + esp_err_t errRc; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + ESP_ERROR_CHECK(i2c_master_start(cmd)); + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (RTC_ADDRESS << 1) | I2C_MASTER_WRITE, 1 /* expect ack */)); + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, 0x03, 1)); + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_sec), 1)); // seconds + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_min), 1 )); // minutes + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_hour), 1 )); // hours + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_mday), 1)); // date of month + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_wday+1), 1 )); // week day + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_mon+1), 1)); // month + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, intToBCD(tm.tm_year-100), 1)); // year + ESP_ERROR_CHECK(i2c_master_stop(cmd)); + errRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS); + if (errRc != 0) { + ESP_LOGE(tag, "i2c_master_cmd_begin: %d", errRc); + } + i2c_cmd_link_delete(cmd); +} + + +/* + implement in your time function + @Kolban created a nice one, here is my contribution. + + esp_err_t sntp_update(){ + + static const char *tag = "TIME_SETUP"; + esp_err_t ret; + char buffer[20]; + EventBits_t bitreturn; + TickType_t waittime = 10000/portTICK_PERIOD_MS; + + + bitreturn = xEventGroupWaitBits(event_group, WIFI_CONNECTED_BIT, pdFALSE, pdTRUE, waittime); + + if((bitreturn & BIT0) != 0){ + + printf("going online\n"); + + } + else printf("going offline\n"); + + + // initialize the SNTP service + sntp_setoperatingmode(SNTP_OPMODE_POLL); + // to create SNTP server variable make a #define statement i.e. "pool.ntp.org" + sntp_setservername(0, CONFIG_SNTP_SERVER); + sntp_init(); + + initI2C(); + + time_t t; + struct tm timertc; + t = rtc_readValue(); + localtime_r(&t, &timertc); + + strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", &timertc); + ESP_LOGI(tag,"Current time in rtc (GTM) is: %s\n\n", buffer); + + // wait for the service to set the time + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + int counter = 0; + + // try for a minute to get time from network + while((timeinfo.tm_year < (2018 - 1900)) && (counter < 12)) + { + + ESP_LOGW(tag,"Time outdated, waiting...\n"); + vTaskDelay(5000 / portTICK_PERIOD_MS); + time(&now); + localtime_r(&now, &timeinfo); + counter ++; + } + + if((timeinfo.tm_year < (2018 - 1900)) && (counter == 12)){ + ESP_LOGE(tag, "TIMEOUT"); + + + // stick to rtc time + now = rtc_readValue(); + + } + else{ + // update rtc time + rtc_writeValue(now); + } + + + // to create timezone variable make a #define statement i.e. "COT+5" + setenv("TZ",CONFIG_TIMEZONE_TZ, 1); + tzset(); + + // print the actual time in location + localtime_r(&now, &timeinfo); + strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", &timeinfo); + ESP_LOGI(tag,"Current time in your Location: %s\n\n", buffer); + + // check time set in rtc in case it was updated from network + t = rtc_readValue(); + localtime_r(&t, &timertc); + strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", &timertc); + ESP_LOGI(tag,"Current time in rtc (GTM) is: %s\n\n", buffer); + + ret = ESP_OK; + + return ret; +} + + */ diff --git a/tasks/watchdogs/README.md b/tasks/watchdogs/README.md new file mode 100644 index 00000000..052bc868 --- /dev/null +++ b/tasks/watchdogs/README.md @@ -0,0 +1,6 @@ +# Watchdogs +This is a sample application that illustrates the capabilities of watchdogs and watchdog processing. + +A related YouTube video is available here: + +https://www.youtube.com/watch?v=C2xF3O6qkbg \ No newline at end of file diff --git a/tasks/watchdogs/main.cpp b/tasks/watchdogs/main.cpp new file mode 100644 index 00000000..de4484c5 --- /dev/null +++ b/tasks/watchdogs/main.cpp @@ -0,0 +1,155 @@ +#include "freertos/FreeRTOS.h" +#include "esp_wifi.h" +#include "esp_system.h" +#include "esp_event.h" +#include "esp_event_loop.h" +#include "nvs_flash.h" +#include "driver/gpio.h" +#include + +esp_err_t event_handler(void *ctx, system_event_t *event) +{ + return ESP_OK; +} + +extern "C" +{ + void app_main(void); +} + +void highPriorityTask(void *myData) +{ + printf("High priority task started and now looping for 10 seconds. Our priority is %d.\n", uxTaskPriorityGet(nullptr)); + TickType_t startTicks = xTaskGetTickCount(); + while (xTaskGetTickCount() - startTicks < (10 * 1000 / portTICK_PERIOD_MS)) + { + // Do nothing but loop + } + printf("High priority task ended\n"); + vTaskDelete(nullptr); +} + +void hardLoopTask(void *myData) +{ + printf("Hard loop task started ...\n"); + while (1) + { + // do nothing but burn CPU + } +} + +void hardLoopTaskNoInterrupts(void *myData) +{ + printf("Hard loop task disabling interrupts started ...\n"); + taskDISABLE_INTERRUPTS(); + while (1) + { + // do nothing but burn CPU + } +} + +void myTask(void *myData) +{ + printf("# Running in myTask\n"); + printf("# Registering our new task with the task watchdog.\n"); + esp_task_wdt_add(nullptr); + + printf("# Looping 5 times with a delay of 1 second and not feeding the watchdog.\n"); + for (int i = 0; i < 5; i++) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Tick\n"); + } + + printf("# Looping 5 times with a delay of 1 second and positively feeding the watchdog.\n"); + esp_task_wdt_reset(); + for (int i = 0; i < 5; i++) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Tick\n"); + esp_task_wdt_reset(); + } + + printf("# Removing our watchdog registration so we can do something expensive.\n"); + esp_task_wdt_delete(nullptr); + + printf("# Looping 5 times with a delay of 1 second and not feeding the watchdog.\n"); + for (int i = 0; i < 5; i++) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Tick\n"); + } + + printf("# Re-registering our task with the task watchdog.\n"); + esp_task_wdt_add(nullptr); + printf("# Looping 5 times with a delay of 1 second and not feeding the watchdog.\n"); + for (int i = 0; i < 5; i++) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Tick\n"); + } + + printf("# Our current task priority is %d.\n", uxTaskPriorityGet(nullptr)); + printf("# Spwaning a higher priority task\n"); + xTaskCreate(highPriorityTask, // Task code + "Priority task", // Name of task + 16 * 1024, // Stack size + nullptr, // Task data + 5, // Priority + nullptr // task handle + ); + + printf("# Looping 5 times with a delay of 1 second and positively feeding the watchdog.\n"); + esp_task_wdt_reset(); + for (int i = 0; i < 5; i++) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Tick\n"); + esp_task_wdt_reset(); + } + + printf("Spawning a hard-loop function!\n"); + xTaskCreate(hardLoopTaskNoInterrupts, // Task code + "Hard Loop", // Name of task + 16 * 1024, // Stack size + nullptr, // Task data + 5, // Priority + nullptr // task handle + ); + + printf("# Looping 5 times with a delay of 1 second and positively feeding the watchdog.\n"); + esp_task_wdt_reset(); + for (int i = 0; i < 5; i++) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Tick\n"); + esp_task_wdt_reset(); + } + + + printf("# Removing our watchdog registration before we end the task.\n"); + esp_task_wdt_delete(nullptr); + + printf("# Ending myTask\n"); + vTaskDelete(nullptr); +} // myTask + +void app_main(void) +{ + xTaskHandle handle; + printf("App starting\n"); + printf("Initializing the task watchdog subsystem with an interval of 2 seconds.\n"); + esp_task_wdt_init(2, false); + + printf("Creatign a new task.\n"); + // Now let us create a new task. + xTaskCreate(myTask, // Task code + "My Task", // Name of task + 16 * 1024, // Stack size + nullptr, // Task data + 0, // Priority + &handle // task handle + ); + + //printf("App Ended!\n"); +} // app_main diff --git a/tools/bootloaderExamine/main.cpp b/tools/bootloaderExamine/main.cpp index 22e8a5aa..60472e30 100644 --- a/tools/bootloaderExamine/main.cpp +++ b/tools/bootloaderExamine/main.cpp @@ -1,5 +1,6 @@ #include #include +#include /* Main header of binary image */ typedef struct { @@ -120,6 +121,11 @@ int main(int argc, char *argv[]) { return 0; } + if (header.magic != 0xE9) { + printf("Failed to find magic number (0xE9) in BIN file header.\n"); + return 0; + } + printf("Dump of ESP32 binary file: %s\n", fileName); printf("magic: 0x%x, segment_count: %d, entry_addr: 0x%x - %s, hash_appended: %d\n", header.magic, header.segment_count, header.entry_addr, area(header.entry_addr), header.hash_appended);