diff --git a/maddius/3d_models/maddius-next.FCStd b/maddius/3d_models/maddius-next.FCStd new file mode 100644 index 0000000..0fff994 Binary files /dev/null and b/maddius/3d_models/maddius-next.FCStd differ diff --git a/maddius/maddius_button8/.gitignore b/maddius/maddius_button8/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/maddius/maddius_button8/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/maddius/maddius_button8/.vscode/extensions.json b/maddius/maddius_button8/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/maddius/maddius_button8/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/maddius/maddius_button8/include/README b/maddius/maddius_button8/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/maddius/maddius_button8/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/maddius/maddius_button8/lib/README b/maddius/maddius_button8/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/maddius/maddius_button8/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/maddius/maddius_button8/platformio.ini b/maddius/maddius_button8/platformio.ini new file mode 100644 index 0000000..8ba220f --- /dev/null +++ b/maddius/maddius_button8/platformio.ini @@ -0,0 +1,14 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:nanoatmega328new] +platform = atmelavr +board = nanoatmega328new +framework = arduino diff --git a/maddius/maddius_button8/src/MaddiusClient.cpp b/maddius/maddius_button8/src/MaddiusClient.cpp new file mode 100644 index 0000000..3d96e16 --- /dev/null +++ b/maddius/maddius_button8/src/MaddiusClient.cpp @@ -0,0 +1,162 @@ + +#include // I2C +#include + +#define CHIPSET ARDUINO_NANO +#define DEVMODE true + +#define I2C_SCL 19 // A5 +#define I2C_SDA 18 // A4 +#define I2C_INTERRUPT_REQUEST 2 // D2 // D3? + +#define BUTTON_PIN0 12 // D12 S10 +#define BUTTON_PIN1 13 // D13 S11 +#define BUTTON_PIN2 14 // A0 S12 +#define BUTTON_PIN3 15 // A1 S13 +#define BUTTON_PIN4 16 // A2 S14 +#define BUTTON_PIN5 17 // A3 S15 +#define BUTTON_PIN6 20 // A6 S16 +#define BUTTON_PIN7 21 // A7 S17 + +#define LED_PIN0 4 // D4 S10 +#define LED_PIN1 5 // D5 S11 +#define LED_PIN2 6 // D6 S12 +#define LED_PIN3 7 // D7 S13 +#define LED_PIN4 8 // D8 S14 +#define LED_PIN5 9 // D9 S15 +#define LED_PIN6 10 // D10 S16 +#define LED_PIN7 11 // D11 S17 + +#define I2C_SLAVE1_ADR 56 + +uint8_t ledPins[8] = {LED_PIN0, LED_PIN1, LED_PIN2, LED_PIN3, LED_PIN4, LED_PIN5, LED_PIN6, LED_PIN7}; + +uint8_t buttonLastState[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t buttonNextState[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + +uint8_t buttonExternalState[8] = {0}; + +bool changeDetected = false; + +void requestEvent() +{ + + Serial.print("requestEvent"); + Wire.write(buttonLastState, 8); // respond with message of 8 bytes + + // as expected by master + changeDetected = false; +} + +void setup() +{ + // put your setup code here, to run once: + if (DEVMODE) + { + // pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(9600); // start serial for output + } + // initialize the LED pin as an output: + + pinMode(LED_PIN0, OUTPUT); + pinMode(LED_PIN1, OUTPUT); + pinMode(LED_PIN2, OUTPUT); + pinMode(LED_PIN3, OUTPUT); + pinMode(LED_PIN4, OUTPUT); + pinMode(LED_PIN5, OUTPUT); + pinMode(LED_PIN6, OUTPUT); + pinMode(LED_PIN7, OUTPUT); + + // initialize the pushbutton pin as an input: + // pinMode(BUTTON_PIN0, INPUT); + pinMode(BUTTON_PIN0, INPUT_PULLUP); + pinMode(BUTTON_PIN1, INPUT_PULLUP); + pinMode(BUTTON_PIN2, INPUT_PULLUP); + pinMode(BUTTON_PIN3, INPUT_PULLUP); + pinMode(BUTTON_PIN4, INPUT_PULLUP); + pinMode(BUTTON_PIN5, INPUT_PULLUP); + pinMode(BUTTON_PIN6, INPUT); + pinMode(BUTTON_PIN7, INPUT); + // digitalWrite(BUTTON_PIN6, INPUT_PULLUP); + // digitalWrite(BUTTON_PIN7, INPUT_PULLUP); + + // Interrupt line open drain + pinMode(I2C_INTERRUPT_REQUEST, INPUT); + digitalWrite(I2C_INTERRUPT_REQUEST, LOW); + + Wire.begin(I2C_SLAVE1_ADR); // join i2c bus + // Write to low for voltage compatibility + digitalWrite(SDA, LOW); + digitalWrite(SCL, LOW); + Wire.onRequest(requestEvent); // register event +} + +int resetIRQCount = 0; + +void loop() +{ + buttonNextState[0] = digitalRead(BUTTON_PIN0) ? 0 : 255; + buttonNextState[1] = digitalRead(BUTTON_PIN1) ? 0 : 255; + buttonNextState[2] = digitalRead(BUTTON_PIN2) ? 0 : 255; + buttonNextState[3] = digitalRead(BUTTON_PIN3) ? 0 : 255; + buttonNextState[4] = digitalRead(BUTTON_PIN4) ? 0 : 255; + buttonNextState[5] = digitalRead(BUTTON_PIN5) ? 0 : 255; + + int buttonNextState6 = analogRead(BUTTON_PIN6); + int buttonNextState7 = analogRead(BUTTON_PIN7); + if (buttonNextState6 > 500) + { + buttonNextState[6] = 0; + } + else + { + buttonNextState[6] = 255; + } + if (buttonNextState7 > 500) + { + buttonNextState[7] = 0; + } + else + { + buttonNextState[7] = 255; + } + // WIRE I2C + + // better only on change? + for (int i = 0; i < 8; i++) + { + if (buttonNextState[i] != buttonLastState[i]) + { + buttonLastState[i] = buttonNextState[i]; + Serial.print("B"); + Serial.print(i); + Serial.print(": "); + Serial.println(buttonNextState[i]); + changeDetected = true; + } + if (buttonLastState[i] == 255 || buttonExternalState[i] == 255) + { + digitalWrite(ledPins[i], HIGH); + } + else + { + digitalWrite(ledPins[i], LOW); + } + } + if (changeDetected) + { + pinMode(I2C_INTERRUPT_REQUEST, OUTPUT); + resetIRQCount++; + } + else + { + pinMode(I2C_INTERRUPT_REQUEST, INPUT); + resetIRQCount = 0; + } + if (resetIRQCount > 1000) + { + changeDetected = false; + resetIRQCount = 0; + } + delayMicroseconds(5); +} diff --git a/maddius/maddius_button8/test/README b/maddius/maddius_button8/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/maddius/maddius_button8/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/maddius/maddius_fade9/.gitignore b/maddius/maddius_fade9/.gitignore new file mode 100644 index 0000000..b9f3806 --- /dev/null +++ b/maddius/maddius_fade9/.gitignore @@ -0,0 +1,2 @@ +.pio +.vscode diff --git a/maddius/maddius_fade9/include/README b/maddius/maddius_fade9/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/maddius/maddius_fade9/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/maddius/maddius_fade9/lib/README b/maddius/maddius_fade9/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/maddius/maddius_fade9/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/maddius/maddius_fade9/platformio.ini b/maddius/maddius_fade9/platformio.ini new file mode 100644 index 0000000..9cb7b36 --- /dev/null +++ b/maddius/maddius_fade9/platformio.ini @@ -0,0 +1,15 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:teensy36] +platform = teensy +board = teensy36 +framework = arduino +lib_deps = arduinogetstarted/ezButton@^1.0.4 diff --git a/maddius/maddius_fade9/src/MaddiusClient.cpp b/maddius/maddius_fade9/src/MaddiusClient.cpp new file mode 100644 index 0000000..d7f06d9 --- /dev/null +++ b/maddius/maddius_fade9/src/MaddiusClient.cpp @@ -0,0 +1,290 @@ +/* Belegung Pin Name Pin Number Spice Number + VBAT 1 1 + 5V 2 2 + USBD2- 3 3 + USBD2+ 4 4 + USBD1- 5 5 + USBD1+ 6 6 +Fader 5 64/A10 7 7 +Fader 6 65/A11 8 8 + GND 9 9 +Btn 1 0 10 10 +Btn 2 1 11 11 +Btn LED 1 2 12 12 +Btn LED 2 3 13 13 +Btn LED 3 4 14 14 +Btn LED 4 5 15 15 +Btn LED 5 6 16 16 +Btn LED 6 7 17 17 +Btn LED 7 8 18 18 +Btn LED 8 9 19 19 +Btn LED 9 10 20 20 +Motor 1 B 11 21 21 +Motor 1 A 12 22 22 +Motor 5 B 40 23 23 +Motor 2 B 24 24 24 +Motor 3 B 25 25 25 +Motor 3 A 26 26 26 +Motor 4 A 27 27 27 +Motor 4 B 28 28 28 +Touch 8 29 29 29 +Touch 9 30 30 30 +Fader 1 31/A12 31 31 +Fader 2 32/A13 32 32 +Motor 5 A 41 33 33 +Motor 6 A 42 34 34 +Motor 6 B 43 35 35 +Motor 7 B 44 36 36 +Motor 7 B 45 37 37 +Motor 8 A 46 38 38 +Motor 8 B 47 39 39 +Motor 9 B 48 40 40 +Btn 3 49/A23 41 41 +Btn 4 50/A24 42 42 +Motor 9 A 51 43 43 +Btn 5 52 44 44 +Btn 6 53 45 45 +Btn 7 54 46 46 +Btn 8 55 47 47 +I2C 56 48 48 +Standby 33/A14 49 49 +Motor 2 A 34/A15 50 50 + 35/A16 51 51 +Motor Speed 36/A17 52 52 +I2C 37/A18 53 53 +I2C 38/A19 54 54 +Fader 7 39/A20 55 55 +Fader 3 66/A21 56 56 +Fader 4 67/A22 57 57 +I2C 57 58 58 +Sys LED 13 (LED) 59 59 +Fader 8 14/A0 60 60 +Touch 1 15/A1 61 61 +Touch 2 16/A2 62 62 +Touch 3 17/A3 63 63 +Touch 4 18/A4 64 64 +Touch 5 19/A5 65 65 +Fader 9 20/A6 66 66 +Btn 9 21/A7 67 67 +Touch 6 22/A8 68 68 +Touch 7 23/A9 69 69 + 3V3 70 70 + AGND 71 71 + VIN 72 72 + GND 73 73 + VUSB 74 74 + PRGM 75 75 + RESET 76 76 + AREF 77 77 + DBGEN 78 78 + SWCLK 79 79 + SWDIO 80 80 + MT1 81 81 + MT2 82 82 +*/ + +#include // I2C +#include +#include + +#define CHIPSET ARDUINO_NANO +#define DEVMODE true + +// #define I2C_SCL 37 // +// #define I2C_SDA 38 // +#define I2C_INTERRUPT_REQUEST 57 // + +#define FADER_PIN0 31 +#define FADER_PIN1 32 +#define FADER_PIN2 66 +#define FADER_PIN3 67 +#define FADER_PIN4 64 // +#define FADER_PIN5 65 // +#define FADER_PIN6 39 // +#define FADER_PIN7 14 // +#define FADER_PIN8 20 // +// sensibility 0 is highest +// fader 4 has problems so i need to set to 3 to not getting signals all the time the others worked good with 1 // todo invetigate +#define FADER_SENIBILITY 3 // + +#define BUTTON_PIN0 0 +#define BUTTON_PIN1 1 +#define BUTTON_PIN2 49 +#define BUTTON_PIN3 50 +#define BUTTON_PIN4 52 // +#define BUTTON_PIN5 53 // +#define BUTTON_PIN6 54 // +#define BUTTON_PIN7 55 // +#define BUTTON_PIN8 21 // + +#define BUTTON_DEBOUNCE 20 + +#define LED_PIN0 2 // +#define LED_PIN1 3 // +#define LED_PIN2 4 // +#define LED_PIN3 5 // +#define LED_PIN4 6 // +#define LED_PIN5 7 // +#define LED_PIN6 8 // +#define LED_PIN7 9 // +#define LED_PIN8 10 // + +#define SYS_LED 13 // + +#define I2C_SLAVE1_ADR 55 + +uint8_t ledPins[9] = {LED_PIN0, LED_PIN1, LED_PIN2, LED_PIN3, LED_PIN4, LED_PIN5, LED_PIN6, LED_PIN7, LED_PIN8}; + +uint8_t faderPins[9] = {FADER_PIN0, FADER_PIN1, FADER_PIN2, FADER_PIN3, FADER_PIN4, FADER_PIN5, FADER_PIN6, FADER_PIN7, FADER_PIN8}; + +uint8_t buttonPins[9] = {BUTTON_PIN0, BUTTON_PIN1, BUTTON_PIN2, BUTTON_PIN3, BUTTON_PIN4, BUTTON_PIN5, BUTTON_PIN6, BUTTON_PIN7, BUTTON_PIN8}; + +uint8_t faderLastState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t faderNextState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; + +uint8_t buttonLastState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t buttonNextState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; + +uint8_t buttonExternalState[9] = {0}; + +bool changeDetected = false; + +ezButton button[9] = {{BUTTON_PIN0}, {BUTTON_PIN1}, {BUTTON_PIN2}, {BUTTON_PIN3}, {BUTTON_PIN4}, {BUTTON_PIN5}, {BUTTON_PIN6}, {BUTTON_PIN7}, {BUTTON_PIN8}}; + +void requestEvent() +{ + + Serial.print("requestEvent"); + Wire1.write(faderLastState, 9); // respond with message of 8 bytes + Wire1.write(buttonLastState, 9); // respond with message of 8 bytes + // as expected by master + changeDetected = false; +} + +void setup() +{ + // put your setup code here, to run once: + if (DEVMODE) + { + Serial.begin(9600); // start serial for output + } + // INIT PINS + // SYS LED + pinMode(SYS_LED, OUTPUT); + digitalWrite(SYS_LED, HIGH); + + for (int i = 0; i < 9; i++) + { + // BTN LED + pinMode(ledPins[i], OUTPUT); + // BTN PIN + // pinMode(buttonPins[i], INPUT_PULLUP); + // button[i] = *new ezButton(buttonPins[i]); + button[i].setDebounceTime(BUTTON_DEBOUNCE); + // FADER + pinMode(faderPins[i], INPUT); + } + + // Interrupt line open drain + pinMode(I2C_INTERRUPT_REQUEST, INPUT); + digitalWrite(I2C_INTERRUPT_REQUEST, LOW); + // I2C + Wire1.begin(I2C_SLAVE1_ADR); + // INTERUPTTRIGGER + // Write to low for voltage compatibility + // digitalWrite(SDA, LOW); + // digitalWrite(SCL, LOW); + Wire1.onRequest(requestEvent); // register event +} + +int resetIRQCount = 0; + +void loop() +{ + for (int i = 0; i < 9; i++) + { + // uint8_t buttonValue = digitalRead(buttonPins[i]); + // buttonNextState[i] = buttonValue ? 0 : 255; + button[i].loop(); + if (button[i].isPressed()) + { + buttonNextState[i] = 255; + } + else if (button[i].isReleased()) + { + buttonNextState[i] = 0; + } + int read = analogRead(faderPins[i]); + faderNextState[i] = read >> 2; + // Serial.print("r"); + // Serial.print(read); + // Serial.print(": "); + // Serial.println(faderNextState[i]); + } + + // WIRE I2C + bool nextChangeDetected = false; + // better only on change? + for (int i = 0; i < 9; i++) + { + // FADERS + if (abs(faderNextState[i] - faderLastState[i]) > 3) // > 3 + { + if (faderNextState[i] <= 3) + { + faderNextState[i] = 0; + } + else if (faderNextState[i] >= (255 - 3)) + { + faderNextState[i] = 255; + } + faderLastState[i] = faderNextState[i]; + Serial.print("F"); + Serial.print(i); + Serial.print(": "); + Serial.println(faderNextState[i]); + // Serial.println(analogRead(faderPins[i])); + nextChangeDetected = true; + } + // Buttons + if (buttonNextState[i] != buttonLastState[i]) + { + buttonLastState[i] = buttonNextState[i]; + Serial.print("B"); + Serial.print(i); + Serial.print(": "); + Serial.println(buttonNextState[i]); + nextChangeDetected = true; + } + if (buttonLastState[i] == 255 || buttonExternalState[i] == 255) + { + digitalWrite(ledPins[i], HIGH); + } + else + { + digitalWrite(ledPins[i], LOW); + } + } + if (nextChangeDetected && !changeDetected) + { + changeDetected = nextChangeDetected; + pinMode(I2C_INTERRUPT_REQUEST, OUTPUT); + // resetIRQCount++; + } + else if (!changeDetected) + { + pinMode(I2C_INTERRUPT_REQUEST, INPUT); + } + // else + // { + + // // resetIRQCount = 0; + // } + // if (resetIRQCount > 1000) + // { + // changeDetected = false; + // resetIRQCount = 0; + // Serial.println(buttonNextState[i]); + // } + // delayMicroseconds(5); +} diff --git a/maddius/maddius_fade9/test/README b/maddius/maddius_fade9/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/maddius/maddius_fade9/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/maddius/maddius_matrix_control/.gitignore b/maddius/maddius_matrix_control/.gitignore new file mode 100644 index 0000000..d4cbbe1 --- /dev/null +++ b/maddius/maddius_matrix_control/.gitignore @@ -0,0 +1,4 @@ +.pio +.vscode +build +managed_components \ No newline at end of file diff --git a/maddius/maddius_matrix_control/CMakeLists.txt b/maddius/maddius_matrix_control/CMakeLists.txt new file mode 100644 index 0000000..ac95049 --- /dev/null +++ b/maddius/maddius_matrix_control/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(tusb_midi) diff --git a/maddius/maddius_matrix_control/README.md b/maddius/maddius_matrix_control/README.md new file mode 100644 index 0000000..f510b15 --- /dev/null +++ b/maddius/maddius_matrix_control/README.md @@ -0,0 +1,83 @@ +| Supported Targets | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | + +# TinyUSB MIDI Device Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example shows how to set up ESP chip to work as a USB MIDI Device. +It outputs a MIDI note sequence via the native USB port. + +As a USB stack, a TinyUSB component is used. + +## How to use example + +### Hardware Required + +Any ESP board that have USB-OTG supported. + +#### Pin Assignment + +_Note:_ In case your board doesn't have micro-USB connector connected to USB-OTG peripheral, you may have to DIY a cable and connect **D+** and **D-** to the pins listed below. + +See common pin assignments for USB Device examples from [upper level](../../README.md#common-pin-assignments). + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +```bash +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## MIDI output + +You can use several programs on your computer to listen to the ESP's MIDI output depending on your operating system, e.g.: + +* Windows: `MIDI-OX` +* Linux: `qsynth` with `qjackctl` +* macOS: `SimpleSynth` + +## Example Output + +After the flashing you should see the output at idf monitor: + +``` +I (285) example: USB initialization +I (285) tusb_desc: +┌─────────────────────────────────┐ +│ USB Device Descriptor Summary │ +├───────────────────┬─────────────┤ +│bDeviceClass │ 0 │ +├───────────────────┼─────────────┤ +│bDeviceSubClass │ 0 │ +├───────────────────┼─────────────┤ +│bDeviceProtocol │ 0 │ +├───────────────────┼─────────────┤ +│bMaxPacketSize0 │ 64 │ +├───────────────────┼─────────────┤ +│idVendor │ 0x303a │ +├───────────────────┼─────────────┤ +│idProduct │ 0x4008 │ +├───────────────────┼─────────────┤ +│bcdDevice │ 0x100 │ +├───────────────────┼─────────────┤ +│iManufacturer │ 0x1 │ +├───────────────────┼─────────────┤ +│iProduct │ 0x2 │ +├───────────────────┼─────────────┤ +│iSerialNumber │ 0x3 │ +├───────────────────┼─────────────┤ +│bNumConfigurations │ 0x1 │ +└───────────────────┴─────────────┘ +I (455) TinyUSB: TinyUSB Driver installed +I (465) example: USB initialization DONE +``` + +Disconnect UART-to-USB port and connect the native USB port to a computer then the device should show up as a USB MIDI Device while outputting notes. diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/.component_hash b/maddius/maddius_matrix_control/components/Adafruit_Keypad/.component_hash new file mode 100644 index 0000000..0685781 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/.component_hash @@ -0,0 +1 @@ +3f3297a0c07a511d5b455c3806d53f23fa65cf75833270daa89f35564e9375a3 \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad.cpp b/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad.cpp new file mode 100644 index 0000000..31117d8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad.cpp @@ -0,0 +1,217 @@ +#include "Adafruit_Keypad.h" + +#define _KEY_PRESSED_POS (1) +#define _KEY_PRESSED (1UL << _KEY_PRESSED_POS) + +#define _JUST_PRESSED_POS (2) +#define _JUST_PRESSED (1UL << _JUST_PRESSED_POS) + +#define _JUST_RELEASED_POS (3) +#define _JUST_RELEASED (1UL << _JUST_RELEASED_POS) + +#define _KEYPAD_SETTLING_DELAY 20 + +/**************************************************************************/ +/*! + @brief default constructor + @param userKeymap a multidimensional array of key characters + @param row an array of GPIO pins that are connected to each row of the + keypad + @param col an array of GPIO pins that are connected to each column of the + keypad + @param numRows the number of rows on the keypad + @param numCols the number of columns on the keypad +*/ +/**************************************************************************/ +Adafruit_Keypad::Adafruit_Keypad(byte *userKeymap, byte *row, byte *col, + int numRows, int numCols) { + _userKeymap = userKeymap; + _row = row; + _col = col; + _numRows = numRows; + _numCols = numCols; + + _keystates = NULL; +} + +/**************************************************************************/ +/*! + @brief default destructor +*/ +/**************************************************************************/ +Adafruit_Keypad::~Adafruit_Keypad() { + if (_keystates != NULL) { + free((void *)_keystates); + } +} + +/**************************************************************************/ +/*! + @brief get the state of a key with the given name + @param key the name of the key to be checked +*/ +/**************************************************************************/ +volatile byte *Adafruit_Keypad::getKeyState(byte key) { + for (int i = 0; i < _numRows * _numCols; i++) { + if (_userKeymap[i] == key) { + return _keystates + i; + } + } + return NULL; +} + +/**************************************************************************/ +/*! + @brief read the array of switches and place any events in the buffer. +*/ +/**************************************************************************/ +void Adafruit_Keypad::tick() { + uint8_t evt; + for (int i = 0; i < _numCols; i++) { + digitalWrite(_col[i], HIGH); + } + + int i = 0; + for (int c = 0; c < _numCols; c++) { + digitalWrite(_col[c], LOW); + delayMicroseconds(_KEYPAD_SETTLING_DELAY); + for (int r = 0; r < _numRows; r++) { + i = r * _numCols + c; + bool pressed = !digitalRead(_row[r]); + // Serial.print((int)pressed); + volatile byte *state = _keystates + i; + byte currentState = *state; + if (pressed && !(currentState & _KEY_PRESSED)) { + currentState |= (_JUST_PRESSED | _KEY_PRESSED); + evt = KEY_JUST_PRESSED; + _eventbuf.store_char(evt); + _eventbuf.store_char(*(_userKeymap + i)); + _eventbuf.store_char(r); + _eventbuf.store_char(c); + } else if (!pressed && (currentState & _KEY_PRESSED)) { + currentState |= _JUST_RELEASED; + currentState &= ~(_KEY_PRESSED); + evt = KEY_JUST_RELEASED; + _eventbuf.store_char(evt); + _eventbuf.store_char(*(_userKeymap + i)); + _eventbuf.store_char(r); + _eventbuf.store_char(c); + } + *state = currentState; + } + // Serial.println(""); + digitalWrite(_col[c], HIGH); + } +} + +/**************************************************************************/ +/*! + @brief set all the pin modes and set up variables. +*/ +/**************************************************************************/ +void Adafruit_Keypad::begin() { + _keystates = (volatile byte *)malloc(_numRows * _numCols); + memset((void *)_keystates, 0, _numRows * _numCols); + + for (int i = 0; i < _numCols; i++) { + pinMode(_col[i], OUTPUT); + digitalWrite(_col[i], HIGH); + } + + for (int i = 0; i < _numRows; i++) { + pinMode(_row[i], INPUT_PULLUP); + } +} + +/**************************************************************************/ +/*! + @brief check if the given key has just been pressed since the last tick. + @param key the name of the key to be checked + @param clear whether to reset the state (default yes) post-check + @returns true if it has been pressed, false otherwise. +*/ +/**************************************************************************/ +bool Adafruit_Keypad::justPressed(byte key, bool clear) { + volatile byte *state = getKeyState(key); + bool val = (*state & _JUST_PRESSED) != 0; + + if (clear) + *state &= ~(_JUST_PRESSED); + + return val; +} + +/**************************************************************************/ +/*! + @brief check if the given key has just been released since the last tick. + @param key the name of the key to be checked + @returns true if it has been released, false otherwise. +*/ +/**************************************************************************/ +bool Adafruit_Keypad::justReleased(byte key) { + volatile byte *state = getKeyState(key); + bool val = (*state & _JUST_RELEASED) != 0; + + *state &= ~(_JUST_RELEASED); + + return val; +} + +/**************************************************************************/ +/*! + @brief check if the given key is currently pressed + @param key the name of the key to be checked + @returns true if it is currently pressed, false otherwise. +*/ +/**************************************************************************/ +bool Adafruit_Keypad::isPressed(byte key) { + return (*getKeyState(key) & _KEY_PRESSED) != 0; +} + +/**************************************************************************/ +/*! + @brief check if the given key is currently released + @param key the name of the key to be checked + @returns true if it is currently released, false otherwise. +*/ +/**************************************************************************/ +bool Adafruit_Keypad::isReleased(byte key) { + return (*getKeyState(key) & _KEY_PRESSED) == 0; +} + +/**************************************************************************/ +/*! + @brief check how many events are in the keypads buffer + @returns the number of events currently in the buffer +*/ +/**************************************************************************/ +int Adafruit_Keypad::available() { + return (_eventbuf.available() / sizeof(keypadEvent)); +} + +/**************************************************************************/ +/*! + @brief pop the next event off of the FIFO + @returns the next event in the FIFO +*/ +/**************************************************************************/ +keypadEvent Adafruit_Keypad::read() { + keypadEvent k; + k.bit.EVENT = _eventbuf.read_char(); + k.bit.KEY = _eventbuf.read_char(); + k.bit.ROW = _eventbuf.read_char(); + k.bit.COL = _eventbuf.read_char(); + + return k; +} + +/**************************************************************************/ +/*! + @brief Clear out the event buffer and all the key states +*/ +/**************************************************************************/ +void Adafruit_Keypad::clear() { + _eventbuf.clear(); + for (int i = 0; i < _numRows * _numCols; i++) + *(_keystates + i) = 0; +} diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad.h b/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad.h new file mode 100644 index 0000000..fdb8947 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad.h @@ -0,0 +1,63 @@ +#ifndef _ADAFRUIT_KEYPAD_H_ +#define _ADAFRUIT_KEYPAD_H_ + +#include "Adafruit_Keypad_Ringbuffer.h" +#include "Arduino.h" +#include + +#define makeKeymap(x) ((byte *)x) ///< cast the passed key characters to bytes + +#define KEY_JUST_RELEASED (0) ///< key has been released +#define KEY_JUST_PRESSED (1) ///< key has been pressed + +/**************************************************************************/ +/*! + @brief key event structure +*/ +/**************************************************************************/ +union keypadEvent { + struct { + uint8_t KEY : 8; ///< the keycode + uint8_t EVENT : 8; ///< the edge + uint8_t ROW : 8; ///< the row number + uint8_t COL : 8; ///< the col number + } bit; ///< bitfield format + uint32_t reg; ///< register format +}; + +/**************************************************************************/ +/*! + @brief Class for interfacing GPIO with a diode-multiplexed keypad +*/ +/**************************************************************************/ +class Adafruit_Keypad { +public: + Adafruit_Keypad(byte *userKeymap, byte *row, byte *col, int numRows, + int numCols); + ~Adafruit_Keypad(); + void begin(); + + void tick(); + + bool justPressed(byte key, bool clear = true); + bool justReleased(byte key); + bool isPressed(byte key); + bool isReleased(byte key); + int available(); + keypadEvent read(); + void clear(); + +private: + byte *_userKeymap; + byte *_row; + byte *_col; + volatile byte *_keystates; + Adafruit_Keypad_Ringbuffer _eventbuf; + + int _numRows; + int _numCols; + + volatile byte *getKeyState(byte key); +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad_Ringbuffer.h b/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad_Ringbuffer.h new file mode 100644 index 0000000..af504e1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/Adafruit_Keypad_Ringbuffer.h @@ -0,0 +1,126 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef __cplusplus + +#ifndef _ADAFRUIT_KEYPAD_RING_BUFFER_ +#define _ADAFRUIT_KEYPAD_RING_BUFFER_ + +#include +#include + +// Define constants and variables for buffering incoming serial data. We're +// using a ring buffer (I think), in which head is the index of the location +// to which to write the next incoming character and tail is the index of the +// location from which to read. + +#ifndef SERIAL_BUFFER_SIZE +#define SERIAL_BUFFER_SIZE 256 +#endif + +template class Adafruit_Keypad_RingbufferN { +public: + uint8_t _aucBuffer[N]; + volatile int _iHead; + volatile int _iTail; + +public: + Adafruit_Keypad_RingbufferN(void); + void store_char(uint8_t c); + void clear(); + int read_char(); + int available(); + int availableForStore(); + int peek(); + bool isFull(); + +private: + int nextIndex(int index); +}; + +typedef Adafruit_Keypad_RingbufferN + Adafruit_Keypad_Ringbuffer; + +template +Adafruit_Keypad_RingbufferN::Adafruit_Keypad_RingbufferN(void) { + memset(_aucBuffer, 0, N); + clear(); +} + +template void Adafruit_Keypad_RingbufferN::store_char(uint8_t c) { + int i = nextIndex(_iHead); + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != _iTail) { + _aucBuffer[_iHead] = c; + _iHead = i; + } +} + +template void Adafruit_Keypad_RingbufferN::clear() { + _iHead = 0; + _iTail = 0; +} + +template int Adafruit_Keypad_RingbufferN::read_char() { + if (_iTail == _iHead) + return -1; + + uint8_t value = _aucBuffer[_iTail]; + _iTail = nextIndex(_iTail); + + return value; +} + +template int Adafruit_Keypad_RingbufferN::available() { + int delta = _iHead - _iTail; + + if (delta < 0) + return N + delta; + else + return delta; +} + +template int Adafruit_Keypad_RingbufferN::availableForStore() { + if (_iHead >= _iTail) + return N - 1 - _iHead + _iTail; + else + return _iTail - _iHead - 1; +} + +template int Adafruit_Keypad_RingbufferN::peek() { + if (_iTail == _iHead) + return -1; + + return _aucBuffer[_iTail]; +} + +template int Adafruit_Keypad_RingbufferN::nextIndex(int index) { + return (uint32_t)(index + 1) % N; +} + +template bool Adafruit_Keypad_RingbufferN::isFull() { + return (nextIndex(_iHead) == _iTail); +} + +#endif /* _ADAFRUIT_KEYPAD_RING_BUFFER_ */ + +#endif /* __cplusplus */ diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/CMakeLists.txt b/maddius/maddius_matrix_control/components/Adafruit_Keypad/CMakeLists.txt new file mode 100644 index 0000000..8deb9ac --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.5) +idf_component_register(SRCS "Adafruit_Keypad.cpp" + REQUIRES "arduino-esp32" "spi_flash" "esp_partition" + INCLUDE_DIRS ".") +project(Adafruit_Keypad) \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/README.md b/maddius/maddius_matrix_control/components/Adafruit_Keypad/README.md new file mode 100644 index 0000000..4bb998c --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/README.md @@ -0,0 +1,10 @@ +# Adafruit Keypad Library [![Build Status](https://github.com/adafruit/Adafruit_Keypad/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_Keypad/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_Keypad/html/index.html) + + + +This is a library for using diode multiplexed keypads with GPIO pins on Arduino. + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +Written by Dean Miller for Adafruit Industries. +MIT license, all text above must be included in any redistribution diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/Ortho5x6Demo/Ortho5x6Demo.ino b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/Ortho5x6Demo/Ortho5x6Demo.ino new file mode 100644 index 0000000..acbb06a --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/Ortho5x6Demo/Ortho5x6Demo.ino @@ -0,0 +1,100 @@ +#include +#include "Adafruit_Keypad.h" + +#define ROWS 5 // rows +#define COLS 6 // columns + +#define NEOPIXEL_PIN A0 +#define NUM_PIXELS (ROWS * COLS) + +Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); + + +//define the symbols on the buttons of the keypads +char keys[ROWS][COLS] = { + {'1','2','3','4','5','6'}, + {'7','8','9','A','B','C'}, + {'D','E','F','G','H','I'}, + {'J','K','L','M','N','O'}, + {'P','Q','R','S','T','U'} +}; + +uint8_t rowPins[ROWS] = {6, 5, 4, 3, 2}; //connect to the row pinouts of the keypad +uint8_t colPins[COLS] = {7, 8, 9, 10, 11, 12}; //connect to the column pinouts of the keypad + +//initialize an instance of class NewKeypad +Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); + +bool lit[ROWS*COLS] = {0}; + +void setup() { + Serial.begin(115200); + //while (!Serial); + Serial.println("Ortho 5x6 keypad demo"); + strip.begin(); + strip.setBrightness(40); + strip.show(); // Initialize all pixels to 'off' + + customKeypad.begin(); + for (int i=0; i "); + uint16_t keynum; + if (row % 2 == 0) { // even row + keynum = row * COLS + col; + } else { // odd row the neopixels go BACKWARDS! + keynum = row * COLS + (5 - col); + } + Serial.println(keynum); + lit[keynum] = !lit[keynum]; // invert neopixel status + } + else if(e.bit.EVENT == KEY_JUST_RELEASED) { + Serial.println(" released"); + } + } + + for(int i=0; i< strip.numPixels(); i++) { + if (lit[i]) { + strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); + } else { + strip.setPixelColor(i, 0); + } + } + strip.show(); + j++; + + delay(10); +} + + +// Input a value 0 to 255 to get a color value. +// The colours are a transition r - g - b - back to r. +uint32_t Wheel(byte WheelPos) { + if(WheelPos < 85) { + return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); + } else if(WheelPos < 170) { + WheelPos -= 85; + return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); + } else { + WheelPos -= 170; + return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); + } +} diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_generic/keypad_generic.ino b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_generic/keypad_generic.ino new file mode 100644 index 0000000..663a3bc --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_generic/keypad_generic.ino @@ -0,0 +1,36 @@ +#include "Adafruit_Keypad.h" + +const byte ROWS = 4; // rows +const byte COLS = 4; // columns +//define the symbols on the buttons of the keypads +char keys[ROWS][COLS] = { + {'1','2','3','A'}, + {'4','5','6','B'}, + {'7','8','9','C'}, + {'*','0','#','D'} +}; +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {11, 10, 9, 8}; //connect to the column pinouts of the keypad + +//initialize an instance of class NewKeypad +Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); + +void setup() { + Serial.begin(9600); + customKeypad.begin(); + +} + +void loop() { + // put your main code here, to run repeatedly: + customKeypad.tick(); + + while(customKeypad.available()){ + keypadEvent e = customKeypad.read(); + Serial.print((char)e.bit.KEY); + if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed"); + else if(e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released"); + } + + delay(10); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_test/keypad_config.h b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_test/keypad_config.h new file mode 100644 index 0000000..d688f32 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_test/keypad_config.h @@ -0,0 +1,43 @@ +// This file contains predefined setup for various Adafruit Matrix Keypads. +#ifndef __KEYPAD_CONFIG_H__ +#define __KEYPAD_CONFIG_H__ + +#if defined(KEYPAD_PID3844) +const byte ROWS = 4; // rows +const byte COLS = 4; // columns +// define the symbols on the buttons of the keypads +char keys[ROWS][COLS] = {{'1', '2', '3', 'A'}, + {'4', '5', '6', 'B'}, + {'7', '8', '9', 'C'}, + {'*', '0', '#', 'D'}}; +byte rowPins[ROWS] = {R1, R2, R3, + R4}; // connect to the row pinouts of the keypad +byte colPins[COLS] = {C1, C2, C3, + C4}; // connect to the column pinouts of the keypad +#endif + +#if defined(KEYPAD_PID1824) || defined(KEYPAD_PID3845) || defined(KEYPAD_PID419) +const byte ROWS = 4; // rows +const byte COLS = 3; // columns +// define the symbols on the buttons of the keypads +char keys[ROWS][COLS] = { + {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'}}; +byte rowPins[ROWS] = {R1, R2, R3, + R4}; // connect to the row pinouts of the keypad +byte colPins[COLS] = {C1, C2, C3}; // connect to the column pinouts of the + // keypad +#endif + +#if defined(KEYPAD_PID1332) +const byte ROWS = 1; // rows +const byte COLS = 4; // columns +// define the symbols on the buttons of the keypads +char keys[ROWS][COLS] = { + {'1', '2', '3', '4'}, +}; +byte rowPins[ROWS] = {R1}; // connect to the row pinouts of the keypad +byte colPins[COLS] = {C1, C2, C3, + C4}; // connect to the column pinouts of the keypad +#endif + +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_test/keypad_test.ino b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_test/keypad_test.ino new file mode 100644 index 0000000..2551e2e --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/keypad_test/keypad_test.ino @@ -0,0 +1,47 @@ +// Use this example with the Adafruit Keypad products. +// You'll need to know the Product ID for your keypad. +// Here's a summary: +// * PID3844 4x4 Matrix Keypad +// * PID3845 3x4 Matrix Keypad +// * PID1824 3x4 Phone-style Matrix Keypad +// * PID1332 Membrane 1x4 Keypad +// * PID419 Membrane 3x4 Matrix Keypad + +#include "Adafruit_Keypad.h" + +// define your specific keypad here via PID +#define KEYPAD_PID3844 +// define your pins here +// can ignore ones that don't apply +#define R1 2 +#define R2 3 +#define R3 4 +#define R4 5 +#define C1 8 +#define C2 9 +#define C3 10 +#define C4 11 +// leave this import after the above configuration +#include "keypad_config.h" + +//initialize an instance of class NewKeypad +Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); + +void setup() { + Serial.begin(9600); + customKeypad.begin(); +} + +void loop() { + // put your main code here, to run repeatedly: + customKeypad.tick(); + + while(customKeypad.available()){ + keypadEvent e = customKeypad.read(); + Serial.print((char)e.bit.KEY); + if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed"); + else if(e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released"); + } + + delay(10); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/trellis_keypad_test/trellis_keypad_test.ino b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/trellis_keypad_test/trellis_keypad_test.ino new file mode 100644 index 0000000..81ebb33 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/examples/trellis_keypad_test/trellis_keypad_test.ino @@ -0,0 +1,36 @@ +#include "Adafruit_Keypad.h" + +const byte ROWS = 4; // four rows +const byte COLS = 8; // eight columns +//define the symbols on the buttons of the keypads +byte trellisKeys[ROWS][COLS] = { + {1, 2, 3, 4, 5, 6, 7, 8}, + {9, 10, 11, 12, 13, 14, 15, 16}, + {17, 18, 19, 20, 21, 22, 23, 24}, + {25, 26, 27, 28, 29, 30, 31, 32} +}; +byte rowPins[ROWS] = {14, 15, 16, 17}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {2, 3, 4, 5, 6, 7, 8, 9}; //connect to the column pinouts of the keypad + +//initialize an instance of class NewKeypad +Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(trellisKeys), rowPins, colPins, ROWS, COLS); + +void setup() { + Serial.begin(115200); + customKeypad.begin(); + +} + +void loop() { + // put your main code here, to run repeatedly: + customKeypad.tick(); + + while(customKeypad.available()){ + keypadEvent e = customKeypad.read(); + Serial.print((int)e.bit.KEY); + if(e.bit.EVENT == KEY_JUST_PRESSED) Serial.println(" pressed"); + else if(e.bit.EVENT == KEY_JUST_RELEASED) Serial.println(" released"); + } + + delay(10); +} diff --git a/maddius/maddius_matrix_control/components/Adafruit_Keypad/library.properties b/maddius/maddius_matrix_control/components/Adafruit_Keypad/library.properties new file mode 100644 index 0000000..caf40e8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/Adafruit_Keypad/library.properties @@ -0,0 +1,10 @@ +name=Adafruit Keypad +version=1.3.2 +author=Adafruit +maintainer=Adafruit +sentence=Diode-multiplexed keypad support for Arduino +paragraph=Diode-multiplexed keypad support for Arduino +category=Signal Input/Output +url=https://github.com/adafruit/Adafruit_Keypad +architectures=* +depends=Adafruit NeoPixel diff --git a/maddius/maddius_matrix_control/components/ESPRotary/CMakeLists.txt b/maddius/maddius_matrix_control/components/ESPRotary/CMakeLists.txt new file mode 100644 index 0000000..e5725e3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/ESPRotary/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.5) +idf_component_register(SRCS "ESPRotary.cpp" + REQUIRES "arduino-esp32" "spi_flash" "esp_partition" + INCLUDE_DIRS ".") +project(ESPRotary) \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/ESPRotary/ESPRotary.cpp b/maddius/maddius_matrix_control/components/ESPRotary/ESPRotary.cpp new file mode 100644 index 0000000..345bbbb --- /dev/null +++ b/maddius/maddius_matrix_control/components/ESPRotary/ESPRotary.cpp @@ -0,0 +1,435 @@ +///////////////////////////////////////////////////////////////// +/* + ESP8266/Arduino Library for reading rotary encoder values. + Copyright 2017-2022 Lennart Hennigs. +*/ +///////////////////////////////////////////////////////////////// + +#include "ESPRotary.h" + +///////////////////////////////////////////////////////////////// +// initialize static counter + +int ESPRotary::_nextID = 0; + +///////////////////////////////////////////////////////////////// + +void ESPRotary::_setID() +{ + id = _nextID; + _nextID++; +} + +///////////////////////////////////////////////////////////////// + +ESPRotary::ESPRotary() +{ + _setID(); +} + +///////////////////////////////////////////////////////////////// + +ESPRotary::ESPRotary(byte pin1, byte pin2, byte steps_per_click /* = 1 */, int lower_bound /* = INT16_MIN */, int upper_bound /* = INT16_MAX */, int inital_pos /* = 0 */, int increment /* = 1 */) +{ + ESPRotary(); + begin(pin1, pin2, steps_per_click, lower_bound, upper_bound, inital_pos, increment); +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::begin(byte pin1, byte pin2, byte steps_per_click /* = 1 */, int lower_bound /* = INT16_MIN */, int upper_bound /* = INT16_MAX */, int inital_pos /* = 0 */, int increment /* = 1 */) +{ + this->pin1 = pin1; + this->pin2 = pin2; + pinMode(pin1, INPUT_PULLUP); + pinMode(pin2, INPUT_PULLUP); + + setUpperBound(upper_bound); + setLowerBound(lower_bound); + setIncrement(increment); + setStepsPerClick(steps_per_click); + + loop(); + steps = inital_pos * steps_per_click; + last_event = rotary_event::none; + dir = rotary_direction::undefined; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setUpperBound(int upper) +{ + upper_bound = (lower_bound < upper) ? upper : lower_bound; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setLowerBound(int lower) +{ + lower_bound = (lower < upper_bound) ? lower : upper_bound; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getUpperBound() const +{ + return upper_bound; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getLowerBound() const +{ + return lower_bound; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setChangedHandler(CallbackFunction f) +{ + change_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setRightRotationHandler(CallbackFunction f) +{ + right_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setLeftRotationHandler(CallbackFunction f) +{ + left_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setUpperOverflowHandler(CallbackFunction f) +{ + upper_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setLowerOverflowHandler(CallbackFunction f) +{ + lower_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setSpeedupStartedHandler(CallbackFunction f) +{ + speedup_start_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setSpeedupEndedHandler(CallbackFunction f) +{ + speedup_end_cb = f; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::resetPosition(int p /* = 0 */, bool fireCallback /* = true */) +{ + // change position? + if (p == getPosition()) + return; + // yes... + steps = p * steps_per_click; + _isWithinBounds(); + if (fireCallback) + _callCallback(change_cb); + last_event = rotary_event::none; + dir = rotary_direction::undefined; + in_speedup = false; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setIncrement(int increment) +{ + this->increment = increment; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getIncrement() const +{ + return increment; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setStepsPerClick(int steps) +{ + steps_per_click = (steps < 1) ? 1 : steps; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getStepsPerClick() const +{ + return steps_per_click; +} + +///////////////////////////////////////////////////////////////// + +rotary_direction ESPRotary::getDirection() const +{ + return dir; +} + +///////////////////////////////////////////////////////////////// + +String ESPRotary::directionToString(rotary_direction dir) const +{ + return (dir == rotary_direction::right) ? "right" : "left"; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getPosition() const +{ + return steps / steps_per_click; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getID() const +{ + return id; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setID(int newID) +{ + id = newID; +} + +///////////////////////////////////////////////////////////////// + +bool ESPRotary::operator==(ESPRotary &rhs) +{ + return (this == &rhs); +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::loop() +{ + unsigned long now = millis(); + // did it change (enough)? + if (!_wasRotated()) + return; + dir = (steps > last_steps) ? rotary_direction::right : rotary_direction::left; + // shall I speedup things + if (enable_speedup) + _checkForSpeedup(now); + // are we out of bounds? + if (_isWithinBounds(true)) + { + // trigger rotation event + _setEvent((dir == rotary_direction::right) ? rotary_event::right_rotation : rotary_event::left_rotation); + last_turn = now; + } + last_steps = steps; +} + +///////////////////////////////////////////////////////////////// + +bool ESPRotary::_wasRotated() +{ + static const int8_t factors[] = {0, 1, -1, 2, -1, 0, -2, 1, 1, -2, 0, -1, 2, -1, 1, 0}; + int encoderState = (state & 3) | digitalRead(pin1) << 2 | digitalRead(pin2) << 3; + steps += factors[encoderState] * increment; + state = (encoderState >> 2); + int stepDifference = abs(steps - last_steps); + return stepDifference >= (steps_per_click * increment); +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::_checkForSpeedup(unsigned long now) +{ + if (now - last_turn > speedup_interval) + { + if (in_speedup) + _setEvent(rotary_event::speedup_ended); + return; + } + steps += ((dir == rotary_direction::right ? 1 : -1) * (speedup_increment - increment) * steps_per_click); + int pos = getPosition(); + // only trigger speedup when you are not "on a wall" + if (pos > lower_bound && pos < upper_bound) + { + if (!in_speedup) + _setEvent(rotary_event::speedup_started); + } +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::triggerOnBounds(bool triggerEvents /* = true */) +{ + boundsTrigger = triggerEvents; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::_callCallback(CallbackFunction callback) +{ + if (callback != NULL) + callback(*this); +} + +///////////////////////////////////////////////////////////////// + +bool ESPRotary::_isWithinBounds(bool triggerAlerts /* = false */) +{ + int pos = getPosition(); + if (pos > lower_bound && pos < upper_bound) + return true; + + if (pos >= upper_bound) + { + steps = upper_bound * steps_per_click; + if (in_speedup) + _setEvent(rotary_event::speedup_ended); + if (triggerAlerts) + _setEvent(rotary_event::upper_bound_hit); + } + else if (pos <= lower_bound) + { + steps = lower_bound * steps_per_click; + if (in_speedup) + _setEvent(rotary_event::speedup_ended); + if (triggerAlerts) + _setEvent(rotary_event::lower_bound_hit); + } + + return false; +} +///////////////////////////////////////////////////////////////// + +void ESPRotary::_setEvent(rotary_event event) +{ + switch (event) + { + case rotary_event::left_rotation: + _callCallback(left_cb); + _callCallback(change_cb); + break; + + case rotary_event::right_rotation: + _callCallback(right_cb); + _callCallback(change_cb); + break; + + case rotary_event::speedup_started: + _callCallback(speedup_start_cb); + in_speedup = true; + break; + + case rotary_event::speedup_ended: + _callCallback(speedup_end_cb); + in_speedup = false; + break; + + case rotary_event::upper_bound_hit: + if (last_event == rotary_event::upper_bound_hit && !retrigger_event) + return; + if (boundsTrigger) + { + _callCallback(right_cb); + _callCallback(change_cb); + } + _callCallback(upper_cb); + break; + + case rotary_event::lower_bound_hit: + if (last_event == rotary_event::lower_bound_hit && !retrigger_event) + return; + if (boundsTrigger) + { + _callCallback(left_cb); + _callCallback(change_cb); + } + _callCallback(lower_cb); + break; + + case rotary_event::none: + break; + } + last_event = event; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setSpeedupInterval(int interval) +{ + speedup_interval = interval; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getSpeedupInterval() const +{ + return speedup_interval; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::setSpeedupIncrement(int increment) +{ + speedup_increment = increment; +} + +///////////////////////////////////////////////////////////////// + +int ESPRotary::getSpeedupIncrement() const +{ + return speedup_increment; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::enableSpeedup(bool enable) +{ + enable_speedup = enable; +} + +///////////////////////////////////////////////////////////////// + +bool ESPRotary::isSpeedupEnabled() const +{ + return enable_speedup; +} + +///////////////////////////////////////////////////////////////// + +rotary_event ESPRotary::getLastEvent() const +{ + return last_event; +} + +///////////////////////////////////////////////////////////////// + +void ESPRotary::retriggerEvent(bool retrigger) +{ + retrigger_event = retrigger; +} + +///////////////////////////////////////////////////////////////// + +bool ESPRotary::isInSpeedup() const +{ + return in_speedup; +} + +///////////////////////////////////////////////////////////////// diff --git a/maddius/maddius_matrix_control/components/ESPRotary/ESPRotary.h b/maddius/maddius_matrix_control/components/ESPRotary/ESPRotary.h new file mode 100644 index 0000000..017f621 --- /dev/null +++ b/maddius/maddius_matrix_control/components/ESPRotary/ESPRotary.h @@ -0,0 +1,136 @@ +///////////////////////////////////////////////////////////////// +/* + ESP8266/Arduino Library for reading rotary encoder values. + Copyright 2017-2022 Lennart Hennigs +*/ +///////////////////////////////////////////////////////////////// +#pragma once + +#ifndef ESPRotary_h +#define ESPRotary_h + +///////////////////////////////////////////////////////////////// + +#include "Arduino.h" + +///////////////////////////////////////////////////////////////// + +enum class rotary_direction +{ + undefined = 0, + right = 1, + left = 255 +}; + +enum class rotary_event +{ + left_rotation, + right_rotation, + speedup_started, + speedup_ended, + upper_bound_hit, + lower_bound_hit, + none +}; + +///////////////////////////////////////////////////////////////// + +class ESPRotary +{ +protected: + int id; + byte pin1, pin2; + byte steps_per_click; + int lower_bound; + int upper_bound; + byte state; + int increment; + int steps = 0; + int last_steps = 0; + rotary_event last_event; + rotary_direction dir; + + bool boundsTrigger = true; + bool retrigger_event = true; + bool enable_speedup = false; + unsigned int speedup_increment = 5; + unsigned int speedup_interval = 75; + int in_speedup = false; + unsigned long last_turn = 0; + + using CallbackFunction = void (*)(ESPRotary &); + + CallbackFunction change_cb = NULL; + CallbackFunction right_cb = NULL; + CallbackFunction left_cb = NULL; + CallbackFunction lower_cb = NULL; + CallbackFunction upper_cb = NULL; + + CallbackFunction speedup_start_cb = NULL; + CallbackFunction speedup_end_cb = NULL; + +public: + ESPRotary(); + ESPRotary(byte pin1, byte pin2, byte steps_per_click = 1, int lower_bound = INT16_MIN, int upper_bound = INT16_MAX, int inital_pos = 0, int increment = 1); + + void begin(byte pin1, byte pin2, byte steps_per_click = 1, int lower_bound = INT16_MIN, int upper_bound = INT16_MAX, int inital_pos = 0, int increment = 1); + + int getPosition() const; + void resetPosition(int p = 0, bool fireCallback = true); + + void triggerOnBounds(bool triggerEvents = true); + rotary_direction getDirection() const; + String directionToString(rotary_direction dir) const; + + void setIncrement(int increment); + int getIncrement() const; + + void enableSpeedup(bool enable); + void setSpeedupInterval(int interval); + void setSpeedupIncrement(int increment); + + bool isSpeedupEnabled() const; + int getSpeedupInterval() const; + int getSpeedupIncrement() const; + bool isInSpeedup() const; + + rotary_event getLastEvent() const; + void retriggerEvent(bool retrigger); + + void setUpperBound(int upper_bound); + void setLowerBound(int lower_bound); + int getUpperBound() const; + int getLowerBound() const; + + void setStepsPerClick(int steps); + int getStepsPerClick() const; + + void setChangedHandler(CallbackFunction f); + void setRightRotationHandler(CallbackFunction f); + void setLeftRotationHandler(CallbackFunction f); + void setUpperOverflowHandler(CallbackFunction f); + void setLowerOverflowHandler(CallbackFunction f); + void setSpeedupStartedHandler(CallbackFunction f); + void setSpeedupEndedHandler(CallbackFunction f); + + int getID() const; + void setID(int newID); + + bool operator==(ESPRotary &rhs); + + void loop(); + +private: + static int _nextID; + + void _callCallback(CallbackFunction callback); + void _setEvent(rotary_event e); + bool _wasRotated(); + bool _isWithinBounds(bool triggerAlerts = false); + void _checkForSpeedup(unsigned long now); + void _setID(); +}; + +///////////////////////////////////////////////////////////////// +#endif +///////////////////////////////////////////////////////////////// diff --git a/maddius/maddius_matrix_control/components/esp_lan/CMakeLists.txt b/maddius/maddius_matrix_control/components/esp_lan/CMakeLists.txt new file mode 100644 index 0000000..47ebcf6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_lan/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.5) +idf_component_register(SRCS "esp_lan.c" + PRIV_REQUIRES esp_netif driver esp_wifi vfs + INCLUDE_DIRS ".") +project(esp_lan) \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_lan/esp_lan.c b/maddius/maddius_matrix_control/components/esp_lan/esp_lan.c new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/esp_lan/esp_lan.h b/maddius/maddius_matrix_control/components/esp_lan/esp_lan.h new file mode 100644 index 0000000..1621590 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_lan/esp_lan.h @@ -0,0 +1,51 @@ +#include +#include +#ifdef __cplusplus +extern "C" +{ +#endif + typedef enum + { + W5500, + DM9051 + } lan_eth_driver; + + typedef struct + { + bool enabled; + uint16_t reset_io; + uint16_t miso_io; + uint16_t mosi_io; + uint16_t sclk_io; + uint16_t cs_io; + uint16_t phy_addr; + uint16_t spi_host; + uint16_t spi_mhz; + uint16_t stack_size; + uint16_t driver; + } lan_eth_config; + + typedef struct + { + int rssi; + uint16_t authmode; + } wifi_config_threshold; + + typedef struct { + bool enabled; + char *ssid; + char *password; + uint16_t scan_method; + uint16_t sort_method; + struct wifi_config_threshold *threshold; + } wifi_config; + + typedef struct + { + struct lan_eth_config *eth; + struct wifi_config *wifi; + } network_config; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/CMakeLists.txt b/maddius/maddius_matrix_control/components/esp_server/CMakeLists.txt new file mode 100644 index 0000000..7ecb3e5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.5) +# set(COMPONENT_REQUIRES "esp_timer") +# set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) +set(COMPONENT_REQUIRES "protocol_examples_common") +idf_component_register(SRCS "esp_server.c" "keep_alive.c" "udp_server.c" "websocket_client.c" + +REQUIRES "esp_timer" "esp_event" "nvs_flash" "esp_netif" "esp_eth" "esp_wifi" "protocol_examples_common" "esp_https_server" "json_parser" "esp_websocket_client" +INCLUDE_DIRS "." +EMBED_TXTFILES "certs/servercert.pem" + "certs/prvtkey.pem" + "esp_vue/dist/index.html" + "esp_vue/dist/favicon.ico" + "esp_vue/dist/assets/SettingsView.css" + "esp_vue/dist/assets/SettingsView.js" + "esp_vue/dist/assets/index.css" + "esp_vue/dist/assets/index.js") +project(server) \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/Kconfig.projbuild b/maddius/maddius_matrix_control/components/esp_server/Kconfig.projbuild new file mode 100644 index 0000000..eb94293 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/Kconfig.projbuild @@ -0,0 +1,39 @@ +menu "Example Configuration" + + config EXAMPLE_IPV4 + bool "IPV4" + default y + + config EXAMPLE_IPV6 + bool "IPV6" + default n + select EXAMPLE_CONNECT_IPV6 + + config EXAMPLE_PORT + int "Port" + range 0 65535 + default 9003 + help + Local port the example server will listen on. + + choice WEBSOCKET_URI_SOURCE + prompt "Websocket URI source" + default WEBSOCKET_URI_FROM_STRING + help + Selects the source of the URI used in the example. + + config WEBSOCKET_URI_FROM_STRING + bool "From string" + + config WEBSOCKET_URI_FROM_STDIN + bool "From stdin" + endchoice + + config WEBSOCKET_URI + string "Websocket endpoint URI" + depends on WEBSOCKET_URI_FROM_STRING + default "ws://localhost:9999/qlcplusWS" + help + URL of websocket endpoint this example connects to and sends echo + +endmenu \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/certs/prvtkey.pem b/maddius/maddius_matrix_control/components/esp_server/certs/prvtkey.pem new file mode 100644 index 0000000..70d2907 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/certs/prvtkey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH +JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw +h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT +aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al +3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg +0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB +vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui +f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9 +Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y +JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX +49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc ++3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6 +pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D +0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG +YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV +MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL +CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin +7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1 +noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8 +4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g +Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/ +nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3 +q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2 +lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB +jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr +v/t+MeGJP/0Zw8v/X2CFll96 +-----END PRIVATE KEY----- diff --git a/maddius/maddius_matrix_control/components/esp_server/certs/servercert.pem b/maddius/maddius_matrix_control/components/esp_server/certs/servercert.pem new file mode 100644 index 0000000..cd2b80c --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/certs/servercert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL +BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx +MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ +UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T +sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k +qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd +GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4 +sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb +jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/ +ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3 +emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY +W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx +bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN +ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl +hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo= +-----END CERTIFICATE----- diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_server.c b/maddius/maddius_matrix_control/components/esp_server/esp_server.c new file mode 100644 index 0000000..26b6605 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_server.c @@ -0,0 +1,559 @@ +/* Simple HTTP + SSL + WS Server Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include +#include "esp_netif.h" +#include "esp_eth.h" +#include "esp_wifi.h" +#include "protocol_examples_common.h" +#include "lwip/sockets.h" +#include +#include "keep_alive.h" +#include "sdkconfig.h" +#include "json_parser.h" + +#if !CONFIG_HTTPD_WS_SUPPORT +#error This example cannot be used unless HTTPD_WS_SUPPORT is enabled in esp-http-server component configuration +#endif + +struct async_resp_arg +{ + httpd_handle_t hd; + int fd; +}; + +static const char *TAG_SERVER = "wss_echo_server"; +static const size_t max_clients = 4; +/* An HTTP GET handler */ +extern const uint8_t file_index_html_start[] asm("_binary_index_html_start"); +// extern const uint8_t file_index_html_end[] asm("_binary_index_html_end"); +// static esp_err_t index_html_handler(httpd_req_t *req) +// { +// httpd_resp_set_type(req, "text/html"); +// httpd_resp_send(req, (char *)file_index_html_start, HTTPD_RESP_USE_STRLEN); +// return ESP_OK; +// } + +// static const httpd_uri_t index_html = { +// .uri = "/", +// .method = HTTP_GET, +// .handler = index_html_handler}; +httpd_handle_t *gserver = NULL; + +int parse_json(char *payload, int length) +{ + jparse_ctx_t jctx; + int ret = json_parse_start(&jctx, payload, length); + if (ret != OS_SUCCESS) + { + printf("Parser failed\n"); + return -1; + } + int bf00, bf01; + + if (json_obj_get_object(&jctx, "controls") == OS_SUCCESS) + { + printf("Found controls\n"); + if (json_obj_get_int(&jctx, "bf00", &bf00) == OS_SUCCESS) + printf("bf00 %d\n", bf00); + if (json_obj_get_int(&jctx, "bf01", &bf01) == OS_SUCCESS) + printf("bf01 %d\n", bf01); + json_obj_leave_object(&jctx); + } + + // char str_val[64]; + // int int_val, num_elem; + // int64_t int64_val; + // bool bool_val; + // float float_val; + + // if (json_obj_get_string(&jctx, "str_val", str_val, sizeof(str_val)) == OS_SUCCESS) + // printf("str_val %s\n", str_val); + + // if (json_obj_get_float(&jctx, "float_val", &float_val) == OS_SUCCESS) + // printf("float_val %f\n", float_val); + + // if (json_obj_get_int(&jctx, "int_val", &int_val) == OS_SUCCESS) + // printf("int_val %d\n", int_val); + + // if (json_obj_get_bool(&jctx, "bool_val", &bool_val) == OS_SUCCESS) + // printf("bool_val %s\n", bool_val ? "true" : "false"); + + // if (json_obj_get_array(&jctx, "supported_el", &num_elem) == OS_SUCCESS) + // { + // printf("Array has %d elements\n", num_elem); + // int i; + // for (i = 0; i < num_elem; i++) + // { + // json_arr_get_string(&jctx, i, str_val, sizeof(str_val)); + // printf("index %d: %s\n", i, str_val); + // } + // json_obj_leave_array(&jctx); + // } + // if (json_obj_get_object(&jctx, "features") == OS_SUCCESS) + // { + // printf("Found object\n"); + // if (json_obj_get_bool(&jctx, "objects", &bool_val) == OS_SUCCESS) + // printf("objects %s\n", bool_val ? "true" : "false"); + // if (json_obj_get_string(&jctx, "arrays", str_val, sizeof(str_val)) == OS_SUCCESS) + // printf("arrays %s\n", str_val); + // json_obj_leave_object(&jctx); + // } + // if (json_obj_get_int64(&jctx, "int_64", &int64_val) == OS_SUCCESS) + // printf("int64_val %lld\n", int64_val); + + json_parse_end(&jctx); + return 0; +} + +static esp_err_t all_to_index_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "text/html"); + httpd_resp_send(req, (char *)file_index_html_start, HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +static const httpd_uri_t all_to_index = { + .uri = "*", + .method = HTTP_GET, + .handler = all_to_index_handler}; + +extern const uint8_t file_favicon_ico_start[] asm("_binary_favicon_ico_start"); +static esp_err_t favicon_ico_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "image/x-icon"); + httpd_resp_send(req, (char *)file_favicon_ico_start, HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +static const httpd_uri_t favicon_ico = { + .uri = "/favicon.ico", + .method = HTTP_GET, + .handler = favicon_ico_handler}; + +extern const uint8_t file_SettingsView_css_start[] asm("_binary_SettingsView_css_start"); +static esp_err_t SettingsView_css_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "text/css"); + httpd_resp_send(req, (char *)file_SettingsView_css_start, HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +static const httpd_uri_t SettingsView_css = { + .uri = "/assets/SettingsView.css", + .method = HTTP_GET, + .handler = SettingsView_css_handler}; + +// +extern const uint8_t file_SettingsView_js_start[] asm("_binary_SettingsView_js_start"); // application/javascript +static esp_err_t SettingsView_js_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "application/javascript"); + httpd_resp_send(req, (char *)file_SettingsView_js_start, HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +static const httpd_uri_t SettingsView_js = { + .uri = "/assets/SettingsView.js", + .method = HTTP_GET, + .handler = SettingsView_js_handler}; +// +extern const uint8_t file_index_css_start[] asm("_binary_index_css_start"); +static esp_err_t index_css_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "text/css"); + httpd_resp_send(req, (char *)file_index_css_start, HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +static const httpd_uri_t index_css = { + .uri = "/assets/index.css", + .method = HTTP_GET, + .handler = index_css_handler}; +// +extern const uint8_t file_index_js_start[] asm("_binary_index_js_start"); +static esp_err_t index_js_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "application/javascript"); + httpd_resp_send(req, (char *)file_index_js_start, HTTPD_RESP_USE_STRLEN); + return ESP_OK; +} +static const httpd_uri_t index_js = { + .uri = "/assets/index.js", + .method = HTTP_GET, + .handler = index_js_handler}; +// +// extern const uint8_t file_logo_svg_start[] asm("_binary_logo_svg_start"); +// static esp_err_t logo_svg_handler(httpd_req_t *req) +// { +// httpd_resp_set_type(req, "image/svg"); +// httpd_resp_send(req, (char *)file_logo_svg_start, HTTPD_RESP_USE_STRLEN); +// return ESP_OK; +// } +// static const httpd_uri_t logo_svg = { +// .uri = "/assets/logo.svg", +// .method = HTTP_GET, +// .handler = logo_svg_handler}; + +static void send_hello(void *arg) +{ + static const char *data = "Hello client"; + struct async_resp_arg *resp_arg = arg; + httpd_handle_t hd = resp_arg->hd; + int fd = resp_arg->fd; + httpd_ws_frame_t ws_pkt; + memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t)); + ws_pkt.payload = (uint8_t *)data; + ws_pkt.len = strlen(data); + ws_pkt.type = HTTPD_WS_TYPE_TEXT; + + httpd_ws_send_frame_async(hd, fd, &ws_pkt); + free(resp_arg); +} +static esp_err_t ws_handler(httpd_req_t *req) +{ + if (req->method == HTTP_GET) + { + ESP_LOGI(TAG_SERVER, "Handshake done, the new connection was opened"); + return ESP_OK; + } + httpd_ws_frame_t ws_pkt; + uint8_t *buf = NULL; + memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t)); + + // First receive the full ws message + /* Set max_len = 0 to get the frame len */ + esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, 0); + if (ret != ESP_OK) + { + ESP_LOGE(TAG_SERVER, "httpd_ws_recv_frame failed to get frame len with %d", ret); + return ret; + } + ESP_LOGI(TAG_SERVER, "frame len is %d", ws_pkt.len); + if (ws_pkt.len) + { + /* ws_pkt.len + 1 is for NULL termination as we are expecting a string */ + buf = calloc(1, ws_pkt.len + 1); + if (buf == NULL) + { + ESP_LOGE(TAG_SERVER, "Failed to calloc memory for buf"); + return ESP_ERR_NO_MEM; + } + ws_pkt.payload = buf; + /* Set max_len = ws_pkt.len to get the frame payload */ + ret = httpd_ws_recv_frame(req, &ws_pkt, ws_pkt.len); + if (ret != ESP_OK) + { + ESP_LOGE(TAG_SERVER, "httpd_ws_recv_frame failed with %d", ret); + free(buf); + return ret; + } + } + // If it was a PONG, update the keep-alive + if (ws_pkt.type == HTTPD_WS_TYPE_PONG) + { + ESP_LOGD(TAG_SERVER, "Received PONG message"); + free(buf); + return wss_keep_alive_client_is_active(httpd_get_global_user_ctx(req->handle), + httpd_req_to_sockfd(req)); + + // If it was a TEXT message, just echo it back + } + else if (ws_pkt.type == HTTPD_WS_TYPE_TEXT || ws_pkt.type == HTTPD_WS_TYPE_PING || ws_pkt.type == HTTPD_WS_TYPE_CLOSE) + { + if (ws_pkt.type == HTTPD_WS_TYPE_TEXT) + { + ESP_LOGI(TAG_SERVER, "Received packet with message: %s", ws_pkt.payload); + parse_json((char *)ws_pkt.payload, strlen((char *)ws_pkt.payload)); + if (*gserver) + { // httpd might not have been created by now + size_t clients = max_clients; + int client_fds[max_clients]; + if (httpd_get_client_list(*gserver, &clients, client_fds) == ESP_OK) + { + for (size_t i = 0; i < clients; ++i) + { + int sock = client_fds[i]; + if (httpd_ws_get_fd_info(*gserver, sock) == HTTPD_WS_CLIENT_WEBSOCKET) + { + ESP_LOGI(TAG_SERVER, "Active client (fd=%d) -> sending async message", sock); + // struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); + // resp_arg->hd = *gserver; + // resp_arg->fd = sock; + // if (httpd_queue_work(resp_arg->hd, send_hello, resp_arg) != ESP_OK) + // { + // ESP_LOGE(TAG_SERVER, "httpd_queue_work failed!"); + // // send_messages = false; + // break; + // } + } + } + } + else + { + ESP_LOGE(TAG_SERVER, "httpd_get_client_list failed!"); + } + } + } + else if (ws_pkt.type == HTTPD_WS_TYPE_PING) + { + // Response PONG packet to peer + ESP_LOGI(TAG_SERVER, "Got a WS PING frame, Replying PONG"); + ws_pkt.type = HTTPD_WS_TYPE_PONG; + } + else if (ws_pkt.type == HTTPD_WS_TYPE_CLOSE) + { + // Response CLOSE packet with no payload to peer + ws_pkt.len = 0; + ws_pkt.payload = NULL; + } + ret = httpd_ws_send_frame(req, &ws_pkt); + if (ret != ESP_OK) + { + ESP_LOGE(TAG_SERVER, "httpd_ws_send_frame failed with %d", ret); + } + ESP_LOGI(TAG_SERVER, "ws_handler: httpd_handle_t=%p, sockfd=%d, client_info:%d", req->handle, + httpd_req_to_sockfd(req), httpd_ws_get_fd_info(req->handle, httpd_req_to_sockfd(req))); + free(buf); + return ret; + } + free(buf); + return ESP_OK; +} + +esp_err_t wss_open_fd(httpd_handle_t hd, int sockfd) +{ + ESP_LOGI(TAG_SERVER, "New client connected %d", sockfd); + wss_keep_alive_t h = httpd_get_global_user_ctx(hd); + return wss_keep_alive_add_client(h, sockfd); +} + +void wss_close_fd(httpd_handle_t hd, int sockfd) +{ + ESP_LOGI(TAG_SERVER, "Client disconnected %d", sockfd); + wss_keep_alive_t h = httpd_get_global_user_ctx(hd); + wss_keep_alive_remove_client(h, sockfd); + close(sockfd); +} + +static const httpd_uri_t ws = { + .uri = "/ws", + .method = HTTP_GET, + .handler = ws_handler, + .user_ctx = NULL, + .is_websocket = true, + .handle_ws_control_frames = true}; + +static void send_ping(void *arg) +{ + struct async_resp_arg *resp_arg = arg; + httpd_handle_t hd = resp_arg->hd; + int fd = resp_arg->fd; + httpd_ws_frame_t ws_pkt; + memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t)); + ws_pkt.payload = NULL; + ws_pkt.len = 0; + ws_pkt.type = HTTPD_WS_TYPE_PING; + + httpd_ws_send_frame_async(hd, fd, &ws_pkt); + free(resp_arg); +} + +bool client_not_alive_cb(wss_keep_alive_t h, int fd) +{ + ESP_LOGE(TAG_SERVER, "Client not alive, closing fd %d", fd); + httpd_sess_trigger_close(wss_keep_alive_get_user_ctx(h), fd); + return true; +} + +bool check_client_alive_cb(wss_keep_alive_t h, int fd) +{ + ESP_LOGD(TAG_SERVER, "Checking if client (fd=%d) is alive", fd); + struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); + resp_arg->hd = wss_keep_alive_get_user_ctx(h); + resp_arg->fd = fd; + + if (httpd_queue_work(resp_arg->hd, send_ping, resp_arg) == ESP_OK) + { + return true; + } + return false; +} + +static httpd_handle_t start_wss_echo_server(void) +{ + // Prepare keep-alive engine + wss_keep_alive_config_t keep_alive_config = KEEP_ALIVE_CONFIG_DEFAULT(); + keep_alive_config.max_clients = max_clients; + keep_alive_config.client_not_alive_cb = client_not_alive_cb; + keep_alive_config.check_client_alive_cb = check_client_alive_cb; + wss_keep_alive_t keep_alive = wss_keep_alive_start(&keep_alive_config); + + // Start the httpd server + httpd_handle_t server = NULL; + ESP_LOGI(TAG_SERVER, "Starting server"); + + httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT(); + conf.transport_mode = HTTPD_SSL_TRANSPORT_INSECURE; + conf.httpd.max_open_sockets = max_clients; + conf.httpd.global_user_ctx = keep_alive; + conf.httpd.open_fn = wss_open_fd; + conf.httpd.close_fn = wss_close_fd; + // wildcard matcher + conf.httpd.uri_match_fn = httpd_uri_match_wildcard; + // Certificates + extern const unsigned char servercert_start[] asm("_binary_servercert_pem_start"); + extern const unsigned char servercert_end[] asm("_binary_servercert_pem_end"); + conf.servercert = servercert_start; + conf.servercert_len = servercert_end - servercert_start; + + extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start"); + extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end"); + conf.prvtkey_pem = prvtkey_pem_start; + conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start; + + esp_err_t ret = httpd_ssl_start(&server, &conf); + if (ESP_OK != ret) + { + ESP_LOGI(TAG_SERVER, "Error starting server!"); + return NULL; + } + + // Set URI handlers + ESP_LOGI(TAG_SERVER, "Registering URI handlers"); + httpd_register_uri_handler(server, &ws); + wss_keep_alive_set_user_ctx(keep_alive, server); + + ESP_LOGI(TAG_SERVER, "Registering site URI handlers"); + // httpd_register_uri_handler(server, &index_html); + httpd_register_uri_handler(server, &SettingsView_css); + httpd_register_uri_handler(server, &SettingsView_js); + + httpd_register_uri_handler(server, &index_css); + // httpd_register_uri_handler(server, &logo_svg); + httpd_register_uri_handler(server, &index_js); + httpd_register_uri_handler(server, &favicon_ico); + + httpd_register_uri_handler(server, &all_to_index); + return server; +} + +static esp_err_t stop_wss_echo_server(httpd_handle_t server) +{ + // Stop keep alive thread + wss_keep_alive_stop(httpd_get_global_user_ctx(server)); + // Stop the httpd server + return httpd_ssl_stop(server); +} + +void disconnect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + httpd_handle_t *server = (httpd_handle_t *)arg; + if (*server) + { + if (stop_wss_echo_server(*server) == ESP_OK) + { + *server = NULL; + } + else + { + ESP_LOGE(TAG_SERVER, "Failed to stop https server"); + } + } +} + +void connect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + httpd_handle_t *server = (httpd_handle_t *)arg; + ESP_LOGI(TAG_SERVER, "server %i", *server == NULL); + if (*server == NULL) + { + *server = start_wss_echo_server(); + gserver = server; + ESP_LOGI(TAG_SERVER, "start_wss_echo_server started"); + } +} + +// Get all clients and send async message +static void wss_server_send_messages(httpd_handle_t *server) +{ + bool send_messages = true; + + // Send async message to all connected clients that use websocket protocol every 10 seconds + while (send_messages) + { + vTaskDelay(10000 / portTICK_PERIOD_MS); + + if (!*server) + { // httpd might not have been created by now + continue; + } + size_t clients = max_clients; + int client_fds[max_clients]; + if (httpd_get_client_list(*server, &clients, client_fds) == ESP_OK) + { + for (size_t i = 0; i < clients; ++i) + { + int sock = client_fds[i]; + if (httpd_ws_get_fd_info(*server, sock) == HTTPD_WS_CLIENT_WEBSOCKET) + { + ESP_LOGI(TAG_SERVER, "Active client (fd=%d) -> sending async message", sock); + struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); + resp_arg->hd = *server; + resp_arg->fd = sock; + if (httpd_queue_work(resp_arg->hd, send_hello, resp_arg) != ESP_OK) + { + ESP_LOGE(TAG_SERVER, "httpd_queue_work failed!"); + send_messages = false; + break; + } + } + } + } + else + { + ESP_LOGE(TAG_SERVER, "httpd_get_client_list failed!"); + return; + } + } +} + +// void app_main(void) +// { +// static httpd_handle_t server = NULL; + +// ESP_ERROR_CHECK(nvs_flash_init()); +// ESP_ERROR_CHECK(esp_netif_init()); +// ESP_ERROR_CHECK(esp_event_loop_create_default()); + +// /* Register event handlers to start server when Wi-Fi or Ethernet is connected, +// * and stop server when disconnection happens. +// */ + +// #ifdef CONFIG_EXAMPLE_CONNECT_WIFI +// ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server)); +// ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server)); +// #endif // CONFIG_EXAMPLE_CONNECT_WIFI +// #ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET +// ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server)); +// ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server)); +// #endif // CONFIG_EXAMPLE_CONNECT_ETHERNET + +// /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. +// * Read "Establishing Wi-Fi or Ethernet Connection" section in +// * examples/protocols/README.md for more information about this function. +// */ +// ESP_ERROR_CHECK(example_connect()); + +// /* This function demonstrates periodic sending Websocket messages +// * to all connected clients to this server +// */ +// wss_server_send_messages(&server); +// } diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_server.h b/maddius/maddius_matrix_control/components/esp_server/esp_server.h new file mode 100644 index 0000000..aa0875d --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_server.h @@ -0,0 +1,21 @@ +#pragma once + +// #include "lwip/sys.h" +// #include +// #include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + void disconnect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data); + + void connect_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/.eslintrc.cjs b/maddius/maddius_matrix_control/components/esp_server/esp_vue/.eslintrc.cjs new file mode 100644 index 0000000..6f40582 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/.eslintrc.cjs @@ -0,0 +1,15 @@ +/* eslint-env node */ +require('@rushstack/eslint-patch/modern-module-resolution') + +module.exports = { + root: true, + 'extends': [ + 'plugin:vue/vue3-essential', + 'eslint:recommended', + '@vue/eslint-config-typescript', + '@vue/eslint-config-prettier/skip-formatting' + ], + parserOptions: { + ecmaVersion: 'latest' + } +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/.gitignore b/maddius/maddius_matrix_control/components/esp_server/esp_vue/.gitignore new file mode 100644 index 0000000..38adffa --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/.prettierrc.json b/maddius/maddius_matrix_control/components/esp_server/esp_vue/.prettierrc.json new file mode 100644 index 0000000..66e2335 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none" +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/README.md b/maddius/maddius_matrix_control/components/esp_server/esp_vue/README.md new file mode 100644 index 0000000..75bbd43 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/README.md @@ -0,0 +1,46 @@ +# esp-vue + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types. + +If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps: + +1. Disable the built-in TypeScript Extension + 1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette + 2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)` +2. Reload the VSCode window by running `Developer: Reload Window` from the command palette. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/env.d.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/index.html b/maddius/maddius_matrix_control/components/esp_server/esp_vue/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/package-lock.json b/maddius/maddius_matrix_control/components/esp_server/esp_vue/package-lock.json new file mode 100644 index 0000000..1cb22ad --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/package-lock.json @@ -0,0 +1,7973 @@ +{ + "name": "esp-vue", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "esp-vue", + "version": "0.0.0", + "dependencies": { + "@kyvg/vue3-notification": "^3.0.2", + "pinia": "^2.1.6", + "vue": "^3.3.4", + "vue-router": "^4.2.4" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.3.3", + "@tsconfig/node18": "^18.2.2", + "@types/node": "^18.18.7", + "@vitejs/plugin-vue": "^4.3.4", + "@vitejs/plugin-vue-jsx": "^3.0.2", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/tsconfig": "^0.4.0", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "naive-ui": "^2.35.0", + "npm-run-all2": "^6.0.6", + "prettier": "^3.0.3", + "typescript": "~5.2.0", + "vfonts": "^0.0.3", + "vite": "^4.4.9", + "vue-tsc": "^1.8.11" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.15.tgz", + "integrity": "sha512-1uirS0TnijxvQLnlv5wQBwOX3E1wCFX7ITv+9pBV2wKEk4K+M5tqDaoNXnTH8tjEIYHLO98MwiTWO04Ggz4XuA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@css-render/plugin-bem": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@css-render/plugin-bem/-/plugin-bem-0.15.12.tgz", + "integrity": "sha512-Lq2jSOZn+wYQtsyaFj6QRz2EzAnd3iW5fZeHO1WSXQdVYwvwGX0ZiH3X2JQgtgYLT1yeGtrwrqJdNdMEUD2xTw==", + "dev": true, + "peerDependencies": { + "css-render": "~0.15.12" + } + }, + "node_modules/@css-render/vue3-ssr": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@css-render/vue3-ssr/-/vue3-ssr-0.15.12.tgz", + "integrity": "sha512-AQLGhhaE0F+rwybRCkKUdzBdTEM/5PZBYy+fSYe1T9z9+yxMuV/k7ZRqa4M69X+EI1W8pa4kc9Iq2VjQkZx4rg==", + "dev": true, + "peerDependencies": { + "vue": "^3.0.11" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", + "dev": true + }, + "node_modules/@kyvg/vue3-notification": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@kyvg/vue3-notification/-/vue3-notification-3.0.2.tgz", + "integrity": "sha512-t6PWPWggVqehX0BJZbqOttfKe3oUOrkgYoNQWSx8gwz8+pIRygQNT5MrewaIATdiU3bf//Yyto/wEm7vYl17Uw==", + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz", + "integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==", + "dev": true + }, + "node_modules/@tsconfig/node18": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", + "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "dev": true + }, + "node_modules/@types/katex": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.5.tgz", + "integrity": "sha512-DD2Y3xMlTQvAnN6d8803xdgnOeYZ+HwMglb7/9YCf49J9RkJL53azf9qKa40MkEYhqVwxZ1GS2+VlShnz4Z1Bw==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.200", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz", + "integrity": "sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==", + "dev": true + }, + "node_modules/@types/lodash-es": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.10.tgz", + "integrity": "sha512-YJP+w/2khSBwbUSFdGsSqmDvmnN3cCKoPOL7Zjle6s30ZtemkkqhjVfFqGwPN7ASil5VyjE2GtyU/yqYY6mC0A==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "18.18.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.7.tgz", + "integrity": "sha512-bw+lEsxis6eqJYW8Ql6+yTqkE6RuFtsQPSe5JxXbqYRFQEER5aJA9a5UH9igqDWm3X4iLHIKOHlnAXLM4mi7uQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", + "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", + "integrity": "sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.8.0", + "@typescript-eslint/type-utils": "6.8.0", + "@typescript-eslint/utils": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.8.0.tgz", + "integrity": "sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.8.0", + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz", + "integrity": "sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz", + "integrity": "sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/utils": "6.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.8.0.tgz", + "integrity": "sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz", + "integrity": "sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.8.0.tgz", + "integrity": "sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.8.0", + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/typescript-estree": "6.8.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz", + "integrity": "sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.8.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz", + "integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vitejs/plugin-vue-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-3.0.2.tgz", + "integrity": "sha512-obF26P2Z4Ogy3cPp07B4VaW6rpiu0ue4OT2Y15UxT5BZZ76haUY9guOsZV3uWh/I6xc+VeiW+ZVabRE82FyzWw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.22.10", + "@babel/plugin-transform-typescript": "^7.22.10", + "@vue/babel-plugin-jsx": "^1.1.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0", + "vue": "^3.0.0" + } + }, + "node_modules/@volar/language-core": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.4.tgz", + "integrity": "sha512-Na69qA6uwVIdA0rHuOc2W3pHtVQQO8hCNim7FOaKNpRJh0oAFnu5r9i7Oopo5C4cnELZkPNjTrbmpcCTiW+CMQ==", + "dev": true, + "dependencies": { + "@volar/source-map": "1.10.4" + } + }, + "node_modules/@volar/source-map": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.4.tgz", + "integrity": "sha512-RxZdUEL+pV8p+SMqnhVjzy5zpb1QRZTlcwSk4bdcBO7yOu4rtEWqDGahVCEj4CcXour+0yJUMrMczfSCpP9Uxg==", + "dev": true, + "dependencies": { + "muggle-string": "^0.3.1" + } + }, + "node_modules/@volar/typescript": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.4.tgz", + "integrity": "sha512-BCCUEBASBEMCrz7qmNSi2hBEWYsXD0doaktRKpmmhvb6XntM2sAWYu6gbyK/MluLDgluGLFiFRpWgobgzUqolg==", + "dev": true, + "dependencies": { + "@volar/language-core": "1.10.4" + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.1.5.tgz", + "integrity": "sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==", + "dev": true + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.1.5.tgz", + "integrity": "sha512-nKs1/Bg9U1n3qSWnsHhCVQtAzI6aQXqua8j/bZrau8ywT1ilXQbK4FwEJGmU8fV7tcpuFvWmmN7TMmV1OBma1g==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", + "@vue/babel-helper-vue-transform-on": "^1.1.5", + "camelcase": "^6.3.0", + "html-tags": "^3.3.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz", + "integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==", + "dependencies": { + "@babel/parser": "^7.21.3", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz", + "integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==", + "dependencies": { + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz", + "integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-ssr": "3.3.4", + "@vue/reactivity-transform": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0", + "postcss": "^8.1.10", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz", + "integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==", + "dependencies": { + "@vue/compiler-dom": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", + "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" + }, + "node_modules/@vue/eslint-config-prettier": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-8.0.0.tgz", + "integrity": "sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==", + "dev": true, + "dependencies": { + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^5.0.0" + }, + "peerDependencies": { + "eslint": ">= 8.0.0", + "prettier": ">= 3.0.0" + } + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-12.0.0.tgz", + "integrity": "sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "vue-eslint-parser": "^9.3.1" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0", + "eslint-plugin-vue": "^9.0.0", + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.19.tgz", + "integrity": "sha512-nt3dodGs97UM6fnxeQBazO50yYCKBK53waFWB3qMbLmR6eL3aUryZgQtZoBe1pye17Wl8fs9HysV3si6xMgndQ==", + "dev": true, + "dependencies": { + "@volar/language-core": "~1.10.4", + "@volar/source-map": "~1.10.4", + "@vue/compiler-dom": "^3.3.0", + "@vue/reactivity": "^3.3.0", + "@vue/shared": "^3.3.0", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", + "integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==", + "dependencies": { + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz", + "integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz", + "integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==", + "dependencies": { + "@vue/reactivity": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz", + "integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==", + "dependencies": { + "@vue/runtime-core": "3.3.4", + "@vue/shared": "3.3.4", + "csstype": "^3.1.1" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz", + "integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==", + "dependencies": { + "@vue/compiler-ssr": "3.3.4", + "@vue/shared": "3.3.4" + }, + "peerDependencies": { + "vue": "3.3.4" + } + }, + "node_modules/@vue/shared": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", + "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" + }, + "node_modules/@vue/tsconfig": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.4.0.tgz", + "integrity": "sha512-CPuIReonid9+zOG/CGTT05FXrPYATEqoDGNrEaqS4hwcw5BUNM2FguC0mOwJD4Jr16UpRVl9N0pY3P+srIbqmg==", + "dev": true + }, + "node_modules/@vue/typescript": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@vue/typescript/-/typescript-1.8.19.tgz", + "integrity": "sha512-k/SHeeQROUgqsxyHQ8Cs3Zz5TnX57p7BcBDVYR2E0c61QL2DJ2G8CsaBremmNGuGE6o1R5D50IHIxFmroMz8iw==", + "dev": true, + "dependencies": { + "@volar/typescript": "~1.10.4", + "@vue/language-core": "1.8.19" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001550", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001550.tgz", + "integrity": "sha512-p82WjBYIypO0ukTsd/FG3Xxs+4tFeaY9pfT4amQL8KWtYH7H9nYwReGAbMTJ0hsmRO8IfDtsS6p3ZWj8+1c2RQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-render": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/css-render/-/css-render-0.15.12.tgz", + "integrity": "sha512-eWzS66patiGkTTik+ipO9qNGZ+uNuGyTmnz6/+EJIiFg8+3yZRpnMwgFo8YdXhQRsiePzehnusrxVvugNjXzbw==", + "dev": true, + "dependencies": { + "@emotion/hash": "~0.8.0", + "csstype": "~3.0.5" + } + }, + "node_modules/css-render/node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/date-fns-tz": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-2.0.0.tgz", + "integrity": "sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==", + "dev": true, + "peerDependencies": { + "date-fns": ">=2.0.0" + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.559", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.559.tgz", + "integrity": "sha512-iS7KhLYCSJbdo3rUSkhDTVuFNCV34RKs2UaB9Ecr7VlqzjjWW//0nfsFF5dtDmyXlZQaDYYtID5fjtC/6lpRug==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.51.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.17.0.tgz", + "integrity": "sha512-r7Bp79pxQk9I5XDP0k2dpUC7Ots3OSWgvGZNu3BxmKK6Zg7NgVtcOB6OCna5Kb9oQwJPl5hq183WD0SY5tZtIQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.13", + "semver": "^7.5.4", + "vue-eslint-parser": "^9.3.1", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-vue/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-vue/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/evtd": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/evtd/-/evtd-0.2.4.tgz", + "integrity": "sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==", + "dev": true + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true + }, + "node_modules/naive-ui": { + "version": "2.35.0", + "resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.35.0.tgz", + "integrity": "sha512-PdnLpOip1LQaKs5+rXLZoPDPQkTq26TnHWeABvUA2eOQjtHxE4+TQvj0Jq/W8clM2On/7jptoGmenLt48G3Bhg==", + "dev": true, + "dependencies": { + "@css-render/plugin-bem": "^0.15.12", + "@css-render/vue3-ssr": "^0.15.12", + "@types/katex": "^0.16.2", + "@types/lodash": "^4.14.198", + "@types/lodash-es": "^4.17.9", + "async-validator": "^4.2.5", + "css-render": "^0.15.12", + "date-fns": "^2.30.0", + "date-fns-tz": "^2.0.0", + "evtd": "^0.2.4", + "highlight.js": "^11.8.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "seemly": "^0.3.6", + "treemate": "^0.3.11", + "vdirs": "^0.1.8", + "vooks": "^0.2.12", + "vueuc": "^0.4.51" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/npm-run-all2": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.1.tgz", + "integrity": "sha512-lWLbkPZ5BSdXtN8lR+0rc8caKoPdymycpZksyDEC9MOBvfdwTXZ0uVhb7bMcGeXv2/BKtfQuo6Zn3zfc8rxNXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-pkg": "^8.0.0", + "shell-quote": "^1.7.3" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0", + "npm": ">= 8" + } + }, + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm-run-all2/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-run-all2/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.0.tgz", + "integrity": "sha512-ihtdrgbqdONYD156Ap6qTcaGcGdkdAxodO1wLqQ/j7HP1u2sFYppINiq4jyC8F+Nm+4fVufylCV00QmkTHkSUg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pinia": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz", + "integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/seemly": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.6.tgz", + "integrity": "sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/treemate": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/treemate/-/treemate-0.3.11.tgz", + "integrity": "sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==", + "dev": true + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.5.0.tgz", + "integrity": "sha512-diLQivFzddJl4ylL3jxSkEc39Tpw7o1QeEHIPxVwryDK2lpB7Nqhzhuo6v5/Ls08Z0yPSAhsyAWlv1/H0ciNmw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vdirs": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/vdirs/-/vdirs-0.1.8.tgz", + "integrity": "sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==", + "dev": true, + "dependencies": { + "evtd": "^0.2.2" + }, + "peerDependencies": { + "vue": "^3.0.11" + } + }, + "node_modules/vfonts": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vfonts/-/vfonts-0.0.3.tgz", + "integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==", + "dev": true + }, + "node_modules/vite": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vooks": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/vooks/-/vooks-0.2.12.tgz", + "integrity": "sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==", + "dev": true, + "dependencies": { + "evtd": "^0.2.2" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz", + "integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==", + "dependencies": { + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-sfc": "3.3.4", + "@vue/runtime-dom": "3.3.4", + "@vue/server-renderer": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz", + "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-eslint-parser/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/vue-router": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", + "integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==", + "dependencies": { + "@vue/devtools-api": "^6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.14", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz", + "integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.19.tgz", + "integrity": "sha512-tacMQLQ0CXAfbhRycCL5sWIy1qujXaIEtP1hIQpzHWOUuICbtTj9gJyFf91PvzG5KCNIkA5Eg7k2Fmgt28l5DQ==", + "dev": true, + "dependencies": { + "@vue/language-core": "1.8.19", + "@vue/typescript": "1.8.19", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/vue-tsc/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-tsc/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-tsc/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/vueuc": { + "version": "0.4.51", + "resolved": "https://registry.npmjs.org/vueuc/-/vueuc-0.4.51.tgz", + "integrity": "sha512-pLiMChM4f+W8czlIClGvGBYo656lc2Y0/mXFSCydcSmnCR1izlKPGMgiYBGjbY9FDkFG8a2HEVz7t0DNzBWbDw==", + "dev": true, + "dependencies": { + "@css-render/vue3-ssr": "^0.15.10", + "@juggle/resize-observer": "^3.3.1", + "css-render": "^0.15.10", + "evtd": "^0.2.4", + "seemly": "^0.3.6", + "vdirs": "^0.1.4", + "vooks": "^0.2.4" + }, + "peerDependencies": { + "vue": "^3.0.11" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "dev": true + }, + "@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dev": true, + "requires": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "requires": { + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true + }, + "@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + } + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" + }, + "@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.15.tgz", + "integrity": "sha512-1uirS0TnijxvQLnlv5wQBwOX3E1wCFX7ITv+9pBV2wKEk4K+M5tqDaoNXnTH8tjEIYHLO98MwiTWO04Ggz4XuA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" + } + }, + "@babel/runtime": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@css-render/plugin-bem": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@css-render/plugin-bem/-/plugin-bem-0.15.12.tgz", + "integrity": "sha512-Lq2jSOZn+wYQtsyaFj6QRz2EzAnd3iW5fZeHO1WSXQdVYwvwGX0ZiH3X2JQgtgYLT1yeGtrwrqJdNdMEUD2xTw==", + "dev": true, + "requires": {} + }, + "@css-render/vue3-ssr": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@css-render/vue3-ssr/-/vue3-ssr-0.15.12.tgz", + "integrity": "sha512-AQLGhhaE0F+rwybRCkKUdzBdTEM/5PZBYy+fSYe1T9z9+yxMuV/k7ZRqa4M69X+EI1W8pa4kc9Iq2VjQkZx4rg==", + "dev": true, + "requires": {} + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "dev": true, + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", + "dev": true + }, + "@kyvg/vue3-notification": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@kyvg/vue3-notification/-/vue3-notification-3.0.2.tgz", + "integrity": "sha512-t6PWPWggVqehX0BJZbqOttfKe3oUOrkgYoNQWSx8gwz8+pIRygQNT5MrewaIATdiU3bf//Yyto/wEm7vYl17Uw==", + "requires": {} + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + } + }, + "@rushstack/eslint-patch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz", + "integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==", + "dev": true + }, + "@tsconfig/node18": { + "version": "18.2.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node18/-/node18-18.2.2.tgz", + "integrity": "sha512-d6McJeGsuoRlwWZmVIeE8CUA27lu6jLjvv1JzqmpsytOYYbVi1tHZEnwCNVOXnj4pyLvneZlFlpXUK+X9wBWyw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "dev": true + }, + "@types/katex": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.5.tgz", + "integrity": "sha512-DD2Y3xMlTQvAnN6d8803xdgnOeYZ+HwMglb7/9YCf49J9RkJL53azf9qKa40MkEYhqVwxZ1GS2+VlShnz4Z1Bw==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.200", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz", + "integrity": "sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==", + "dev": true + }, + "@types/lodash-es": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.10.tgz", + "integrity": "sha512-YJP+w/2khSBwbUSFdGsSqmDvmnN3cCKoPOL7Zjle6s30ZtemkkqhjVfFqGwPN7ASil5VyjE2GtyU/yqYY6mC0A==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, + "@types/node": { + "version": "18.18.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.7.tgz", + "integrity": "sha512-bw+lEsxis6eqJYW8Ql6+yTqkE6RuFtsQPSe5JxXbqYRFQEER5aJA9a5UH9igqDWm3X4iLHIKOHlnAXLM4mi7uQ==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/normalize-package-data": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", + "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", + "dev": true + }, + "@types/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", + "integrity": "sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.8.0", + "@typescript-eslint/type-utils": "6.8.0", + "@typescript-eslint/utils": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.8.0.tgz", + "integrity": "sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "6.8.0", + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz", + "integrity": "sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz", + "integrity": "sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/utils": "6.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.8.0.tgz", + "integrity": "sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz", + "integrity": "sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/visitor-keys": "6.8.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.8.0.tgz", + "integrity": "sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.8.0", + "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/typescript-estree": "6.8.0", + "semver": "^7.5.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz", + "integrity": "sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.8.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@vitejs/plugin-vue": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz", + "integrity": "sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==", + "dev": true, + "requires": {} + }, + "@vitejs/plugin-vue-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-3.0.2.tgz", + "integrity": "sha512-obF26P2Z4Ogy3cPp07B4VaW6rpiu0ue4OT2Y15UxT5BZZ76haUY9guOsZV3uWh/I6xc+VeiW+ZVabRE82FyzWw==", + "dev": true, + "requires": { + "@babel/core": "^7.22.10", + "@babel/plugin-transform-typescript": "^7.22.10", + "@vue/babel-plugin-jsx": "^1.1.5" + } + }, + "@volar/language-core": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.10.4.tgz", + "integrity": "sha512-Na69qA6uwVIdA0rHuOc2W3pHtVQQO8hCNim7FOaKNpRJh0oAFnu5r9i7Oopo5C4cnELZkPNjTrbmpcCTiW+CMQ==", + "dev": true, + "requires": { + "@volar/source-map": "1.10.4" + } + }, + "@volar/source-map": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.10.4.tgz", + "integrity": "sha512-RxZdUEL+pV8p+SMqnhVjzy5zpb1QRZTlcwSk4bdcBO7yOu4rtEWqDGahVCEj4CcXour+0yJUMrMczfSCpP9Uxg==", + "dev": true, + "requires": { + "muggle-string": "^0.3.1" + } + }, + "@volar/typescript": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.10.4.tgz", + "integrity": "sha512-BCCUEBASBEMCrz7qmNSi2hBEWYsXD0doaktRKpmmhvb6XntM2sAWYu6gbyK/MluLDgluGLFiFRpWgobgzUqolg==", + "dev": true, + "requires": { + "@volar/language-core": "1.10.4" + } + }, + "@vue/babel-helper-vue-transform-on": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.1.5.tgz", + "integrity": "sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==", + "dev": true + }, + "@vue/babel-plugin-jsx": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.1.5.tgz", + "integrity": "sha512-nKs1/Bg9U1n3qSWnsHhCVQtAzI6aQXqua8j/bZrau8ywT1ilXQbK4FwEJGmU8fV7tcpuFvWmmN7TMmV1OBma1g==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", + "@vue/babel-helper-vue-transform-on": "^1.1.5", + "camelcase": "^6.3.0", + "html-tags": "^3.3.1", + "svg-tags": "^1.0.0" + } + }, + "@vue/compiler-core": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz", + "integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==", + "requires": { + "@babel/parser": "^7.21.3", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "@vue/compiler-dom": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz", + "integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==", + "requires": { + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "@vue/compiler-sfc": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz", + "integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==", + "requires": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-ssr": "3.3.4", + "@vue/reactivity-transform": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0", + "postcss": "^8.1.10", + "source-map-js": "^1.0.2" + } + }, + "@vue/compiler-ssr": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz", + "integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==", + "requires": { + "@vue/compiler-dom": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "@vue/devtools-api": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", + "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" + }, + "@vue/eslint-config-prettier": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-8.0.0.tgz", + "integrity": "sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==", + "dev": true, + "requires": { + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^5.0.0" + } + }, + "@vue/eslint-config-typescript": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-12.0.0.tgz", + "integrity": "sha512-StxLFet2Qe97T8+7L8pGlhYBBr8Eg05LPuTDVopQV6il+SK6qqom59BA/rcFipUef2jD8P2X44Vd8tMFytfvlg==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "vue-eslint-parser": "^9.3.1" + } + }, + "@vue/language-core": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.19.tgz", + "integrity": "sha512-nt3dodGs97UM6fnxeQBazO50yYCKBK53waFWB3qMbLmR6eL3aUryZgQtZoBe1pye17Wl8fs9HysV3si6xMgndQ==", + "dev": true, + "requires": { + "@volar/language-core": "~1.10.4", + "@volar/source-map": "~1.10.4", + "@vue/compiler-dom": "^3.3.0", + "@vue/reactivity": "^3.3.0", + "@vue/shared": "^3.3.0", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "vue-template-compiler": "^2.7.14" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@vue/reactivity": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", + "integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==", + "requires": { + "@vue/shared": "3.3.4" + } + }, + "@vue/reactivity-transform": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz", + "integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==", + "requires": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0" + } + }, + "@vue/runtime-core": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz", + "integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==", + "requires": { + "@vue/reactivity": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "@vue/runtime-dom": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz", + "integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==", + "requires": { + "@vue/runtime-core": "3.3.4", + "@vue/shared": "3.3.4", + "csstype": "^3.1.1" + } + }, + "@vue/server-renderer": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz", + "integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==", + "requires": { + "@vue/compiler-ssr": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "@vue/shared": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", + "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" + }, + "@vue/tsconfig": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.4.0.tgz", + "integrity": "sha512-CPuIReonid9+zOG/CGTT05FXrPYATEqoDGNrEaqS4hwcw5BUNM2FguC0mOwJD4Jr16UpRVl9N0pY3P+srIbqmg==", + "dev": true + }, + "@vue/typescript": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/@vue/typescript/-/typescript-1.8.19.tgz", + "integrity": "sha512-k/SHeeQROUgqsxyHQ8Cs3Zz5TnX57p7BcBDVYR2E0c61QL2DJ2G8CsaBremmNGuGE6o1R5D50IHIxFmroMz8iw==", + "dev": true, + "requires": { + "@volar/typescript": "~1.10.4", + "@vue/language-core": "1.8.19" + } + }, + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "requires": { + "big-integer": "^1.6.44" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + } + }, + "bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "requires": { + "run-applescript": "^5.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001550", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001550.tgz", + "integrity": "sha512-p82WjBYIypO0ukTsd/FG3Xxs+4tFeaY9pfT4amQL8KWtYH7H9nYwReGAbMTJ0hsmRO8IfDtsS6p3ZWj8+1c2RQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-render": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/css-render/-/css-render-0.15.12.tgz", + "integrity": "sha512-eWzS66patiGkTTik+ipO9qNGZ+uNuGyTmnz6/+EJIiFg8+3yZRpnMwgFo8YdXhQRsiePzehnusrxVvugNjXzbw==", + "dev": true, + "requires": { + "@emotion/hash": "~0.8.0", + "csstype": "~3.0.5" + }, + "dependencies": { + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", + "dev": true + } + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "date-fns-tz": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-2.0.0.tgz", + "integrity": "sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==", + "dev": true, + "requires": {} + }, + "de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "requires": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + } + }, + "default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "requires": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + } + }, + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.559", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.559.tgz", + "integrity": "sha512-iS7KhLYCSJbdo3rUSkhDTVuFNCV34RKs2UaB9Ecr7VlqzjjWW//0nfsFF5dtDmyXlZQaDYYtID5fjtC/6lpRug==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.51.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "requires": {} + }, + "eslint-plugin-prettier": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + } + }, + "eslint-plugin-vue": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.17.0.tgz", + "integrity": "sha512-r7Bp79pxQk9I5XDP0k2dpUC7Ots3OSWgvGZNu3BxmKK6Zg7NgVtcOB6OCna5Kb9oQwJPl5hq183WD0SY5tZtIQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.13", + "semver": "^7.5.4", + "vue-eslint-parser": "^9.3.1", + "xml-name-validator": "^4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "evtd": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/evtd/-/evtd-0.2.4.tgz", + "integrity": "sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==", + "dev": true + }, + "execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "dev": true + }, + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + } + } + }, + "html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true + }, + "human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + }, + "dependencies": { + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + } + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true + }, + "naive-ui": { + "version": "2.35.0", + "resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.35.0.tgz", + "integrity": "sha512-PdnLpOip1LQaKs5+rXLZoPDPQkTq26TnHWeABvUA2eOQjtHxE4+TQvj0Jq/W8clM2On/7jptoGmenLt48G3Bhg==", + "dev": true, + "requires": { + "@css-render/plugin-bem": "^0.15.12", + "@css-render/vue3-ssr": "^0.15.12", + "@types/katex": "^0.16.2", + "@types/lodash": "^4.14.198", + "@types/lodash-es": "^4.17.9", + "async-validator": "^4.2.5", + "css-render": "^0.15.12", + "date-fns": "^2.30.0", + "date-fns-tz": "^2.0.0", + "evtd": "^0.2.4", + "highlight.js": "^11.8.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "seemly": "^0.3.6", + "treemate": "^0.3.11", + "vdirs": "^0.1.8", + "vooks": "^0.2.12", + "vueuc": "^0.4.51" + } + }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "npm-run-all2": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-6.1.1.tgz", + "integrity": "sha512-lWLbkPZ5BSdXtN8lR+0rc8caKoPdymycpZksyDEC9MOBvfdwTXZ0uVhb7bMcGeXv2/BKtfQuo6Zn3zfc8rxNXA==", + "dev": true, + "requires": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.3", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-pkg": "^8.0.0", + "shell-quote": "^1.7.3" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "requires": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.0.tgz", + "integrity": "sha512-ihtdrgbqdONYD156Ap6qTcaGcGdkdAxodO1wLqQ/j7HP1u2sFYppINiq4jyC8F+Nm+4fVufylCV00QmkTHkSUg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "dependencies": { + "type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true + } + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true + }, + "pinia": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz", + "integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==", + "requires": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "dependencies": { + "vue-demi": { + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", + "requires": {} + } + } + }, + "postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + } + }, + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + }, + "dependencies": { + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "seemly": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/seemly/-/seemly-0.3.6.tgz", + "integrity": "sha512-lEV5VB8BUKTo/AfktXJcy+JeXns26ylbMkIUco8CYREsQijuz4mrXres2Q+vMLdwkuLxJdIPQ8IlCIxLYm71Yw==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "requires": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "treemate": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/treemate/-/treemate-0.3.11.tgz", + "integrity": "sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==", + "dev": true + }, + "ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "requires": {} + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.5.0.tgz", + "integrity": "sha512-diLQivFzddJl4ylL3jxSkEc39Tpw7o1QeEHIPxVwryDK2lpB7Nqhzhuo6v5/Ls08Z0yPSAhsyAWlv1/H0ciNmw==", + "dev": true + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "devOptional": true + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vdirs": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/vdirs/-/vdirs-0.1.8.tgz", + "integrity": "sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==", + "dev": true, + "requires": { + "evtd": "^0.2.2" + } + }, + "vfonts": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/vfonts/-/vfonts-0.0.3.tgz", + "integrity": "sha512-nguyw8L6Un8eelg1vQ31vIU2ESxqid7EYmy8V+MDeMaHBqaRSkg3dTBToC1PR00D89UzS/SLkfYPnx0Wf23IQQ==", + "dev": true + }, + "vite": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "dev": true, + "requires": { + "esbuild": "^0.18.10", + "fsevents": "~2.3.2", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + } + }, + "vooks": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/vooks/-/vooks-0.2.12.tgz", + "integrity": "sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==", + "dev": true, + "requires": { + "evtd": "^0.2.2" + } + }, + "vue": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz", + "integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==", + "requires": { + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-sfc": "3.3.4", + "@vue/runtime-dom": "3.3.4", + "@vue/server-renderer": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "vue-eslint-parser": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz", + "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "vue-router": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", + "integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==", + "requires": { + "@vue/devtools-api": "^6.5.0" + } + }, + "vue-template-compiler": { + "version": "2.7.14", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz", + "integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==", + "dev": true, + "requires": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "vue-tsc": { + "version": "1.8.19", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.19.tgz", + "integrity": "sha512-tacMQLQ0CXAfbhRycCL5sWIy1qujXaIEtP1hIQpzHWOUuICbtTj9gJyFf91PvzG5KCNIkA5Eg7k2Fmgt28l5DQ==", + "dev": true, + "requires": { + "@vue/language-core": "1.8.19", + "@vue/typescript": "1.8.19", + "semver": "^7.5.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "vueuc": { + "version": "0.4.51", + "resolved": "https://registry.npmjs.org/vueuc/-/vueuc-0.4.51.tgz", + "integrity": "sha512-pLiMChM4f+W8czlIClGvGBYo656lc2Y0/mXFSCydcSmnCR1izlKPGMgiYBGjbY9FDkFG8a2HEVz7t0DNzBWbDw==", + "dev": true, + "requires": { + "@css-render/vue3-ssr": "^0.15.10", + "@juggle/resize-observer": "^3.3.1", + "css-render": "^0.15.10", + "evtd": "^0.2.4", + "seemly": "^0.3.6", + "vdirs": "^0.1.4", + "vooks": "^0.2.4" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/package.json b/maddius/maddius_matrix_control/components/esp_server/esp_vue/package.json new file mode 100644 index 0000000..71a9e19 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/package.json @@ -0,0 +1,39 @@ +{ + "name": "esp-vue", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "@kyvg/vue3-notification": "^3.0.2", + "pinia": "^2.1.6", + "vue": "^3.3.4", + "vue-router": "^4.2.4" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.3.3", + "@tsconfig/node18": "^18.2.2", + "@types/node": "^18.18.7", + "@vitejs/plugin-vue": "^4.3.4", + "@vitejs/plugin-vue-jsx": "^3.0.2", + "@vue/eslint-config-prettier": "^8.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "@vue/tsconfig": "^0.4.0", + "eslint": "^8.49.0", + "eslint-plugin-vue": "^9.17.0", + "naive-ui": "^2.35.0", + "npm-run-all2": "^6.0.6", + "prettier": "^3.0.3", + "typescript": "~5.2.0", + "vfonts": "^0.0.3", + "vite": "^4.4.9", + "vue-tsc": "^1.8.11" + } +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/public/favicon.ico b/maddius/maddius_matrix_control/components/esp_server/esp_vue/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/maddius/maddius_matrix_control/components/esp_server/esp_vue/public/favicon.ico differ diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/App.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/App.vue new file mode 100644 index 0000000..61cac42 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/App.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/base.css b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/logo.svg b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/main.css b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/main.css new file mode 100644 index 0000000..56bcec3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + /* max-width: 1280px; */ + /* margin: 0 auto; */ + /* padding: 2rem; */ + + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +/* @media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} */ diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/HelloWorld.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/HelloWorld.vue new file mode 100644 index 0000000..38d821e --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/TheWelcome.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/WelcomeItem.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconCommunity.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconDocumentation.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconEcosystem.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconSupport.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconTooling.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/main.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/main.ts new file mode 100644 index 0000000..a6015b6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/main.ts @@ -0,0 +1,23 @@ +import './assets/main.css' + +import Notifications from '@kyvg/vue3-notification' +import { createPinia } from 'pinia' +import { createApp } from 'vue' +import App from './App.vue' +import { WebsocketPlugin, type WebsocketPlugInterface } from './plugins/WebsocketPlugin' +import router from './router' + +//declare the property so that it can be used by ts +declare module '@vue/runtime-core' { + interface ComponentCustomProperties { + $ws: WebsocketPlugInterface + } +} + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(Notifications) +app.use(WebsocketPlugin) +app.mount('#app') diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/plugins/WebsocketPlugin/index.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/plugins/WebsocketPlugin/index.ts new file mode 100644 index 0000000..0c3a275 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/plugins/WebsocketPlugin/index.ts @@ -0,0 +1,60 @@ +import { useNotification } from '@kyvg/vue3-notification' +import { reactive, type App, type Plugin } from 'vue' +const { notify } = useNotification() +// plugins/mebsocket.js +// const ws: Ref = ref() +export interface WebsocketPluginOptions { + retryDelayTime?: string + addNotification?(): void +} +export interface WebsocketPlugInterface { + connected: boolean + socket?: WebSocket + connect(): void + disconnect(): void + sendMessage(payload: Object): void +} +export const WebsocketPlugin: Plugin = { + install(app: App, options: WebsocketPluginOptions) { + app.config.globalProperties.$ws = reactive({ + connected: false, + socket: undefined, + connect: () => { + const url = 'ws://' + window.location.host + '/ws' + // if (process.env.NODE_ENV === 'development') { + // url = 'ws://192.168.1.206/ws' + // } + console.log('Starting connection to WebSocket Server', url) + const websocket = new WebSocket(url) + websocket.onmessage = (event) => { + console.log('onmessage', event) + } + + websocket.onopen = (event) => { + notify({ text: 'Successfully connected', type: 'success' }) + console.log(event) + app.config.globalProperties.$ws.connected = true + console.log('Successfully connected to the echo websocket server...') + } + + websocket.onclose = () => { + app.config.globalProperties.$ws.connected = false + console.log('onclose') + } + addEventListener('unload', (event) => { + websocket.close() + console.log('unload') + }) + app.config.globalProperties.$ws.socket = websocket + }, + disconnect: () => { + console.log('disconnect WebSocket Server') + app.config.globalProperties.$ws.socket?.close() + }, + sendMessage: (payload: Object) => { + console.log('sendMessage') + app.config.globalProperties.$ws.socket?.send(JSON.stringify(payload)) + } + }) + } +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/router/index.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/router/index.ts new file mode 100644 index 0000000..2c4aa58 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/router/index.ts @@ -0,0 +1,25 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/settings', + name: 'settings', + component: () => import('../views/SettingsView.vue') + }, + { + path: '/qlc', + name: 'qlc', + component: () => import('../views/QlcIframeView.vue') + } + ] +}) + +export default router diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/controlStore.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/controlStore.ts new file mode 100644 index 0000000..e11180c --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/controlStore.ts @@ -0,0 +1,55 @@ +import { defineStore } from 'pinia' + +export const useControlStore = defineStore({ + id: 'control', + state: () => ({ + buttons: [], + faders: [], + constrols: { + bf00: 255, + bf01: 255, + bf02: 255, + bf03: 255, + bf04: 0, + bf05: 0, + bf06: 0, + bf07: 0, + bf08: 0, + bf09: 0, + bf10: 0, + bf11: 0, + bf12: 0, + bf13: 0, + bf14: 0, + bf15: 0, + bf16: 0, + bf17: 0, + bf18: 0, + bf19: 0, + bf20: 0, + bf21: 0, + bf22: 0, + bf23: 0, + bf24: 0, + bf25: 0, + bf26: 0, + bf27: 0, + bf28: 0, + bf29: 0, + + fc00: 0, + fc01: 0, + fc02: 0, + fc03: 0, + + fb00: 0, + fb01: 0, + fb02: 0, + fb03: 0, + fb04: 0, + fb05: 0, + fb06: 0, + fb07: 0 + } + }) +}) diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/counter.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/settingsStore.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/stores/settingsStore.ts new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/HomeView.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/HomeView.vue new file mode 100644 index 0000000..90815e3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/HomeView.vue @@ -0,0 +1,86 @@ + + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/QlcIframeView.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/QlcIframeView.vue new file mode 100644 index 0000000..46bd100 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/QlcIframeView.vue @@ -0,0 +1,29 @@ + + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/QlcWsView.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/QlcWsView.vue new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/SettingsView.vue b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/SettingsView.vue new file mode 100644 index 0000000..6367919 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/src/views/SettingsView.vue @@ -0,0 +1,116 @@ + + + + diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.app.json b/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.app.json new file mode 100644 index 0000000..3e5b621 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.json b/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.node.json b/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.node.json new file mode 100644 index 0000000..dee96be --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/tsconfig.node.json @@ -0,0 +1,16 @@ +{ + "extends": "@tsconfig/node18/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/maddius/maddius_matrix_control/components/esp_server/esp_vue/vite.config.ts b/maddius/maddius_matrix_control/components/esp_server/esp_vue/vite.config.ts new file mode 100644 index 0000000..567596e --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/esp_vue/vite.config.ts @@ -0,0 +1,24 @@ +import { fileURLToPath, URL } from 'node:url' + +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), vueJsx()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + }, + build: { + rollupOptions: { + output: { + entryFileNames: `assets/[name].js`, + chunkFileNames: `assets/[name].js`, + assetFileNames: `assets/[name].[ext]` + } + } + } +}) diff --git a/maddius/maddius_matrix_control/components/esp_server/keep_alive.c b/maddius/maddius_matrix_control/components/esp_server/keep_alive.c new file mode 100644 index 0000000..92ae0f6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/keep_alive.c @@ -0,0 +1,229 @@ +/* Keep Alive engine for wss server example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "keep_alive.h" +#include "esp_timer.h" + +typedef enum { + NO_CLIENT = 0, + CLIENT_FD_ADD, + CLIENT_FD_REMOVE, + CLIENT_UPDATE, + CLIENT_ACTIVE, + STOP_TASK, +} client_fd_action_type_t; + +typedef struct { + client_fd_action_type_t type; + int fd; + uint64_t last_seen; +} client_fd_action_t; + +typedef struct wss_keep_alive_storage { + size_t max_clients; + wss_check_client_alive_cb_t check_client_alive_cb; + wss_check_client_alive_cb_t client_not_alive_cb; + size_t keep_alive_period_ms; + size_t not_alive_after_ms; + void * user_ctx; + QueueHandle_t q; + client_fd_action_t clients[]; +} wss_keep_alive_storage_t; + +typedef struct wss_keep_alive_storage* wss_keep_alive_t; + +static const char *TAG = "wss_keep_alive"; + +static uint64_t _tick_get_ms(void) +{ + return esp_timer_get_time()/1000; +} + +// Goes over active clients to find out how long we could sleep before checking who's alive +static uint64_t get_max_delay(wss_keep_alive_t h) +{ + int64_t check_after_ms = 30000; // max delay, no need to check anyone + for (int i=0; imax_clients; ++i) { + if (h->clients[i].type == CLIENT_ACTIVE) { + uint64_t check_this_client_at = h->clients[i].last_seen + h->keep_alive_period_ms; + if (check_this_client_at < check_after_ms + _tick_get_ms()) { + check_after_ms = check_this_client_at - _tick_get_ms(); + if (check_after_ms < 0) { + check_after_ms = 1000; // min delay, some client(s) not responding already + } + } + } + } + return check_after_ms; +} + + +static bool update_client(wss_keep_alive_t h, int sockfd, uint64_t timestamp) +{ + for (int i=0; imax_clients; ++i) { + if (h->clients[i].type == CLIENT_ACTIVE && h->clients[i].fd == sockfd) { + h->clients[i].last_seen = timestamp; + return true; + } + } + return false; +} + +static bool remove_client(wss_keep_alive_t h, int sockfd) +{ + for (int i=0; imax_clients; ++i) { + if (h->clients[i].type == CLIENT_ACTIVE && h->clients[i].fd == sockfd) { + h->clients[i].type = NO_CLIENT; + h->clients[i].fd = -1; + return true; + } + } + return false; +} +static bool add_new_client(wss_keep_alive_t h,int sockfd) +{ + for (int i=0; imax_clients; ++i) { + if (h->clients[i].type == NO_CLIENT) { + h->clients[i].type = CLIENT_ACTIVE; + h->clients[i].fd = sockfd; + h->clients[i].last_seen = _tick_get_ms(); + return true; // success + } + } + return false; +} + +static void keep_alive_task(void* arg) +{ + wss_keep_alive_storage_t *keep_alive_storage = arg; + bool run_task = true; + client_fd_action_t client_action; + while (run_task) { + if (xQueueReceive(keep_alive_storage->q, (void *) &client_action, + get_max_delay(keep_alive_storage) / portTICK_PERIOD_MS) == pdTRUE) { + switch (client_action.type) { + case CLIENT_FD_ADD: + if (!add_new_client(keep_alive_storage, client_action.fd)) { + ESP_LOGE(TAG, "Cannot add new client"); + } + break; + case CLIENT_FD_REMOVE: + if (!remove_client(keep_alive_storage, client_action.fd)) { + ESP_LOGE(TAG, "Cannot remove client fd:%d", client_action.fd); + } + break; + case CLIENT_UPDATE: + if (!update_client(keep_alive_storage, client_action.fd, client_action.last_seen)) { + ESP_LOGE(TAG, "Cannot find client fd:%d", client_action.fd); + } + break; + case STOP_TASK: + run_task = false; + break; + default: + ESP_LOGE(TAG, "Unexpected client action"); + break; + } + } else { + // timeout: check if PING message needed + for (int i=0; imax_clients; ++i) { + if (keep_alive_storage->clients[i].type == CLIENT_ACTIVE) { + if (keep_alive_storage->clients[i].last_seen + keep_alive_storage->keep_alive_period_ms <= _tick_get_ms()) { + ESP_LOGD(TAG, "Haven't seen the client (fd=%d) for a while", keep_alive_storage->clients[i].fd); + if (keep_alive_storage->clients[i].last_seen + keep_alive_storage->not_alive_after_ms <= _tick_get_ms()) { + ESP_LOGE(TAG, "Client (fd=%d) not alive!", keep_alive_storage->clients[i].fd); + keep_alive_storage->client_not_alive_cb(keep_alive_storage, keep_alive_storage->clients[i].fd); + } else { + keep_alive_storage->check_client_alive_cb(keep_alive_storage, keep_alive_storage->clients[i].fd); + } + } + } + } + } + } + vQueueDelete(keep_alive_storage->q); + free(keep_alive_storage); + + vTaskDelete(NULL); +} + +wss_keep_alive_t wss_keep_alive_start(wss_keep_alive_config_t *config) +{ + size_t queue_size = config->max_clients/2; + size_t client_list_size = config->max_clients + queue_size; + wss_keep_alive_t keep_alive_storage = calloc(1, + sizeof(wss_keep_alive_storage_t) + client_list_size* sizeof(client_fd_action_t)); + if (keep_alive_storage == NULL) { + return false; + } + keep_alive_storage->check_client_alive_cb = config->check_client_alive_cb; + keep_alive_storage->client_not_alive_cb = config->client_not_alive_cb; + keep_alive_storage->max_clients = config->max_clients; + keep_alive_storage->not_alive_after_ms = config->not_alive_after_ms; + keep_alive_storage->keep_alive_period_ms = config->keep_alive_period_ms; + keep_alive_storage->user_ctx = config->user_ctx; + keep_alive_storage->q = xQueueCreate(queue_size, sizeof(client_fd_action_t)); + if (xTaskCreate(keep_alive_task, "keep_alive_task", config->task_stack_size, + keep_alive_storage, config->task_prio, NULL) != pdTRUE) { + wss_keep_alive_stop(keep_alive_storage); + return false; + } + return keep_alive_storage; +} + +void wss_keep_alive_stop(wss_keep_alive_t h) +{ + client_fd_action_t stop = { .type = STOP_TASK }; + xQueueSendToBack(h->q, &stop, 0); + // internal structs will be de-allocated in the task +} + +esp_err_t wss_keep_alive_add_client(wss_keep_alive_t h, int fd) +{ + client_fd_action_t client_fd_action = { .fd = fd, .type = CLIENT_FD_ADD}; + if (xQueueSendToBack(h->q, &client_fd_action, 0) == pdTRUE) { + return ESP_OK; + } + return ESP_FAIL; +} + +esp_err_t wss_keep_alive_remove_client(wss_keep_alive_t h, int fd) +{ + client_fd_action_t client_fd_action = { .fd = fd, .type = CLIENT_FD_REMOVE}; + if (xQueueSendToBack(h->q, &client_fd_action, 0) == pdTRUE) { + return ESP_OK; + } + return ESP_FAIL; +} + +esp_err_t wss_keep_alive_client_is_active(wss_keep_alive_t h, int fd) +{ + client_fd_action_t client_fd_action = { .fd = fd, .type = CLIENT_UPDATE, + .last_seen = _tick_get_ms()}; + if (xQueueSendToBack(h->q, &client_fd_action, 0) == pdTRUE) { + return ESP_OK; + } + return ESP_FAIL; + +} + +void wss_keep_alive_set_user_ctx(wss_keep_alive_t h, void *ctx) +{ + h->user_ctx = ctx; +} + +void* wss_keep_alive_get_user_ctx(wss_keep_alive_t h) +{ + return h->user_ctx; +} diff --git a/maddius/maddius_matrix_control/components/esp_server/keep_alive.h b/maddius/maddius_matrix_control/components/esp_server/keep_alive.h new file mode 100644 index 0000000..9d0dae0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/keep_alive.h @@ -0,0 +1,106 @@ +/* Keep Alive engine for wss server example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#pragma once + +#define KEEP_ALIVE_CONFIG_DEFAULT() \ + { \ + .max_clients = 10, \ + .task_stack_size = 2048, \ + .task_prio = tskIDLE_PRIORITY + 1, \ + .keep_alive_period_ms = 5000, \ + .not_alive_after_ms = 10000, \ + } + +#ifdef __cplusplus +extern "C" +{ +#endif + + struct wss_keep_alive_storage; + typedef struct wss_keep_alive_storage *wss_keep_alive_t; + typedef bool (*wss_check_client_alive_cb_t)(wss_keep_alive_t h, int fd); + typedef bool (*wss_client_not_alive_cb_t)(wss_keep_alive_t h, int fd); + + /** + * @brief Confiuration struct + */ + typedef struct + { + size_t max_clients; /*!< max number of clients */ + size_t task_stack_size; /*!< stack size of the created task */ + size_t task_prio; /*!< priority of the created task */ + size_t keep_alive_period_ms; /*!< check every client after this time */ + size_t not_alive_after_ms; /*!< consider client not alive after this time */ + wss_check_client_alive_cb_t check_client_alive_cb; /*!< callback function to check if client is alive */ + wss_client_not_alive_cb_t client_not_alive_cb; /*!< callback function to notify that the client is not alive */ + void *user_ctx; /*!< user context available in the keep-alive handle */ + } wss_keep_alive_config_t; + + /** + * @brief Adds a new client to internal set of clients to keep an eye on + * + * @param h keep-alive handle + * @param fd socket file descriptor for this client + * @return ESP_OK on success + */ + esp_err_t wss_keep_alive_add_client(wss_keep_alive_t h, int fd); + + /** + * @brief Removes this client from the set + * + * @param h keep-alive handle + * @param fd socket file descriptor for this client + * @return ESP_OK on success + */ + esp_err_t wss_keep_alive_remove_client(wss_keep_alive_t h, int fd); + + /** + * @brief Notify that this client is alive + * + * @param h keep-alive handle + * @param fd socket file descriptor for this client + * @return ESP_OK on success + */ + + esp_err_t wss_keep_alive_client_is_active(wss_keep_alive_t h, int fd); + + /** + * @brief Starts keep-alive engine + * + * @param config keep-alive configuration + * @return keep alive handle + */ + wss_keep_alive_t wss_keep_alive_start(wss_keep_alive_config_t *config); + + /** + * @brief Stops keep-alive engine + * + * @param h keep-alive handle + */ + void wss_keep_alive_stop(wss_keep_alive_t h); + + /** + * @brief Sets user defined context + * + * @param h keep-alive handle + * @param ctx user context + */ + void wss_keep_alive_set_user_ctx(wss_keep_alive_t h, void *ctx); + + /** + * @brief Gets user defined context + * + * @param h keep-alive handle + * @return ctx user context + */ + void *wss_keep_alive_get_user_ctx(wss_keep_alive_t h); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/udp_server.c b/maddius/maddius_matrix_control/components/esp_server/udp_server.c new file mode 100644 index 0000000..60c1d4f --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/udp_server.c @@ -0,0 +1,194 @@ +/* BSD Socket API Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_netif.h" +#include "protocol_examples_common.h" + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include + +#define PORT CONFIG_EXAMPLE_PORT + +static const char *TAG = "udp_server"; + +void udp_server_task(void *pvParameters) +{ + char rx_buffer[128]; + char addr_str[128]; + int addr_family = (int)pvParameters; + int ip_protocol = 0; + struct sockaddr_in6 dest_addr; + + while (1) + { + + if (addr_family == AF_INET) + { + struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr; + dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); + dest_addr_ip4->sin_family = AF_INET; + dest_addr_ip4->sin_port = htons(PORT); + ip_protocol = IPPROTO_IP; + } + else if (addr_family == AF_INET6) + { + bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un)); + dest_addr.sin6_family = AF_INET6; + dest_addr.sin6_port = htons(PORT); + ip_protocol = IPPROTO_IPV6; + } + + int sock = socket(addr_family, SOCK_DGRAM, ip_protocol); + if (sock < 0) + { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + break; + } + ESP_LOGI(TAG, "Socket created"); + +#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6) + int enable = 1; + lwip_setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable)); +#endif + +#if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6) + if (addr_family == AF_INET6) + { + // Note that by default IPV6 binds to both protocols, it is must be disabled + // if both protocols used at the same time (used in CI) + int opt = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)); + } +#endif + // Set timeout + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 0; + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout); + + int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err < 0) + { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + } + ESP_LOGI(TAG, "Socket bound, port %d", PORT); + + struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6 + socklen_t socklen = sizeof(source_addr); + +#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6) + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsgtmp; + u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; + + iov.iov_base = rx_buffer; + iov.iov_len = sizeof(rx_buffer); + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + msg.msg_flags = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_name = (struct sockaddr *)&source_addr; + msg.msg_namelen = socklen; +#endif + + while (1) + { + ESP_LOGI(TAG, "Waiting for data"); +#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6) + int len = recvmsg(sock, &msg, 0); +#else + int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen); +#endif + // Error occurred during receiving + if (len < 0) + { + ESP_LOGE(TAG, "recvfrom failed: errno %d", errno); + break; + } + // Data received + else + { + // Get the sender's ip address as string + if (source_addr.ss_family == PF_INET) + { + inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1); +#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6) + for (cmsgtmp = CMSG_FIRSTHDR(&msg); cmsgtmp != NULL; cmsgtmp = CMSG_NXTHDR(&msg, cmsgtmp)) + { + if (cmsgtmp->cmsg_level == IPPROTO_IP && cmsgtmp->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsgtmp); + ESP_LOGI(TAG, "dest ip: %s", inet_ntoa(pktinfo->ipi_addr)); + } + } +#endif + } + else if (source_addr.ss_family == PF_INET6) + { + inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1); + } + + rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string... + ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str); + ESP_LOGI(TAG, "%s", rx_buffer); + + int err = sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&source_addr, sizeof(source_addr)); + if (err < 0) + { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + break; + } + } + } + + // dont restart + // if (sock != -1) + // { + // ESP_LOGE(TAG, "Shutting down socket and restarting..."); + // shutdown(sock, 0); + // close(sock); + // } + } + vTaskDelete(NULL); +} + +// void app_main(void) +// { +// ESP_ERROR_CHECK(nvs_flash_init()); +// ESP_ERROR_CHECK(esp_netif_init()); +// ESP_ERROR_CHECK(esp_event_loop_create_default()); + +// /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. +// * Read "Establishing Wi-Fi or Ethernet Connection" section in +// * examples/protocols/README.md for more information about this function. +// */ +// ESP_ERROR_CHECK(example_connect()); + +// #ifdef CONFIG_EXAMPLE_IPV4 +// xTaskCreate(udp_server_task, "udp_server", 4096, (void*)AF_INET, 5, NULL); +// #endif +// #ifdef CONFIG_EXAMPLE_IPV6 +// xTaskCreate(udp_server_task, "udp_server", 4096, (void*)AF_INET6, 5, NULL); +// #endif + +// } \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/udp_server.h b/maddius/maddius_matrix_control/components/esp_server/udp_server.h new file mode 100644 index 0000000..05f1925 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/udp_server.h @@ -0,0 +1,11 @@ + +#ifdef __cplusplus +extern "C" +{ +#endif + + void udp_server_task(void *pvParameters); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/websocket_client.c b/maddius/maddius_matrix_control/components/esp_server/websocket_client.c new file mode 100644 index 0000000..820a0f2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/websocket_client.c @@ -0,0 +1,157 @@ +/* ESP HTTP Client Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "protocol_examples_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/event_groups.h" + +#include "esp_log.h" +#include "esp_websocket_client.h" +#include "esp_event.h" + +#include "websocket_client.h" +#define NO_DATA_TIMEOUT_SEC 10 + +static const char *TAG = "WEBSOCKET"; + +static TimerHandle_t shutdown_signal_timer; +static SemaphoreHandle_t shutdown_sema; + +static void shutdown_signaler(TimerHandle_t xTimer) +{ + ESP_LOGI(TAG, "No data received for %d seconds, signaling shutdown", NO_DATA_TIMEOUT_SEC); + xSemaphoreGive(shutdown_sema); +} + +#if CONFIG_WEBSOCKET_URI_FROM_STDIN +static void get_string(char *line, size_t size) +{ + int count = 0; + while (count < size) + { + int c = fgetc(stdin); + if (c == '\n') + { + line[count] = '\0'; + break; + } + else if (c > 0 && c < 127) + { + line[count] = c; + ++count; + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +#endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */ + +static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; + switch (event_id) + { + case WEBSOCKET_EVENT_CONNECTED: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED"); + break; + case WEBSOCKET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED"); + break; + case WEBSOCKET_EVENT_DATA: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA"); + ESP_LOGI(TAG, "Received opcode=%d", data->op_code); + ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr); + ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%d\r\n", data->payload_len, data->data_len, data->payload_offset); + + xTimerReset(shutdown_signal_timer, portMAX_DELAY); + break; + case WEBSOCKET_EVENT_ERROR: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR"); + break; + } +} + +// TODO write task +void websocket_client_start(void) +{ + esp_websocket_client_config_t websocket_cfg = {}; + + shutdown_signal_timer = xTimerCreate("Websocket shutdown timer", NO_DATA_TIMEOUT_SEC * 1000 / portTICK_PERIOD_MS, + pdFALSE, NULL, shutdown_signaler); + shutdown_sema = xSemaphoreCreateBinary(); + +#if CONFIG_WEBSOCKET_URI_FROM_STDIN + char line[128]; + + ESP_LOGI(TAG, "Please enter uri of websocket endpoint"); + get_string(line, sizeof(line)); + + websocket_cfg.uri = line; + ESP_LOGI(TAG, "Endpoint uri: %s\n", line); + +#else + websocket_cfg.uri = CONFIG_WEBSOCKET_URI; + +#endif /* CONFIG_WEBSOCKET_URI_FROM_STDIN */ + + ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri); + + esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg); + esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client); + + esp_websocket_client_start(client); + xTimerStart(shutdown_signal_timer, portMAX_DELAY); + char data[32]; + int i = 0; + while (i < 10) + { + if (esp_websocket_client_is_connected(client)) + { + int len = sprintf(data, "hello %04d", i++); + ESP_LOGI(TAG, "Sending %s", data); + esp_websocket_client_send_text(client, data, len, portMAX_DELAY); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + + xSemaphoreTake(shutdown_sema, portMAX_DELAY); + esp_websocket_client_stop(client); + ESP_LOGI(TAG, "Websocket Stopped"); + esp_websocket_client_destroy(client); +} + +// void app_main(void) +// { +// ESP_LOGI(TAG, "[APP] Startup.."); +// ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); +// ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); +// esp_log_level_set("*", ESP_LOG_INFO); +// esp_log_level_set("WEBSOCKET_CLIENT", ESP_LOG_DEBUG); +// esp_log_level_set("TRANS_TCP", ESP_LOG_DEBUG); + +// ESP_ERROR_CHECK(nvs_flash_init()); +// ESP_ERROR_CHECK(esp_netif_init()); +// ESP_ERROR_CHECK(esp_event_loop_create_default()); + +// /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. +// * Read "Establishing Wi-Fi or Ethernet Connection" section in +// * examples/protocols/README.md for more information about this function. +// */ +// ESP_ERROR_CHECK(example_connect()); + +// websocket_app_start(); +// } \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/esp_server/websocket_client.h b/maddius/maddius_matrix_control/components/esp_server/websocket_client.h new file mode 100644 index 0000000..80a697f --- /dev/null +++ b/maddius/maddius_matrix_control/components/esp_server/websocket_client.h @@ -0,0 +1,11 @@ + +#ifdef __cplusplus +extern "C" +{ +#endif + + void websocket_client_start(void); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/.component_hash b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/.component_hash new file mode 100644 index 0000000..fdec944 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/.component_hash @@ -0,0 +1 @@ +e946617ee6bec30ef0cff505bc537e658a80d7b9222c060e225bf748f2029442 \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/CMakeLists.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/CMakeLists.txt new file mode 100644 index 0000000..1982008 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/CMakeLists.txt @@ -0,0 +1,271 @@ +# Check ESP-IDF version and error out if it is not in the supported range. +# +# Note for arduino-esp32 developers: to bypass the version check locally, +# set ARDUINO_SKIP_IDF_VERSION_CHECK environment variable to 1. For example: +# export ARDUINO_SKIP_IDF_VERSION_CHECK=1 +# idf.py build + +set(min_supported_idf_version "5.1.0") +set(max_supported_idf_version "5.1.99") +set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}") + +if ("${idf_version}" AND NOT "$ENV{ARDUINO_SKIP_IDF_VERSION_CHECK}") + if (idf_version VERSION_LESS min_supported_idf_version) + message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions " + "between ${min_supported_idf_version} and ${max_supported_idf_version}, " + "but an older version is detected: ${idf_version}.") + endif() + if (idf_version VERSION_GREATER max_supported_idf_version) + message(FATAL_ERROR "Arduino-esp32 can be used with ESP-IDF versions " + "between ${min_supported_idf_version} and ${max_supported_idf_version}, " + "but a newer version is detected: ${idf_version}.") + endif() +endif() + +set(CORE_SRCS + cores/esp32/base64.cpp + cores/esp32/cbuf.cpp + cores/esp32/chip-debug-report.cpp + cores/esp32/esp32-hal-adc.c + cores/esp32/esp32-hal-bt.c + cores/esp32/esp32-hal-cpu.c + cores/esp32/esp32-hal-dac.c + cores/esp32/esp32-hal-gpio.c + cores/esp32/esp32-hal-i2c.c + cores/esp32/esp32-hal-i2c-slave.c + cores/esp32/esp32-hal-ledc.c + cores/esp32/esp32-hal-matrix.c + cores/esp32/esp32-hal-misc.c + cores/esp32/esp32-hal-periman.c + cores/esp32/esp32-hal-psram.c + cores/esp32/esp32-hal-rgb-led.c + cores/esp32/esp32-hal-sigmadelta.c + cores/esp32/esp32-hal-spi.c + cores/esp32/esp32-hal-time.c + cores/esp32/esp32-hal-timer.c + cores/esp32/esp32-hal-tinyusb.c + cores/esp32/esp32-hal-touch.c + cores/esp32/esp32-hal-uart.c + cores/esp32/esp32-hal-rmt.c + cores/esp32/Esp.cpp + cores/esp32/FunctionalInterrupt.cpp + cores/esp32/HardwareSerial.cpp + cores/esp32/IPAddress.cpp + cores/esp32/IPv6Address.cpp + cores/esp32/libb64/cdecode.c + cores/esp32/libb64/cencode.c + cores/esp32/main.cpp + cores/esp32/MD5Builder.cpp + cores/esp32/Print.cpp + cores/esp32/stdlib_noniso.c + cores/esp32/Stream.cpp + cores/esp32/StreamString.cpp + cores/esp32/Tone.cpp + cores/esp32/HWCDC.cpp + cores/esp32/USB.cpp + cores/esp32/USBCDC.cpp + cores/esp32/USBMSC.cpp + cores/esp32/FirmwareMSC.cpp + cores/esp32/firmware_msc_fat.c + cores/esp32/wiring_pulse.c + cores/esp32/wiring_shift.c + cores/esp32/WMath.cpp + cores/esp32/WString.cpp + ) + +set(LIBRARY_SRCS + libraries/ArduinoOTA/src/ArduinoOTA.cpp + libraries/AsyncUDP/src/AsyncUDP.cpp + libraries/BluetoothSerial/src/BluetoothSerial.cpp + libraries/BluetoothSerial/src/BTAddress.cpp + libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp + libraries/BluetoothSerial/src/BTScanResultsSet.cpp + libraries/DNSServer/src/DNSServer.cpp + libraries/EEPROM/src/EEPROM.cpp + libraries/ESPmDNS/src/ESPmDNS.cpp + libraries/Ethernet/src/ETH.cpp + libraries/FFat/src/FFat.cpp + libraries/FS/src/FS.cpp + libraries/FS/src/vfs_api.cpp + libraries/HTTPClient/src/HTTPClient.cpp + libraries/HTTPUpdate/src/HTTPUpdate.cpp + libraries/LittleFS/src/LittleFS.cpp + libraries/Insights/src/Insights.cpp + libraries/I2S/src/I2S.cpp + libraries/NetBIOS/src/NetBIOS.cpp + libraries/Preferences/src/Preferences.cpp + libraries/RainMaker/src/RMaker.cpp + libraries/RainMaker/src/RMakerNode.cpp + libraries/RainMaker/src/RMakerParam.cpp + libraries/RainMaker/src/RMakerDevice.cpp + libraries/RainMaker/src/RMakerType.cpp + libraries/RainMaker/src/RMakerQR.cpp + libraries/RainMaker/src/RMakerUtils.cpp + libraries/RainMaker/src/AppInsights.cpp + libraries/SD_MMC/src/SD_MMC.cpp + libraries/SD/src/SD.cpp + libraries/SD/src/sd_diskio.cpp + libraries/SD/src/sd_diskio_crc.c + libraries/SimpleBLE/src/SimpleBLE.cpp + libraries/SPIFFS/src/SPIFFS.cpp + libraries/SPI/src/SPI.cpp + libraries/Ticker/src/Ticker.cpp + libraries/Update/src/Updater.cpp + libraries/Update/src/HttpsOTAUpdate.cpp + libraries/USB/src/USBHID.cpp + libraries/USB/src/USBHIDMouse.cpp + libraries/USB/src/USBHIDKeyboard.cpp + libraries/USB/src/USBHIDGamepad.cpp + libraries/USB/src/USBHIDConsumerControl.cpp + libraries/USB/src/USBHIDSystemControl.cpp + libraries/USB/src/USBHIDVendor.cpp + libraries/USB/src/USBVendor.cpp + libraries/WebServer/src/WebServer.cpp + libraries/WebServer/src/Parsing.cpp + libraries/WebServer/src/detail/mimetable.cpp + libraries/WiFiClientSecure/src/ssl_client.cpp + libraries/WiFiClientSecure/src/WiFiClientSecure.cpp + libraries/WiFi/src/WiFiAP.cpp + libraries/WiFi/src/WiFiClient.cpp + libraries/WiFi/src/WiFi.cpp + libraries/WiFi/src/WiFiGeneric.cpp + libraries/WiFi/src/WiFiMulti.cpp + libraries/WiFi/src/WiFiScan.cpp + libraries/WiFi/src/WiFiServer.cpp + libraries/WiFi/src/WiFiSTA.cpp + libraries/WiFi/src/WiFiUdp.cpp + libraries/WiFiProv/src/WiFiProv.cpp + libraries/Wire/src/Wire.cpp + ) + +set(BLE_SRCS + libraries/BLE/src/BLE2902.cpp + libraries/BLE/src/BLE2904.cpp + libraries/BLE/src/BLEAddress.cpp + libraries/BLE/src/BLEAdvertisedDevice.cpp + libraries/BLE/src/BLEAdvertising.cpp + libraries/BLE/src/BLEBeacon.cpp + libraries/BLE/src/BLECharacteristic.cpp + libraries/BLE/src/BLECharacteristicMap.cpp + libraries/BLE/src/BLEClient.cpp + libraries/BLE/src/BLEDescriptor.cpp + libraries/BLE/src/BLEDescriptorMap.cpp + libraries/BLE/src/BLEDevice.cpp + libraries/BLE/src/BLEEddystoneTLM.cpp + libraries/BLE/src/BLEEddystoneURL.cpp + libraries/BLE/src/BLEExceptions.cpp + libraries/BLE/src/BLEHIDDevice.cpp + libraries/BLE/src/BLERemoteCharacteristic.cpp + libraries/BLE/src/BLERemoteDescriptor.cpp + libraries/BLE/src/BLERemoteService.cpp + libraries/BLE/src/BLEScan.cpp + libraries/BLE/src/BLESecurity.cpp + libraries/BLE/src/BLEServer.cpp + libraries/BLE/src/BLEService.cpp + libraries/BLE/src/BLEServiceMap.cpp + libraries/BLE/src/BLEUtils.cpp + libraries/BLE/src/BLEUUID.cpp + libraries/BLE/src/BLEValue.cpp + libraries/BLE/src/FreeRTOS.cpp + libraries/BLE/src/GeneralUtils.cpp + ) + +set(includedirs + variants/${CONFIG_ARDUINO_VARIANT}/ + cores/esp32/ + libraries/ArduinoOTA/src + libraries/AsyncUDP/src + libraries/BLE/src + libraries/BluetoothSerial/src + libraries/DNSServer/src + libraries/EEPROM/src + libraries/ESP32/src + libraries/ESPmDNS/src + libraries/Ethernet/src + libraries/FFat/src + libraries/FS/src + libraries/HTTPClient/src + libraries/HTTPUpdate/src + libraries/LittleFS/src + libraries/Insights/src + libraries/I2S/src + libraries/NetBIOS/src + libraries/Preferences/src + libraries/RainMaker/src + libraries/SD_MMC/src + libraries/SD/src + libraries/SimpleBLE/src + libraries/SPIFFS/src + libraries/SPI/src + libraries/Ticker/src + libraries/Update/src + libraries/USB/src + libraries/WebServer/src + libraries/WiFiClientSecure/src + libraries/WiFi/src + libraries/WiFiProv/src + libraries/Wire/src + ) + +set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS}) +set(priv_includes cores/esp32/libb64) +set(requires spi_flash mbedtls wifi_provisioning wpa_supplicant esp_adc esp_eth http_parser) +set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support bt esp_hid) + +idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires}) + +if(NOT CONFIG_FREERTOS_HZ EQUAL 1000 AND NOT "$ENV{ARDUINO_SKIP_TICK_CHECK}") + # See delay() in cores/esp32/esp32-hal-misc.c. + message(FATAL_ERROR "esp32-arduino requires CONFIG_FREERTOS_HZ=1000 " + "(currently ${CONFIG_FREERTOS_HZ})") +endif() + +string(TOUPPER ${CONFIG_ARDUINO_VARIANT} idf_target_caps) +string(REPLACE "-" "_" idf_target_for_macro "${idf_target_caps}") +target_compile_options(${COMPONENT_TARGET} PUBLIC + -DARDUINO=10812 + -DARDUINO_${idf_target_for_macro}_DEV + -DARDUINO_ARCH_ESP32 + -DARDUINO_BOARD="${idf_target_caps}_DEV" + -DARDUINO_VARIANT="${CONFIG_ARDUINO_VARIANT}" + -DESP32) + +if(CONFIG_AUTOSTART_ARDUINO) + # in autostart mode, arduino-esp32 contains app_main() function and needs to + # reference setup() and loop() in the main component. If we add main + # component to priv_requires then we create a large circular dependency + # (arduino-esp32 -> main -> arduino-esp32) and can get linker errors, so + # instead we add setup() and loop() to the undefined symbols list so the + # linker will always include them. + # + # (As they are C++ symbol, we need to add the C++ mangled names.) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _Z5setupv -u _Z4loopv") +endif() + +# This function adds a dependency on the given component if the component is included into the build. +function(maybe_add_component component_name) + idf_build_get_property(components BUILD_COMPONENTS) + if (${component_name} IN_LIST components) + idf_component_get_property(lib_name ${component_name} COMPONENT_LIB) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${lib_name}) + endif() +endfunction() + +maybe_add_component(esp-dsp) + +if(CONFIG_ESP_INSIGHTS_ENABLED) + maybe_add_component(esp_insights) +endif() +if(CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK) + maybe_add_component(esp_rainmaker) + maybe_add_component(qrcode) +endif() +if(IDF_TARGET MATCHES "esp32s2|esp32s3" AND CONFIG_TINYUSB_ENABLED) + maybe_add_component(arduino_tinyusb) +endif() +if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_ArduinoOTA) + maybe_add_component(esp_https_ota) +endif() +if(NOT CONFIG_ARDUINO_SELECTIVE_COMPILATION OR CONFIG_ARDUINO_SELECTIVE_LITTLEFS) + maybe_add_component(esp_littlefs) +endif() diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/Kconfig.projbuild b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/Kconfig.projbuild new file mode 100644 index 0000000..f7ee920 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/Kconfig.projbuild @@ -0,0 +1,412 @@ +menu "Arduino Configuration" + +config ARDUINO_VARIANT + string "Arduino target variant (board)" + default IDF_TARGET + help + The name of a target variant (e.g., a specific board) in the variants/ + folder, e.g. "heltec_wifi_lora_32_V2". The name is case sensitive. + Specifying a variant name different from the target enables additional + customization, for example the definition of GPIO pins. + +config ENABLE_ARDUINO_DEPENDS + bool + select LWIP_SO_RCVBUF + select ETHERNET + select WIFI_ENABLED + select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE if IDF_TARGET_ESP32 + select MEMMAP_SMP + default "y" + +config AUTOSTART_ARDUINO + bool "Autostart Arduino setup and loop on boot" + default "n" + help + Enabling this option will implement app_main and start Arduino. + All you need to implement in your main.cpp is setup() and loop() + and include Arduino.h + If disabled, you can call initArduino() to run any preparations + required by the framework + +choice ARDUINO_RUNNING_CORE + bool "Core on which Arduino's setup() and loop() are running" + default ARDUINO_RUN_CORE0 if FREERTOS_UNICORE + default ARDUINO_RUN_CORE1 if !FREERTOS_UNICORE + help + Select on which core Arduino's setup() and loop() functions run + + config ARDUINO_RUN_CORE0 + bool "CORE 0" + config ARDUINO_RUN_CORE1 + bool "CORE 1" + depends on !FREERTOS_UNICORE + config ARDUINO_RUN_NO_AFFINITY + bool "BOTH" + depends on !FREERTOS_UNICORE + +endchoice + +config ARDUINO_RUNNING_CORE + int + default 0 if ARDUINO_RUN_CORE0 + default 1 if ARDUINO_RUN_CORE1 + default -1 if ARDUINO_RUN_NO_AFFINITY + +config ARDUINO_LOOP_STACK_SIZE + int "Loop thread stack size" + default 8192 + help + Amount of stack available for the Arduino task. + +choice ARDUINO_EVENT_RUNNING_CORE + bool "Core on which Arduino's event handler is running" + default ARDUINO_EVENT_RUN_CORE0 if FREERTOS_UNICORE + default ARDUINO_EVENT_RUN_CORE1 if !FREERTOS_UNICORE + help + Select on which core Arduino's WiFi.onEvent() run + + config ARDUINO_EVENT_RUN_CORE0 + bool "CORE 0" + config ARDUINO_EVENT_RUN_CORE1 + bool "CORE 1" + depends on !FREERTOS_UNICORE + config ARDUINO_EVENT_RUN_NO_AFFINITY + bool "BOTH" + depends on !FREERTOS_UNICORE + +endchoice + +config ARDUINO_EVENT_RUNNING_CORE + int + default 0 if ARDUINO_EVENT_RUN_CORE0 + default 1 if ARDUINO_EVENT_RUN_CORE1 + default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY + +choice ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE + bool "Core on which Arduino's Serial Event task is running" + default ARDUINO_SERIAL_EVENT_RUN_CORE0 if FREERTOS_UNICORE + default ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY if !FREERTOS_UNICORE + help + Select on which core Arduino's Serial Event task run + + config ARDUINO_SERIAL_EVENT_RUN_CORE0 + bool "CORE 0" + config ARDUINO_SERIAL_EVENT_RUN_CORE1 + bool "CORE 1" + depends on !FREERTOS_UNICORE + config ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY + bool "BOTH" + depends on !FREERTOS_UNICORE + +endchoice + +config ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE + int + default 0 if ARDUINO_SERIAL_EVENT_RUN_CORE0 + default 1 if ARDUINO_SERIAL_EVENT_RUN_CORE1 + default -1 if ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY + +config ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE + int "Serial Event task stack size" + default 2048 + help + Amount of stack available for the Serial Event task. + +config ARDUINO_SERIAL_EVENT_TASK_PRIORITY + int "Priority of the Serial Event task" + default 24 + help + Select at what priority you want the Serial Event task to run. + +choice ARDUINO_UDP_RUNNING_CORE + bool "Core on which Arduino's UDP is running" + default ARDUINO_UDP_RUN_CORE0 + help + Select on which core Arduino's UDP run + + config ARDUINO_UDP_RUN_CORE0 + bool "CORE 0" + config ARDUINO_UDP_RUN_CORE1 + bool "CORE 1" + depends on !FREERTOS_UNICORE + config ARDUINO_UDP_RUN_NO_AFFINITY + bool "BOTH" + depends on !FREERTOS_UNICORE + +endchoice + +config ARDUINO_UDP_RUNNING_CORE + int + default 0 if ARDUINO_UDP_RUN_CORE0 + default 1 if ARDUINO_UDP_RUN_CORE1 + default -1 if ARDUINO_UDP_RUN_NO_AFFINITY + +config ARDUINO_UDP_TASK_PRIORITY + int "Priority of the UDP task" + default 3 + help + Select at what priority you want the UDP task to run. + +config ARDUINO_ISR_IRAM + bool "Run interrupts in IRAM" + default "n" + help + Enabling this option will Attach all interrupts with the IRAm flag. + It will also make some HAL function, like, digitalRead/Write and more + be loaded into IRAM for access inside ISRs. + Beware that this is a very dangerous setting. Enable it only if you + are fully aware of the consequences. + +config DISABLE_HAL_LOCKS + bool "Disable mutex locks for HAL" + default "n" + help + Enabling this option will run all hardware abstraction without locks. + While communication with external hardware will be faster, you need to + make sure that there is no option to use the same bus from another thread + or interrupt at the same time. Option is best used with Arduino enabled + and code implemented only in setup/loop and Arduino callbacks + +menu "Debug Log Configuration" +choice ARDUHAL_LOG_DEFAULT_LEVEL + bool "Default log level" + default ARDUHAL_LOG_DEFAULT_LEVEL_ERROR + help + Specify how much output to see in logs by default. + +config ARDUHAL_LOG_DEFAULT_LEVEL_NONE + bool "No output" +config ARDUHAL_LOG_DEFAULT_LEVEL_ERROR + bool "Error" +config ARDUHAL_LOG_DEFAULT_LEVEL_WARN + bool "Warning" +config ARDUHAL_LOG_DEFAULT_LEVEL_INFO + bool "Info" +config ARDUHAL_LOG_DEFAULT_LEVEL_DEBUG + bool "Debug" +config ARDUHAL_LOG_DEFAULT_LEVEL_VERBOSE + bool "Verbose" +endchoice + +config ARDUHAL_LOG_DEFAULT_LEVEL + int + default 0 if ARDUHAL_LOG_DEFAULT_LEVEL_NONE + default 1 if ARDUHAL_LOG_DEFAULT_LEVEL_ERROR + default 2 if ARDUHAL_LOG_DEFAULT_LEVEL_WARN + default 3 if ARDUHAL_LOG_DEFAULT_LEVEL_INFO + default 4 if ARDUHAL_LOG_DEFAULT_LEVEL_DEBUG + default 5 if ARDUHAL_LOG_DEFAULT_LEVEL_VERBOSE + +config ARDUHAL_LOG_COLORS + bool "Use ANSI terminal colors in log output" + default "n" + help + Enable ANSI terminal color codes in bootloader output. + In order to view these, your terminal program must support ANSI color codes. + +config ARDUHAL_ESP_LOG + bool "Forward ESP_LOGx to Arduino log output" + default "n" + help + This option will redefine the ESP_LOGx macros to Arduino's log_x macros. + To enable for your application, add the follwing after your includes: + #ifdef ARDUINO_ARCH_ESP32 + #include "esp32-hal-log.h" + #endif + +endmenu + +choice ARDUHAL_PARTITION_SCHEME + bool "Used partition scheme" + default ARDUHAL_PARTITION_SCHEME_DEFAULT + help + Specify which partition scheme to be used. + +config ARDUHAL_PARTITION_SCHEME_DEFAULT + bool "Default" +config ARDUHAL_PARTITION_SCHEME_MINIMAL + bool "Minimal (for 2MB FLASH)" +config ARDUHAL_PARTITION_SCHEME_NO_OTA + bool "No OTA (for large apps)" +config ARDUHAL_PARTITION_SCHEME_HUGE_APP + bool "Huge App (for very large apps)" +config ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS + bool "Minimal SPIFFS (for large apps with OTA)" +endchoice + +config ARDUHAL_PARTITION_SCHEME + string + default "default" if ARDUHAL_PARTITION_SCHEME_DEFAULT + default "minimal" if ARDUHAL_PARTITION_SCHEME_MINIMAL + default "no_ota" if ARDUHAL_PARTITION_SCHEME_NO_OTA + default "huge_app" if ARDUHAL_PARTITION_SCHEME_HUGE_APP + default "min_spiffs" if ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS + + +config AUTOCONNECT_WIFI + bool "Autoconnect WiFi on boot" + default "n" + depends on AUTOSTART_ARDUINO + select ARDUINO_SELECTIVE_WiFi + help + If enabled, WiFi will connect to the last used SSID (if station was enabled), + else connection will be started only after calling WiFi.begin(ssid, password) + +config ARDUINO_SELECTIVE_COMPILATION + bool "Include only specific Arduino libraries" + default n + +config ARDUINO_SELECTIVE_ArduinoOTA + bool "Enable ArduinoOTA" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + select ARDUINO_SELECTIVE_ESPmDNS + default y + +config ARDUINO_SELECTIVE_AsyncUDP + bool "Enable AsyncUDP" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_AzureIoT + bool "Enable AzureIoT" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_HTTPClient + default y + +config ARDUINO_SELECTIVE_BLE + bool "Enable BLE" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_BluetoothSerial + bool "Enable BluetoothSerial" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_DNSServer + bool "Enable DNSServer" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + default y + +config ARDUINO_SELECTIVE_EEPROM + bool "Enable EEPROM" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_ESP32 + bool "Enable ESP32" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_ESPmDNS + bool "Enable ESPmDNS" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + default y + +config ARDUINO_SELECTIVE_FFat + bool "Enable FFat" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_FS + default y + +config ARDUINO_SELECTIVE_FS + bool "Enable FS" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_HTTPClient + bool "Enable HTTPClient" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + select ARDUINO_SELECTIVE_WiFiClientSecure + default y + +config ARDUINO_SELECTIVE_LITTLEFS + bool "Enable LITTLEFS" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_FS + default y + +config ARDUINO_SELECTIVE_NetBIOS + bool "Enable NetBIOS" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + default y + +config ARDUINO_SELECTIVE_Preferences + bool "Enable Preferences" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_SD + bool "Enable SD" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_FS + default y + +config ARDUINO_SELECTIVE_SD_MMC + bool "Enable SD_MMC" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_FS + default y + +config ARDUINO_SELECTIVE_SimpleBLE + bool "Enable SimpleBLE" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_SPI + bool "Enable SPI" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_SPIFFS + bool "Enable SPIFFS" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_FS + default y + +config ARDUINO_SELECTIVE_Ticker + bool "Enable Ticker" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_Update + bool "Enable Update" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_WebServer + bool "Enable WebServer" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + select ARDUINO_SELECTIVE_FS + +config ARDUINO_SELECTIVE_WiFi + bool "Enable WiFi" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_WiFiClientSecure + bool "Enable WiFiClientSecure" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + default y + +config ARDUINO_SELECTIVE_WiFiProv + bool "Enable WiFiProv" + depends on ARDUINO_SELECTIVE_COMPILATION + select ARDUINO_SELECTIVE_WiFi + default y + +config ARDUINO_SELECTIVE_Wire + bool "Enable Wire" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + + +endmenu + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Arduino.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Arduino.h new file mode 100644 index 0000000..2756f6f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Arduino.h @@ -0,0 +1,239 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "esp_arduino_version.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp32-hal.h" +#include "esp8266-compat.h" +#include "soc/gpio_reg.h" + +#include "stdlib_noniso.h" +#include "binary.h" + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +//Interrupt Modes +#define RISING 0x01 +#define FALLING 0x02 +#define CHANGE 0x03 +#define ONLOW 0x04 +#define ONHIGH 0x05 +#define ONLOW_WE 0x0C +#define ONHIGH_WE 0x0D + +#define DEFAULT 1 +#define EXTERNAL 0 + +#ifndef __STRINGIFY +#define __STRINGIFY(a) #a +#endif + +// can't define max() / min() because of conflicts with C++ +#define _min(a,b) ((a)<(b)?(a):(b)) +#define _max(a,b) ((a)>(b)?(a):(b)) +#define _abs(x) ((x)>0?(x):-(x)) // abs() comes from STL +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define _round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) // round() comes from STL +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +// ESP32xx runs FreeRTOS... disabling interrupts can lead to issues, such as Watchdog Timeout +#define sei() portENABLE_INTERRUPTS() +#define cli() portDISABLE_INTERRUPTS() +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( (long int)getCpuFrequencyMhz() ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitToggle(value, bit) ((value) ^= (1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) + +// avr-libc defines _NOP() since 1.6.2 +#ifndef _NOP +#define _NOP() do { __asm__ volatile ("nop"); } while (0) +#endif + +#define bit(b) (1UL << (b)) +#define _BV(b) (1UL << (b)) + +#define digitalPinToTimer(pin) (0) +#define analogInPinToBit(P) (P) +#if SOC_GPIO_PIN_COUNT <= 32 +#define digitalPinToPort(pin) (0) +#define digitalPinToBitMask(pin) (1UL << (pin)) +#define portOutputRegister(port) ((volatile uint32_t*)GPIO_OUT_REG) +#define portInputRegister(port) ((volatile uint32_t*)GPIO_IN_REG) +#define portModeRegister(port) ((volatile uint32_t*)GPIO_ENABLE_REG) +#elif SOC_GPIO_PIN_COUNT <= 64 +#define digitalPinToPort(pin) (((pin)>31)?1:0) +#define digitalPinToBitMask(pin) (1UL << (((pin)>31)?((pin)-32):(pin))) +#define portOutputRegister(port) ((volatile uint32_t*)((port)?GPIO_OUT1_REG:GPIO_OUT_REG)) +#define portInputRegister(port) ((volatile uint32_t*)((port)?GPIO_IN1_REG:GPIO_IN_REG)) +#define portModeRegister(port) ((volatile uint32_t*)((port)?GPIO_ENABLE1_REG:GPIO_ENABLE_REG)) +#else +#error SOC_GPIO_PIN_COUNT > 64 not implemented +#endif + +#define NOT_A_PIN -1 +#define NOT_A_PORT -1 +#define NOT_AN_INTERRUPT -1 +#define NOT_ON_TIMER 0 + +// some defines generic for all SoC moved from variants/board_name/pins_arduino.h +#define NUM_DIGITAL_PINS SOC_GPIO_PIN_COUNT // All GPIOs +#if SOC_ADC_PERIPH_NUM == 1 +#define NUM_ANALOG_INPUTS (SOC_ADC_CHANNEL_NUM(0)) // Depends on the SoC (ESP32C6, ESP32H2, ESP32C2, ESP32P4) +#elif SOC_ADC_PERIPH_NUM == 2 +#define NUM_ANALOG_INPUTS (SOC_ADC_CHANNEL_NUM(0)+SOC_ADC_CHANNEL_NUM(1)) // Depends on the SoC (ESP32, ESP32S2, ESP32S3, ESP32C3) +#endif +#define EXTERNAL_NUM_INTERRUPTS NUM_DIGITAL_PINS // All GPIOs +#define analogInputToDigitalPin(p) (((p) +#include + +#include "WCharacter.h" +#include "WString.h" +#include "Stream.h" +#include "Printable.h" +#include "Print.h" +#include "IPAddress.h" +#include "Client.h" +#include "Server.h" +#include "Udp.h" +#include "HardwareSerial.h" +#include "Esp.h" + +// Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries +using std::abs; +using std::isinf; +using std::isnan; +using std::max; +using std::min; +using std::round; + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(uint8_t h, uint8_t l); + +#define word(...) makeWord(__VA_ARGS__) + +size_t getArduinoLoopTaskStackSize(void); +#define SET_LOOP_TASK_STACK_SIZE(sz) size_t getArduinoLoopTaskStackSize() { return sz;} + +bool shouldPrintChipDebugReport(void); +#define ENABLE_CHIP_DEBUG_REPORT bool shouldPrintChipDebugReport(void){return true;} + +// allows user to bypass esp_spiram_test() +bool esp_psram_extram_test(void); +#define BYPASS_SPIRAM_TEST(bypass) bool testSPIRAM(void) { if (bypass) return true; else return esp_psram_extram_test(); } + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +extern "C" bool getLocalTime(struct tm * info, uint32_t ms = 5000); +extern "C" void configTime(long gmtOffset_sec, int daylightOffset_sec, + const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); +extern "C" void configTzTime(const char* tz, + const char* server1, const char* server2 = nullptr, const char* server3 = nullptr); + +void setToneChannel(uint8_t channel = 0); +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +#endif /* __cplusplus */ + +#include "pins_arduino.h" + +#endif /* _ESP32_CORE_ARDUINO_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Client.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Client.h new file mode 100644 index 0000000..962cacc --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Client.h @@ -0,0 +1,48 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client: public Stream +{ +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) + { + return addr.raw_address(); + } +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Esp.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Esp.cpp new file mode 100644 index 0000000..7d35fa5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Esp.cpp @@ -0,0 +1,471 @@ +/* + Esp.cpp - ESP31B-specific APIs + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Arduino.h" +#include "Esp.h" +#include "esp_sleep.h" +#include "spi_flash_mmap.h" +#include +#include +#include +extern "C" { +#include "esp_ota_ops.h" +#include "esp_image_format.h" +} +#include + +#include "soc/spi_reg.h" +#include "esp_system.h" +#include "esp_chip_info.h" +#include "esp_mac.h" +#include "esp_flash.h" +#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/spi_flash.h" +#include "soc/efuse_reg.h" +#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing flash size and spi mode +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/spi_flash.h" +#include "soc/efuse_reg.h" +#define ESP_FLASH_IMAGE_BASE 0x1000 +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/spi_flash.h" +#include "soc/efuse_reg.h" +#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32s3 is located at 0x0000 +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/spi_flash.h" +#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c3 is located at 0x0000 +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/spi_flash.h" +#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c6 is located at 0x0000 +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/spi_flash.h" +#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32h2 is located at 0x0000 +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif +#else // ESP32 Before IDF 4.0 +#include "rom/spi_flash.h" +#define ESP_FLASH_IMAGE_BASE 0x1000 +#endif + +// REG_SPI_BASE is not defined for S3/C3 ?? + +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 + #ifndef REG_SPI_BASE + #define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 ))) + #endif // REG_SPI_BASE +#endif // TARGET + +/** + * User-defined Literals + * usage: + * + * uint32_t = test = 10_MHz; // --> 10000000 + */ + +unsigned long long operator"" _kHz(unsigned long long x) +{ + return x * 1000; +} + +unsigned long long operator"" _MHz(unsigned long long x) +{ + return x * 1000 * 1000; +} + +unsigned long long operator"" _GHz(unsigned long long x) +{ + return x * 1000 * 1000 * 1000; +} + +unsigned long long operator"" _kBit(unsigned long long x) +{ + return x * 1024; +} + +unsigned long long operator"" _MBit(unsigned long long x) +{ + return x * 1024 * 1024; +} + +unsigned long long operator"" _GBit(unsigned long long x) +{ + return x * 1024 * 1024 * 1024; +} + +unsigned long long operator"" _kB(unsigned long long x) +{ + return x * 1024; +} + +unsigned long long operator"" _MB(unsigned long long x) +{ + return x * 1024 * 1024; +} + +unsigned long long operator"" _GB(unsigned long long x) +{ + return x * 1024 * 1024 * 1024; +} + + +EspClass ESP; + +void EspClass::deepSleep(uint32_t time_us) +{ + esp_deep_sleep(time_us); +} + +void EspClass::restart(void) +{ + esp_restart(); +} + +uint32_t EspClass::getHeapSize(void) +{ + return heap_caps_get_total_size(MALLOC_CAP_INTERNAL); +} + +uint32_t EspClass::getFreeHeap(void) +{ + return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); +} + +uint32_t EspClass::getMinFreeHeap(void) +{ + return heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL); +} + +uint32_t EspClass::getMaxAllocHeap(void) +{ + return heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); +} + +uint32_t EspClass::getPsramSize(void) +{ + if(psramFound()){ + return heap_caps_get_total_size(MALLOC_CAP_SPIRAM); + } + return 0; +} + +uint32_t EspClass::getFreePsram(void) +{ + if(psramFound()){ + return heap_caps_get_free_size(MALLOC_CAP_SPIRAM); + } + return 0; +} + +uint32_t EspClass::getMinFreePsram(void) +{ + if(psramFound()){ + return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM); + } + return 0; +} + +uint32_t EspClass::getMaxAllocPsram(void) +{ + if(psramFound()){ + return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM); + } + return 0; +} + +static uint32_t sketchSize(sketchSize_t response) { + esp_image_metadata_t data; + const esp_partition_t *running = esp_ota_get_running_partition(); + if (!running) return 0; + const esp_partition_pos_t running_pos = { + .offset = running->address, + .size = running->size, + }; + data.start_addr = running_pos.offset; + esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data); + if (response) { + return running_pos.size - data.image_len; + } else { + return data.image_len; + } +} + +uint32_t EspClass::getSketchSize () { + return sketchSize(SKETCH_SIZE_TOTAL); +} + +String EspClass::getSketchMD5() +{ + static String result; + if (result.length()) { + return result; + } + uint32_t lengthLeft = getSketchSize(); + + const esp_partition_t *running = esp_ota_get_running_partition(); + if (!running) { + log_e("Partition could not be found"); + + return String(); + } + const size_t bufSize = SPI_FLASH_SEC_SIZE; + std::unique_ptr buf(new uint8_t[bufSize]); + uint32_t offset = 0; + if(!buf.get()) { + log_e("Not enough memory to allocate buffer"); + + return String(); + } + MD5Builder md5; + md5.begin(); + while( lengthLeft > 0) { + size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize; + if (!ESP.flashRead(running->address + offset, reinterpret_cast(buf.get()), (readBytes + 3) & ~3)) { + log_e("Could not read buffer from flash"); + + return String(); + } + md5.add(buf.get(), readBytes); + lengthLeft -= readBytes; + offset += readBytes; + } + md5.calculate(); + result = md5.toString(); + return result; +} + +uint32_t EspClass::getFreeSketchSpace () { + const esp_partition_t* _partition = esp_ota_get_next_update_partition(NULL); + if(!_partition){ + return 0; + } + + return _partition->size; +} + +uint16_t EspClass::getChipRevision(void) +{ + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + return chip_info.revision; +} + +const char * EspClass::getChipModel(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); + uint32_t pkg_ver = chip_ver & 0x7; + switch (pkg_ver) { + case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6 : + if (getChipRevision() == 3) + return "ESP32-D0WDQ6-V3"; + else + return "ESP32-D0WDQ6"; + case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ5 : + if (getChipRevision() == 3) + return "ESP32-D0WD-V3"; + else + return "ESP32-D0WD"; + case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 : + return "ESP32-D2WD"; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 : + return "ESP32-PICO-D2"; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 : + return "ESP32-PICO-D4"; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302 : + return "ESP32-PICO-V3-02"; + case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDR2V3 : + return "ESP32-D0WDR2-V3"; + default: + return "Unknown"; + } +#elif CONFIG_IDF_TARGET_ESP32S2 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION); + switch (pkg_ver) { + case 0: + return "ESP32-S2"; + case 1: + return "ESP32-S2FH16"; + case 2: + return "ESP32-S2FH32"; + default: + return "ESP32-S2 (Unknown)"; + } +#else + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + switch(chip_info.model){ + case CHIP_ESP32S3: return "ESP32-S3"; + case CHIP_ESP32C3: return "ESP32-C3"; + case CHIP_ESP32C2: return "ESP32-C2"; + case CHIP_ESP32C6: return "ESP32-C6"; + case CHIP_ESP32H2: return "ESP32-H2"; + default: return "UNKNOWN"; + } +#endif +} + +uint8_t EspClass::getChipCores(void) +{ + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + return chip_info.cores; +} + +const char * EspClass::getSdkVersion(void) +{ + return esp_get_idf_version(); +} + +const char * EspClass::getCoreVersion(void) +{ + return ESP_ARDUINO_VERSION_STR; +} + +uint32_t ESP_getFlashChipId(void) +{ + uint32_t id = g_rom_flashchip.device_id; + id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00); + return id; +} + +uint32_t EspClass::getFlashChipSize(void) +{ + uint32_t id = (ESP_getFlashChipId() >> 16) & 0xFF; + return 2 << (id - 1); +} + +uint32_t EspClass::getFlashChipSpeed(void) +{ + esp_image_header_t fhdr; + if(esp_flash_read(esp_flash_default_chip, (void*)&fhdr, ESP_FLASH_IMAGE_BASE, sizeof(esp_image_header_t)) && fhdr.magic != ESP_IMAGE_HEADER_MAGIC) { + return 0; + } + return magicFlashChipSpeed(fhdr.spi_speed); +} + +FlashMode_t EspClass::getFlashChipMode(void) +{ + #if CONFIG_IDF_TARGET_ESP32S2 + uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL); + #else + #if CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 + uint32_t spi_ctrl = REG_READ(DR_REG_SPI0_BASE + 0x8); + #else + uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); + #endif + #endif + /* Not all of the following constants are already defined in older versions of spi_reg.h, so do it manually for now*/ + if (spi_ctrl & BIT(24)) { //SPI_FREAD_QIO + return (FM_QIO); + } else if (spi_ctrl & BIT(20)) { //SPI_FREAD_QUAD + return (FM_QOUT); + } else if (spi_ctrl & BIT(23)) { //SPI_FREAD_DIO + return (FM_DIO); + } else if (spi_ctrl & BIT(14)) { // SPI_FREAD_DUAL + return (FM_DOUT); + } else if (spi_ctrl & BIT(13)) { //SPI_FASTRD_MODE + return (FM_FAST_READ); + } else { + return (FM_SLOW_READ); + } + return (FM_DOUT); +} + +uint32_t EspClass::magicFlashChipSize(uint8_t byte) +{ + switch(byte & 0x0F) { + case 0x0: // 8 MBit (1MB) + return (1_MB); + case 0x1: // 16 MBit (2MB) + return (2_MB); + case 0x2: // 32 MBit (4MB) + return (4_MB); + case 0x3: // 64 MBit (8MB) + return (8_MB); + case 0x4: // 128 MBit (16MB) + return (16_MB); + default: // fail? + return 0; + } +} + +uint32_t EspClass::magicFlashChipSpeed(uint8_t byte) +{ + switch(byte & 0x0F) { + case 0x0: // 40 MHz + return (40_MHz); + case 0x1: // 26 MHz + return (26_MHz); + case 0x2: // 20 MHz + return (20_MHz); + case 0xf: // 80 MHz + return (80_MHz); + default: // fail? + return 0; + } +} + +FlashMode_t EspClass::magicFlashChipMode(uint8_t byte) +{ + FlashMode_t mode = (FlashMode_t) byte; + if(mode > FM_SLOW_READ) { + mode = FM_UNKNOWN; + } + return mode; +} + +bool EspClass::flashEraseSector(uint32_t sector) +{ + return esp_flash_erase_region(esp_flash_default_chip, sector * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE) == ESP_OK; +} + +// Warning: These functions do not work with encrypted flash +bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) +{ + return esp_flash_write(esp_flash_default_chip, (const void*) data, offset, size) == ESP_OK; +} + +bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size) +{ + return esp_flash_read(esp_flash_default_chip, (void*) data, offset, size) == ESP_OK; +} + +bool EspClass::partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size) +{ + return esp_partition_erase_range(partition, offset, size) == ESP_OK; +} + +bool EspClass::partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) +{ + return esp_partition_write(partition, offset, data, size) == ESP_OK; +} + +bool EspClass::partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) +{ + return esp_partition_read(partition, offset, data, size) == ESP_OK; +} + +uint64_t EspClass::getEfuseMac(void) +{ + uint64_t _chipmacid = 0LL; + esp_efuse_mac_get_default((uint8_t*) (&_chipmacid)); + return _chipmacid; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Esp.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Esp.h new file mode 100644 index 0000000..478158d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Esp.h @@ -0,0 +1,122 @@ +/* + Esp.h - ESP31B-specific APIs + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ESP_H +#define ESP_H + +#include +#include +#include +#include "esp_cpu.h" + +/** + * AVR macros for WDT managment + */ +typedef enum { + WDTO_0MS = 0, //!< WDTO_0MS + WDTO_15MS = 15, //!< WDTO_15MS + WDTO_30MS = 30, //!< WDTO_30MS + WDTO_60MS = 60, //!< WDTO_60MS + WDTO_120MS = 120, //!< WDTO_120MS + WDTO_250MS = 250, //!< WDTO_250MS + WDTO_500MS = 500, //!< WDTO_500MS + WDTO_1S = 1000,//!< WDTO_1S + WDTO_2S = 2000,//!< WDTO_2S + WDTO_4S = 4000,//!< WDTO_4S + WDTO_8S = 8000 //!< WDTO_8S +} WDTO_t; + + +typedef enum { + FM_QIO = 0x00, + FM_QOUT = 0x01, + FM_DIO = 0x02, + FM_DOUT = 0x03, + FM_FAST_READ = 0x04, + FM_SLOW_READ = 0x05, + FM_UNKNOWN = 0xff +} FlashMode_t; + +typedef enum { + SKETCH_SIZE_TOTAL = 0, + SKETCH_SIZE_FREE = 1 +} sketchSize_t; + +class EspClass +{ +public: + EspClass() {} + ~EspClass() {} + void restart(); + + //Internal RAM + uint32_t getHeapSize(); //total heap size + uint32_t getFreeHeap(); //available heap + uint32_t getMinFreeHeap(); //lowest level of free heap since boot + uint32_t getMaxAllocHeap(); //largest block of heap that can be allocated at once + + //SPI RAM + uint32_t getPsramSize(); + uint32_t getFreePsram(); + uint32_t getMinFreePsram(); + uint32_t getMaxAllocPsram(); + + uint16_t getChipRevision(); + const char * getChipModel(); + uint8_t getChipCores(); + uint32_t getCpuFreqMHz(){ return getCpuFrequencyMhz(); } + inline uint32_t getCycleCount() __attribute__((always_inline)); + + const char * getSdkVersion(); //version of ESP-IDF + const char * getCoreVersion();//version of this core + + void deepSleep(uint32_t time_us); + + uint32_t getFlashChipSize(); + uint32_t getFlashChipSpeed(); + FlashMode_t getFlashChipMode(); + + uint32_t magicFlashChipSize(uint8_t byte); + uint32_t magicFlashChipSpeed(uint8_t byte); + FlashMode_t magicFlashChipMode(uint8_t byte); + + uint32_t getSketchSize(); + String getSketchMD5(); + uint32_t getFreeSketchSpace(); + + bool flashEraseSector(uint32_t sector); + bool flashWrite(uint32_t offset, uint32_t *data, size_t size); + bool flashRead(uint32_t offset, uint32_t *data, size_t size); + + bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size); + bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size); + bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size); + + uint64_t getEfuseMac(); + +}; + +uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount() +{ + return (uint32_t)esp_cpu_get_cycle_count(); +} + +extern EspClass ESP; + +#endif //ESP_H diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FirmwareMSC.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FirmwareMSC.cpp new file mode 100644 index 0000000..638f182 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FirmwareMSC.cpp @@ -0,0 +1,426 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "FirmwareMSC.h" + +#if CONFIG_TINYUSB_MSC_ENABLED + +#include +#include "esp_partition.h" +#include "esp_ota_ops.h" +#include "esp_image_format.h" +#include "esp32-hal.h" +#include "pins_arduino.h" +#include "firmware_msc_fat.h" +#include "spi_flash_mmap.h" + +#ifndef USB_FW_MSC_VENDOR_ID +#define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars +#endif +#ifndef USB_FW_MSC_PRODUCT_ID +#define USB_FW_MSC_PRODUCT_ID "Firmware MSC"//max 16 chars +#endif +#ifndef USB_FW_MSC_PRODUCT_REVISION +#define USB_FW_MSC_PRODUCT_REVISION "1.0" //max 4 chars +#endif +#ifndef USB_FW_MSC_VOLUME_NAME +#define USB_FW_MSC_VOLUME_NAME "ESP32-FWMSC" //max 11 chars +#endif +#ifndef USB_FW_MSC_SERIAL_NUMBER +#define USB_FW_MSC_SERIAL_NUMBER 0x00000000 +#endif + +ESP_EVENT_DEFINE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + +//General Variables +static uint8_t * msc_ram_disk = NULL; +static fat_boot_sector_t * msc_boot = NULL; +static uint8_t * msc_table = NULL; +static uint16_t msc_table_sectors = 0; +static uint16_t msc_total_sectors = 0; +static bool mcs_is_fat16 = false; + +//Firmware Read +static const esp_partition_t* msc_run_partition = NULL; +static uint16_t fw_start_sector = 0; +static uint16_t fw_end_sector = 0; +static size_t fw_size = 0; +static fat_dir_entry_t * fw_entry = NULL; + +//Firmware Write +typedef enum { + MSC_UPDATE_IDLE, + MSC_UPDATE_STARTING, + MSC_UPDATE_RUNNING, + MSC_UPDATE_END +} msc_update_state_t; + +static const esp_partition_t* msc_ota_partition = NULL; +static msc_update_state_t msc_update_state = MSC_UPDATE_IDLE; +static uint16_t msc_update_start_sector = 0; +static uint32_t msc_update_bytes_written = 0; +static fat_dir_entry_t * msc_update_entry = NULL; + +static uint32_t get_firmware_size(const esp_partition_t* partition){ + esp_image_metadata_t data; + const esp_partition_pos_t running_pos = { + .offset = partition->address, + .size = partition->size, + }; + data.start_addr = running_pos.offset; + esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data); + return data.image_len; +} + +//Get number of sectors required based on the size of the firmware and OTA partition +static size_t msc_update_get_required_disk_sectors(){ + size_t data_sectors = 16; + size_t total_sectors = 0; + msc_run_partition = esp_ota_get_running_partition(); + msc_ota_partition = esp_ota_get_next_update_partition(NULL); + if(msc_run_partition){ + fw_size = get_firmware_size(msc_run_partition); + data_sectors += FAT_SIZE_TO_SECTORS(fw_size); + log_d("APP size: %u (%u sectors)", fw_size, FAT_SIZE_TO_SECTORS(fw_size)); + } else { + log_w("APP partition not found. Reading disabled"); + } + if(msc_ota_partition){ + data_sectors += FAT_SIZE_TO_SECTORS(msc_ota_partition->size); + log_d("OTA size: %u (%u sectors)", msc_ota_partition->size, FAT_SIZE_TO_SECTORS(msc_ota_partition->size)); + } else { + log_w("OTA partition not found. Writing disabled"); + } + msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, false); + total_sectors = data_sectors + msc_table_sectors + 2; + if(total_sectors > 0xFF4){ + log_d("USING FAT16"); + mcs_is_fat16 = true; + total_sectors -= msc_table_sectors; + msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, true); + total_sectors += msc_table_sectors; + } else { + log_d("USING FAT12"); + mcs_is_fat16 = false; + } + log_d("FAT sector size: %u", DISK_SECTOR_SIZE); + log_d("FAT data sectors: %u", data_sectors); + log_d("FAT table sectors: %u", msc_table_sectors); + log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024); + return total_sectors; +} + +//setup the ramdisk and add the firmware download file +static bool msc_update_setup_disk(const char * volume_label, uint32_t serial_number){ + msc_total_sectors = msc_update_get_required_disk_sectors(); + uint8_t ram_sectors = msc_table_sectors + 2; + msc_ram_disk = (uint8_t*)calloc(ram_sectors, DISK_SECTOR_SIZE); + if(!msc_ram_disk){ + log_e("Failed to allocate RAM Disk: %u bytes", ram_sectors * DISK_SECTOR_SIZE); + return false; + } + fw_start_sector = ram_sectors; + fw_end_sector = fw_start_sector; + msc_boot = fat_add_boot_sector(msc_ram_disk, msc_total_sectors, msc_table_sectors, fat_file_system_type(mcs_is_fat16), volume_label, serial_number); + msc_table = fat_add_table(msc_ram_disk, msc_boot, mcs_is_fat16); + //fat_dir_entry_t * label = fat_add_label(msc_ram_disk, volume_label); + if(msc_run_partition){ + fw_entry = fat_add_root_file(msc_ram_disk, 0, "FIRMWARE", "BIN", fw_size, 2, mcs_is_fat16); + fw_end_sector = FAT_SIZE_TO_SECTORS(fw_size) + fw_start_sector; + } + return true; +} + +static void msc_update_delete_disk(){ + fw_entry = NULL; + fw_size = 0; + fw_end_sector = 0; + fw_start_sector = 0; + msc_table = NULL; + msc_boot = NULL; + msc_table_sectors = 0; + msc_total_sectors = 0; + msc_run_partition = NULL; + msc_ota_partition = NULL; + msc_update_state = MSC_UPDATE_IDLE; + msc_update_start_sector = 0; + msc_update_bytes_written = 0; + msc_update_entry = NULL; + free(msc_ram_disk); + msc_ram_disk = NULL; +} + +//filter out entries to only include BINs in the root folder +static fat_dir_entry_t * msc_update_get_root_bin_entry(uint8_t index){ + fat_dir_entry_t * entry = (fat_dir_entry_t *)(msc_ram_disk + ((msc_boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t))); + fat_lfn_entry_t * lfn = (fat_lfn_entry_t*)entry; + + //empty entry + if(entry->file_magic == 0){ + return NULL; + } + //long file name + if(lfn->attr == 0x0F && lfn->type == 0x00 && lfn->first_cluster == 0x0000){ + return NULL; + } + //only files marked as archives + if(entry->file_attr != FAT_FILE_ATTR_ARCHIVE){ + return NULL; + } + //deleted + if(entry->file_magic == 0xE5 || entry->file_magic == 0x05){ + return NULL; + } + //not bins + if(memcmp("BIN", entry->file_extension, 3)){ + return NULL; + } + return entry; +} + +//get an empty bin (the host will add an entry for file about to be written with size of zero) +static fat_dir_entry_t * msc_update_find_new_bin(){ + for(uint8_t i=16; i;){ + i--; + fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i); + if(entry && entry->file_size == 0){ + return entry; + } + } + return NULL; +} + +//get a bin starting from particular sector +static fat_dir_entry_t * msc_update_find_bin(uint16_t sector){ + for(uint8_t i=16; i; ){ + i--; + fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i); + if(entry && entry->data_start_sector == (sector - msc_boot->sectors_per_alloc_table)){ + return entry; + } + } + return NULL; +} + +//write the new data and erase the flash blocks when necessary +static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t offset, void *data, size_t size){ + esp_err_t err = ESP_OK; + if((offset & (SPI_FLASH_SEC_SIZE-1)) == 0){ + err = esp_partition_erase_range(partition, offset, SPI_FLASH_SEC_SIZE); + log_v("ERASE[0x%08X]: %s", offset, (err != ESP_OK)?"FAIL":"OK"); + if(err != ESP_OK){ + return err; + } + } + return esp_partition_write(partition, offset, data, size); +} + +//called when error was encountered while updating +static void msc_update_error(){ + log_e("UPDATE_ERROR: %u", msc_update_bytes_written); + arduino_firmware_msc_event_data_t p; + p.error.size = msc_update_bytes_written; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + msc_update_state = MSC_UPDATE_IDLE; + msc_update_entry = NULL; + msc_update_bytes_written = 0; + msc_update_start_sector = 0; +} + +//called when all firmware bytes have been received +static void msc_update_end(){ + log_d("UPDATE_END: %u", msc_update_entry->file_size); + msc_update_state = MSC_UPDATE_END; + size_t ota_size = get_firmware_size(msc_ota_partition); + if(ota_size != msc_update_entry->file_size){ + log_e("OTA SIZE MISMATCH %u != %u", ota_size, msc_update_entry->file_size); + msc_update_error(); + return; + } + if(!ota_size || esp_ota_set_boot_partition(msc_ota_partition) != ESP_OK){ + log_e("ENABLING OTA PARTITION FAILED"); + msc_update_error(); + return; + } + arduino_firmware_msc_event_data_t p; + p.end.size = msc_update_entry->file_size; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); +} + +static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){ + //log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize); + if(lba < fw_start_sector){ + //write to sectors that are in RAM + memcpy(msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, buffer, bufsize); + if(msc_ota_partition && lba == (fw_start_sector - 1)){ + //monitor the root folder table + if(msc_update_state <= MSC_UPDATE_RUNNING){ + fat_dir_entry_t * update_entry = msc_update_find_new_bin(); + if(update_entry) { + if(msc_update_entry) { + log_v("REPLACING ENTRY"); + } else { + log_v("ASSIGNING ENTRY"); + } + if(msc_update_state <= MSC_UPDATE_STARTING){ + msc_update_state = MSC_UPDATE_STARTING; + msc_update_bytes_written = 0; + msc_update_start_sector = 0; + } + msc_update_entry = update_entry; + } else if(msc_update_state == MSC_UPDATE_RUNNING){ + if(!msc_update_entry && msc_update_start_sector){ + msc_update_entry = msc_update_find_bin(msc_update_start_sector); + } + if(msc_update_entry && msc_update_bytes_written >= msc_update_entry->file_size){ + msc_update_end(); + } + } + } + } + } else if(msc_ota_partition && lba >= msc_update_start_sector){ + //handle writes to the region where the new firmware will be uploaded + arduino_firmware_msc_event_data_t p; + if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){ + msc_update_state = MSC_UPDATE_RUNNING; + msc_update_start_sector = lba; + msc_update_bytes_written = 0; + log_d("UPDATE_START: %u (0x%02X)", lba, lba - msc_boot->sectors_per_alloc_table); + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_START_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){ + log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize); + msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize; + p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset; + p.write.size = bufsize; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + } else { + msc_update_error(); + return 0; + } + } else if(msc_update_state == MSC_UPDATE_RUNNING){ + if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written < msc_update_entry->file_size && (msc_update_bytes_written + bufsize) >= msc_update_entry->file_size){ + bufsize = msc_update_entry->file_size - msc_update_bytes_written; + } + if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){ + log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize); + msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize; + p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset; + p.write.size = bufsize; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written >= msc_update_entry->file_size){ + msc_update_end(); + } + } else { + msc_update_error(); + return 0; + } + } + } + return bufsize; +} + +static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){ + //log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize); + if(lba < fw_start_sector){ + memcpy(buffer, msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, bufsize); + } else if(msc_run_partition && lba < fw_end_sector){ + //read the currently running firmware + if(esp_partition_read(msc_run_partition, ((lba - fw_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) != ESP_OK){ + return 0; + } + } else { + memset(buffer, 0, bufsize); + } + return bufsize; +} + +static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){ + //log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject); + arduino_firmware_msc_event_data_t p; + p.power.power_condition = power_condition; + p.power.start = start; + p.power.load_eject = load_eject; + arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_POWER_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY); + return true; +} + +static volatile TaskHandle_t msc_task_handle = NULL; +static void msc_task(void *pvParameters){ + for (;;) { + if(msc_update_state == MSC_UPDATE_END){ + delay(100); + esp_restart(); + } + delay(100); + } + msc_task_handle = NULL; + vTaskDelete(NULL); +} + +FirmwareMSC::FirmwareMSC():msc(){} + +FirmwareMSC::~FirmwareMSC(){ + end(); +} + +bool FirmwareMSC::begin(){ + if(msc_ram_disk){ + return true; + } + + if(!msc_update_setup_disk(USB_FW_MSC_VOLUME_NAME, USB_FW_MSC_SERIAL_NUMBER)){ + return false; + } + + if(!msc_task_handle){ + xTaskCreateUniversal(msc_task, "msc_disk", 1024, NULL, 2, (TaskHandle_t*)&msc_task_handle, 0); + if(!msc_task_handle){ + msc_update_delete_disk(); + return false; + } + } + + msc.vendorID(USB_FW_MSC_VENDOR_ID); + msc.productID(USB_FW_MSC_PRODUCT_ID); + msc.productRevision(USB_FW_MSC_PRODUCT_REVISION); + msc.onStartStop(msc_start_stop); + msc.onRead(msc_read); + msc.onWrite(msc_write); + msc.mediaPresent(true); + msc.begin(msc_boot->fat12_sector_num, DISK_SECTOR_SIZE); + return true; +} + +void FirmwareMSC::end(){ + msc.end(); + if(msc_task_handle){ + vTaskDelete(msc_task_handle); + msc_task_handle = NULL; + } + msc_update_delete_disk(); +} + +void FirmwareMSC::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_FIRMWARE_MSC_ANY_EVENT, callback); +} +void FirmwareMSC::onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_FIRMWARE_MSC_EVENTS, event, callback, this); +} + +#if ARDUINO_USB_MSC_ON_BOOT +FirmwareMSC MSC_Update; +#endif + +#endif /* CONFIG_USB_MSC_ENABLED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FirmwareMSC.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FirmwareMSC.h new file mode 100644 index 0000000..570feac --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FirmwareMSC.h @@ -0,0 +1,70 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include +#include "USBMSC.h" + +#if CONFIG_TINYUSB_MSC_ENABLED + +#include "esp_event.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS); + +typedef enum { + ARDUINO_FIRMWARE_MSC_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_FIRMWARE_MSC_START_EVENT = 0, + ARDUINO_FIRMWARE_MSC_WRITE_EVENT, + ARDUINO_FIRMWARE_MSC_END_EVENT, + ARDUINO_FIRMWARE_MSC_ERROR_EVENT, + ARDUINO_FIRMWARE_MSC_POWER_EVENT, + ARDUINO_FIRMWARE_MSC_MAX_EVENT, +} arduino_firmware_msc_event_t; + +typedef union { + struct { + size_t offset; + size_t size; + } write; + struct { + uint8_t power_condition; + bool start; + bool load_eject; + } power; + struct { + size_t size; + } end; + struct { + size_t size; + } error; +} arduino_firmware_msc_event_data_t; + +class FirmwareMSC { +private: + USBMSC msc; + +public: + FirmwareMSC(); + ~FirmwareMSC(); + bool begin(); + void end(); + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback); +}; + +#if ARDUINO_USB_MSC_ON_BOOT +extern FirmwareMSC MSC_Update; +#endif + +#endif /* CONFIG_TINYUSB_MSC_ENABLED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FunctionalInterrupt.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FunctionalInterrupt.cpp new file mode 100644 index 0000000..c5a8d37 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FunctionalInterrupt.cpp @@ -0,0 +1,44 @@ +/* + * FunctionalInterrupt.cpp + * + * Created on: 8 jul. 2018 + * Author: Herman + */ + +#include "FunctionalInterrupt.h" +#include "Arduino.h" + +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); + +extern "C" +{ + extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional); +} + +void ARDUINO_ISR_ATTR interruptFunctional(void* arg) +{ + InterruptArgStructure* localArg = (InterruptArgStructure*)arg; + if (localArg->interruptFunction) + { + localArg->interruptFunction(); + } +} + +void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) +{ + // use the local interrupt routine which takes the ArgStructure as argument + __attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true); +} + +extern "C" +{ + void cleanupFunctional(void* arg) + { + delete (InterruptArgStructure*)arg; + } +} + + + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FunctionalInterrupt.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FunctionalInterrupt.h new file mode 100644 index 0000000..69bb5ae --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/FunctionalInterrupt.h @@ -0,0 +1,21 @@ +/* + * FunctionalInterrupt.h + * + * Created on: 8 jul. 2018 + * Author: Herman + */ + +#ifndef CORE_CORE_FUNCTIONALINTERRUPT_H_ +#define CORE_CORE_FUNCTIONALINTERRUPT_H_ + +#include +#include + +struct InterruptArgStructure { + std::function interruptFunction; +}; + +void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); + + +#endif /* CORE_CORE_FUNCTIONALINTERRUPT_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HWCDC.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HWCDC.cpp new file mode 100644 index 0000000..189eb3b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HWCDC.cpp @@ -0,0 +1,447 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "USB.h" +#if SOC_USB_SERIAL_JTAG_SUPPORTED + +#include "esp32-hal.h" +#include "esp32-hal-periman.h" +#include "HWCDC.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/ringbuf.h" +#include "esp_intr_alloc.h" +#include "soc/periph_defs.h" +#include "soc/io_mux_reg.h" +#pragma GCC diagnostic ignored "-Wvolatile" +#include "hal/usb_serial_jtag_ll.h" +#pragma GCC diagnostic warning "-Wvolatile" +#include "rom/ets_sys.h" + +ESP_EVENT_DEFINE_BASE(ARDUINO_HW_CDC_EVENTS); + +static RingbufHandle_t tx_ring_buf = NULL; +static QueueHandle_t rx_queue = NULL; +static uint8_t rx_data_buf[64] = {0}; +static intr_handle_t intr_handle = NULL; +static volatile bool initial_empty = false; +static SemaphoreHandle_t tx_lock = NULL; + +// workaround for when USB CDC is not connected +static uint32_t tx_timeout_ms = 0; +static bool tx_timeout_change_request = false; + +static esp_event_loop_handle_t arduino_hw_cdc_event_loop_handle = NULL; + +static esp_err_t arduino_hw_cdc_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, BaseType_t *task_unblocked){ + if(arduino_hw_cdc_event_loop_handle == NULL){ + return ESP_FAIL; + } + return esp_event_isr_post_to(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_data, event_data_size, task_unblocked); +} + +static esp_err_t arduino_hw_cdc_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){ + if (!arduino_hw_cdc_event_loop_handle) { + esp_event_loop_args_t event_task_args = { + .queue_size = 5, + .task_name = "arduino_hw_cdc_events", + .task_priority = 5, + .task_stack_size = 2048, + .task_core_id = tskNO_AFFINITY + }; + if (esp_event_loop_create(&event_task_args, &arduino_hw_cdc_event_loop_handle) != ESP_OK) { + log_e("esp_event_loop_create failed"); + } + } + if(arduino_hw_cdc_event_loop_handle == NULL){ + return ESP_FAIL; + } + return esp_event_handler_register_with(arduino_hw_cdc_event_loop_handle, event_base, event_id, event_handler, event_handler_arg); +} + +static void hw_cdc_isr_handler(void *arg) { + portBASE_TYPE xTaskWoken = 0; + uint32_t usbjtag_intr_status = 0; + arduino_hw_cdc_event_data_t event = {0}; + usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); + + if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { + // Interrupt tells us the host picked up the data we sent. + if (usb_serial_jtag_ll_txfifo_writable() == 1) { + // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send. + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + if(!initial_empty){ + initial_empty = true; + // First time USB is plugged and the application has not explicitly set TX Timeout, set it to default 100ms. + // Otherwise, USB is still unplugged and the timeout will be kept as Zero in order to avoid any delay in the + // application whenever it uses write() and the TX Queue gets full. + if (!tx_timeout_change_request) { + tx_timeout_ms = 100; + } + //send event? + //ets_printf("CONNECTED\n"); + arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_CONNECTED_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); + } + size_t queued_size; + uint8_t *queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(tx_ring_buf, &queued_size, 64); + // If the hardware fifo is avaliable, write in it. Otherwise, do nothing. + if (queued_buff != NULL) { //Although tx_queued_bytes may be larger than 0. We may have interrupt before xRingbufferSend() was called. + //Copy the queued buffer into the TX FIFO + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + usb_serial_jtag_ll_write_txfifo(queued_buff, queued_size); + usb_serial_jtag_ll_txfifo_flush(); + vRingbufferReturnItemFromISR(tx_ring_buf, queued_buff, &xTaskWoken); + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + //send event? + //ets_printf("TX:%u\n", queued_size); + event.tx.len = queued_size; + arduino_hw_cdc_event_post(ARDUINO_HW_CDC_EVENTS, ARDUINO_HW_CDC_TX_EVENT, &event, sizeof(arduino_hw_cdc_event_data_t), &xTaskWoken); + } + } else { + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + } + } + + if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) { + // read rx buffer(max length is 64), and send avaliable data to ringbuffer. + // Ensure the rx buffer size is larger than RX_MAX_SIZE. + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); + uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(rx_data_buf, 64); + uint32_t i=0; + for(i=0; i size){ + space = size; + } + // Non-Blocking method, Sending data to ringbuffer, and handle the data in ISR. + if(xRingbufferSend(tx_ring_buf, (void*) (buffer), space, 0) != pdTRUE){ + size = 0; + } else { + to_send -= space; + so_far += space; + // Now trigger the ISR to read data from the ring buffer. + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + + while(to_send){ + if(max_size > to_send){ + max_size = to_send; + } + // Blocking method, Sending data to ringbuffer, and handle the data in ISR. + if(xRingbufferSend(tx_ring_buf, (void*) (buffer+so_far), max_size, tx_timeout_ms / portTICK_PERIOD_MS) != pdTRUE){ + size = so_far; + break; + } + so_far += max_size; + to_send -= max_size; + // Now trigger the ISR to read data from the ring buffer. + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + } + } + xSemaphoreGive(tx_lock); + return size; +} + +size_t HWCDC::write(uint8_t c) +{ + return write(&c, 1); +} + +void HWCDC::flush(void) +{ + if(tx_ring_buf == NULL || tx_lock == NULL){ + return; + } + if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ + return; + } + UBaseType_t uxItemsWaiting = 0; + vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); + if(uxItemsWaiting){ + // Now trigger the ISR to read data from the ring buffer. + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + } + while(uxItemsWaiting){ + delay(5); + vRingbufferGetInfo(tx_ring_buf, NULL, NULL, NULL, NULL, &uxItemsWaiting); + } + xSemaphoreGive(tx_lock); +} + +/* + * READING +*/ + +size_t HWCDC::setRxBufferSize(size_t rx_queue_len){ + if(rx_queue){ + vQueueDelete(rx_queue); + rx_queue = NULL; + } + if(!rx_queue_len){ + return 0; + } + rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); + if(!rx_queue){ + return 0; + } + return rx_queue_len; +} + +int HWCDC::available(void) +{ + if(rx_queue == NULL){ + return -1; + } + return uxQueueMessagesWaiting(rx_queue); +} + +int HWCDC::peek(void) +{ + if(rx_queue == NULL){ + return -1; + } + uint8_t c; + if(xQueuePeek(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +int HWCDC::read(void) +{ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + if(xQueueReceive(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +size_t HWCDC::read(uint8_t *buffer, size_t size) +{ + if(rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + size_t count = 0; + while(count < size && xQueueReceive(rx_queue, &c, 0)){ + buffer[count++] = c; + } + return count; +} + +/* + * DEBUG +*/ + +void HWCDC::setDebugOutput(bool en) +{ + if(en) { + uartSetDebug(NULL); + ets_install_putc1((void (*)(char)) &cdc0_write_char); + } else { + ets_install_putc1(NULL); + } +} + +#if ARDUINO_USB_MODE +#if ARDUINO_USB_CDC_ON_BOOT//Serial used for USB CDC +HWCDC Serial; +#else +HWCDC USBSerial; +#endif +#endif + +#endif /* SOC_USB_SERIAL_JTAG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HWCDC.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HWCDC.h new file mode 100644 index 0000000..b332ae8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HWCDC.h @@ -0,0 +1,114 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +#if SOC_USB_SERIAL_JTAG_SUPPORTED + +#include +#include "esp_event.h" +#include "Stream.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_HW_CDC_EVENTS); + +typedef enum { + ARDUINO_HW_CDC_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_HW_CDC_CONNECTED_EVENT = 0, + ARDUINO_HW_CDC_BUS_RESET_EVENT, + ARDUINO_HW_CDC_RX_EVENT, + ARDUINO_HW_CDC_TX_EVENT, + ARDUINO_HW_CDC_MAX_EVENT, +} arduino_hw_cdc_event_t; + +typedef union { + struct { + size_t len; + } rx; + struct { + size_t len; + } tx; +} arduino_hw_cdc_event_data_t; + +class HWCDC: public Stream +{ +private: + static bool deinit(void * busptr); + +public: + HWCDC(); + ~HWCDC(); + + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_hw_cdc_event_t event, esp_event_handler_t callback); + + size_t setRxBufferSize(size_t); + size_t setTxBufferSize(size_t); + void setTxTimeoutMs(uint32_t timeout); + void begin(unsigned long baud=0); + void end(); + + int available(void); + int availableForWrite(void); + int peek(void); + int read(void); + size_t read(uint8_t *buffer, size_t size); + size_t write(uint8_t); + size_t write(const uint8_t *buffer, size_t size); + void flush(void); + + inline size_t read(char * buffer, size_t size) + { + return read((uint8_t*) buffer, size); + } + inline size_t write(const char * buffer, size_t size) + { + return write((uint8_t*) buffer, size); + } + inline size_t write(const char * s) + { + return write((uint8_t*) s, strlen(s)); + } + inline size_t write(unsigned long n) + { + return write((uint8_t) n); + } + inline size_t write(long n) + { + return write((uint8_t) n); + } + inline size_t write(unsigned int n) + { + return write((uint8_t) n); + } + inline size_t write(int n) + { + return write((uint8_t) n); + } + operator bool() const; + void setDebugOutput(bool); + uint32_t baudRate(){return 115200;} + +}; + +#if ARDUINO_USB_MODE +#if ARDUINO_USB_CDC_ON_BOOT//Serial used for USB CDC +extern HWCDC Serial; +#else +extern HWCDC USBSerial; +#endif +#endif + +#endif /* CONFIG_IDF_TARGET_ESP32C3 */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HardwareSerial.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HardwareSerial.cpp new file mode 100644 index 0000000..1780da4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HardwareSerial.cpp @@ -0,0 +1,627 @@ +#include +#include +#include +#include +#include + +#include "pins_arduino.h" +#include "HardwareSerial.h" +#include "soc/soc_caps.h" +#include "driver/uart.h" +#include "freertos/queue.h" + +#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE +#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048 +#endif + +#ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY +#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES-1) +#endif + +#ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE +#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1 +#endif + +#ifndef SOC_RX0 +#if CONFIG_IDF_TARGET_ESP32 +#define SOC_RX0 3 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#define SOC_RX0 44 +#elif CONFIG_IDF_TARGET_ESP32C3 +#define SOC_RX0 20 +#elif CONFIG_IDF_TARGET_ESP32C6 +#define SOC_RX0 17 +#elif CONFIG_IDF_TARGET_ESP32H2 +#define SOC_RX0 23 +#endif +#endif + +#ifndef SOC_TX0 +#if CONFIG_IDF_TARGET_ESP32 +#define SOC_TX0 1 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#define SOC_TX0 43 +#elif CONFIG_IDF_TARGET_ESP32C3 +#define SOC_TX0 21 +#elif CONFIG_IDF_TARGET_ESP32C6 +#define SOC_TX0 16 +#elif CONFIG_IDF_TARGET_ESP32H2 +#define SOC_TX0 24 +#endif +#endif + +void serialEvent(void) __attribute__((weak)); +void serialEvent(void) {} + +#if SOC_UART_NUM > 1 + +#ifndef RX1 +#if CONFIG_IDF_TARGET_ESP32 +#define RX1 9 +#elif CONFIG_IDF_TARGET_ESP32S2 +#define RX1 18 +#elif CONFIG_IDF_TARGET_ESP32C3 +#define RX1 18 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define RX1 15 +#elif CONFIG_IDF_TARGET_ESP32C6 +#define RX1 4 +#elif CONFIG_IDF_TARGET_ESP32H2 +#define RX1 0 +#endif +#endif + +#ifndef TX1 +#if CONFIG_IDF_TARGET_ESP32 +#define TX1 10 +#elif CONFIG_IDF_TARGET_ESP32S2 +#define TX1 17 +#elif CONFIG_IDF_TARGET_ESP32C3 +#define TX1 19 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define TX1 16 +#elif CONFIG_IDF_TARGET_ESP32C6 +#define TX1 5 +#elif CONFIG_IDF_TARGET_ESP32H2 +#define TX1 1 +#endif +#endif + +void serialEvent1(void) __attribute__((weak)); +void serialEvent1(void) {} +#endif /* SOC_UART_NUM > 1 */ + +#if SOC_UART_NUM > 2 +#ifndef RX2 +#if CONFIG_IDF_TARGET_ESP32 +#define RX2 16 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define RX2 19 +#endif +#endif + +#ifndef TX2 +#if CONFIG_IDF_TARGET_ESP32 +#define TX2 17 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define TX2 20 +#endif +#endif + +void serialEvent2(void) __attribute__((weak)); +void serialEvent2(void) {} +#endif /* SOC_UART_NUM > 2 */ + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC +HardwareSerial Serial0(0); +#else +HardwareSerial Serial(0); +#endif +#if SOC_UART_NUM > 1 +HardwareSerial Serial1(1); +#endif +#if SOC_UART_NUM > 2 +HardwareSerial Serial2(2); +#endif + +void serialEventRun(void) +{ +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC + if(Serial0.available()) serialEvent(); +#else + if(Serial.available()) serialEvent(); +#endif +#if SOC_UART_NUM > 1 + if(Serial1.available()) serialEvent1(); +#endif +#if SOC_UART_NUM > 2 + if(Serial2.available()) serialEvent2(); +#endif +} +#endif + +#if !CONFIG_DISABLE_HAL_LOCKS +#define HSERIAL_MUTEX_LOCK() do {} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS) +#define HSERIAL_MUTEX_UNLOCK() xSemaphoreGive(_lock) +#else +#define HSERIAL_MUTEX_LOCK() +#define HSERIAL_MUTEX_UNLOCK() +#endif + +HardwareSerial::HardwareSerial(uint8_t uart_nr) : +_uart_nr(uart_nr), +_uart(NULL), +_rxBufferSize(256), +_txBufferSize(0), +_onReceiveCB(NULL), +_onReceiveErrorCB(NULL), +_onReceiveTimeout(false), +_rxTimeout(2), +_rxFIFOFull(0), +_eventTask(NULL) +#if !CONFIG_DISABLE_HAL_LOCKS + ,_lock(NULL) +#endif +{ +#if !CONFIG_DISABLE_HAL_LOCKS + if(_lock == NULL){ + _lock = xSemaphoreCreateMutex(); + if(_lock == NULL){ + log_e("xSemaphoreCreateMutex failed"); + return; + } + } +#endif + // sets UART0 (default console) RX/TX pins as already configured in boot + if (uart_nr == 0) { + setPins(SOC_RX0, SOC_TX0); + } + // set deinit function in the Peripheral Manager + uart_init_PeriMan(); +} + +HardwareSerial::~HardwareSerial() +{ + end(); +#if !CONFIG_DISABLE_HAL_LOCKS + if(_lock != NULL){ + vSemaphoreDelete(_lock); + } +#endif +} + + +void HardwareSerial::_createEventTask(void *args) +{ + // Creating UART event Task + xTaskCreateUniversal(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE); + if (_eventTask == NULL) { + log_e(" -- UART%d Event Task not Created!", _uart_nr); + } +} + +void HardwareSerial::_destroyEventTask(void) +{ + if (_eventTask != NULL) { + vTaskDelete(_eventTask); + _eventTask = NULL; + } +} + +void HardwareSerial::onReceiveError(OnReceiveErrorCb function) +{ + HSERIAL_MUTEX_LOCK(); + // function may be NULL to cancel onReceive() from its respective task + _onReceiveErrorCB = function; + // this can be called after Serial.begin(), therefore it shall create the event task + if (function != NULL && _uart != NULL && _eventTask == NULL) { + _createEventTask(this); + } + HSERIAL_MUTEX_UNLOCK(); +} + +void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) +{ + HSERIAL_MUTEX_LOCK(); + // function may be NULL to cancel onReceive() from its respective task + _onReceiveCB = function; + + // setting the callback to NULL will just disable it + if (_onReceiveCB != NULL) { + // When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes + _onReceiveTimeout = _rxTimeout > 0 ? onlyOnTimeout : false; + + // in case that onReceive() shall work only with RX Timeout, FIFO shall be high + // this is a work around for an IDF issue with events and low FIFO Full value (< 3) + if (_onReceiveTimeout) { + uartSetRxFIFOFull(_uart, 120); + log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); + } + + // this method can be called after Serial.begin(), therefore it shall create the event task + if (_uart != NULL && _eventTask == NULL) { + _createEventTask(this); // Create event task + } + } + HSERIAL_MUTEX_UNLOCK(); +} + +// This function allow the user to define how many bytes will trigger an Interrupt that will copy RX FIFO to the internal RX Ringbuffer +// ISR will also move data from FIFO to RX Ringbuffer after a RX Timeout defined in HardwareSerial::setRxTimeout(uint8_t symbols_timeout) +// A low value of FIFO Full bytes will consume more CPU time within the ISR +// A high value of FIFO Full bytes will make the application wait longer to have byte available for the Stkech in a streaming scenario +// Both RX FIFO Full and RX Timeout may affect when onReceive() will be called +bool HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) +{ + HSERIAL_MUTEX_LOCK(); + // in case that onReceive() shall work only with RX Timeout, FIFO shall be high + // this is a work around for an IDF issue with events and low FIFO Full value (< 3) + if (_onReceiveCB != NULL && _onReceiveTimeout) { + fifoBytes = 120; + log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); + } + bool retCode = uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout + if (fifoBytes > 0 && fifoBytes < SOC_UART_FIFO_LEN - 1) _rxFIFOFull = fifoBytes; + HSERIAL_MUTEX_UNLOCK(); + return retCode; +} + +// timout is calculates in time to receive UART symbols at the UART baudrate. +// the estimation is about 11 bits per symbol (SERIAL_8N1) +bool HardwareSerial::setRxTimeout(uint8_t symbols_timeout) +{ + HSERIAL_MUTEX_LOCK(); + + // Zero disables timeout, thus, onReceive callback will only be called when RX FIFO reaches 120 bytes + // Any non-zero value will activate onReceive callback based on UART baudrate with about 11 bits per symbol + _rxTimeout = symbols_timeout; + if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag + + bool retCode = uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout + + HSERIAL_MUTEX_UNLOCK(); + return retCode; +} + +void HardwareSerial::eventQueueReset() +{ + QueueHandle_t uartEventQueue = NULL; + if (_uart == NULL) { + return; + } + uartGetEventQueue(_uart, &uartEventQueue); + if (uartEventQueue != NULL) { + xQueueReset(uartEventQueue); + } +} + +void HardwareSerial::_uartEventTask(void *args) +{ + HardwareSerial *uart = (HardwareSerial *)args; + uart_event_t event; + QueueHandle_t uartEventQueue = NULL; + uartGetEventQueue(uart->_uart, &uartEventQueue); + if (uartEventQueue != NULL) { + for(;;) { + //Waiting for UART event. + if(xQueueReceive(uartEventQueue, (void * )&event, (TickType_t)portMAX_DELAY)) { + hardwareSerial_error_t currentErr = UART_NO_ERROR; + switch(event.type) { + case UART_DATA: + if(uart->_onReceiveCB && uart->available() > 0 && + ((uart->_onReceiveTimeout && event.timeout_flag) || !uart->_onReceiveTimeout) ) + uart->_onReceiveCB(); + break; + case UART_FIFO_OVF: + log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); + currentErr = UART_FIFO_OVF_ERROR; + break; + case UART_BUFFER_FULL: + log_w("UART%d Buffer Full. Consider increasing your buffer size of your Application.", uart->_uart_nr); + currentErr = UART_BUFFER_FULL_ERROR; + break; + case UART_BREAK: + log_w("UART%d RX break.", uart->_uart_nr); + currentErr = UART_BREAK_ERROR; + break; + case UART_PARITY_ERR: + log_w("UART%d parity error.", uart->_uart_nr); + currentErr = UART_PARITY_ERROR; + break; + case UART_FRAME_ERR: + log_w("UART%d frame error.", uart->_uart_nr); + currentErr = UART_FRAME_ERROR; + break; + default: + log_w("UART%d unknown event type %d.", uart->_uart_nr, event.type); + break; + } + if (currentErr != UART_NO_ERROR) { + if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(currentErr); + } + } + } + } + vTaskDelete(NULL); +} + +void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd) +{ + if(_uart_nr >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_NUM - 1); + return; + } + +#if !CONFIG_DISABLE_HAL_LOCKS + if(_lock == NULL){ + log_e("MUTEX Lock failed. Can't begin."); + return; + } +#endif + + HSERIAL_MUTEX_LOCK(); + // First Time or after end() --> set default Pins + if (!uartIsDriverInstalled(_uart)) { + // get previously used RX/TX pins, if any. + int8_t _rxPin = uart_get_RxPin(_uart_nr); + int8_t _txPin = uart_get_TxPin(_uart_nr); + switch (_uart_nr) { + case UART_NUM_0: + if (rxPin < 0 && txPin < 0) { + // do not change RX0/TX0 if it has already been set before + rxPin = _rxPin < 0 ? SOC_RX0 : _rxPin; + txPin = _txPin < 0 ? SOC_TX0 : _txPin; + } + break; +#if SOC_UART_NUM > 1 // may save some flash bytes... + case UART_NUM_1: + if (rxPin < 0 && txPin < 0) { + // do not change RX1/TX1 if it has already been set before + rxPin = _rxPin < 0 ? RX1 : _rxPin; + txPin = _txPin < 0 ? TX1 : _txPin; + } + break; +#endif +#if SOC_UART_NUM > 2 // may save some flash bytes... + case UART_NUM_2: + if (rxPin < 0 && txPin < 0) { + // do not change RX2/TX2 if it has already been set before + rxPin = _rxPin < 0 ? RX2 : _rxPin; + txPin = _txPin < 0 ? TX2 : _txPin; + } + break; +#endif + } + } + + if(_uart) { + // in this case it is a begin() over a previous begin() - maybe to change baud rate + // thus do not disable debug output + end(false); + } + + // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. + // it will detach previous UART attached pins + _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); + if (!baud) { + // using baud rate as zero, forces it to try to detect the current baud rate in place + uartStartDetectBaudrate(_uart); + time_t startMillis = millis(); + unsigned long detectedBaudRate = 0; + while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) { + yield(); + } + + end(false); + + if(detectedBaudRate) { + delay(100); // Give some time... + _uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); + } else { + log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible"); + _uart = NULL; + } + } + // create a task to deal with Serial Events when, for example, calling begin() twice to change the baudrate, + // or when setting the callback before calling begin() + if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) { + _createEventTask(this); + } + + // Set UART RX timeout + uartSetRxTimeout(_uart, _rxTimeout); + + // Set UART FIFO Full depending on the baud rate. + // Lower baud rates will force to emulate byte-by-byte reading + // Higher baud rates will keep IDF default of 120 bytes for FIFO FULL Interrupt + // It can also be changed by the application at any time + if (!_rxFIFOFull) { // it has not being changed before calling begin() + // set a default FIFO Full value for the IDF driver + uint8_t fifoFull = 1; + if (baud > 57600 || (_onReceiveCB != NULL && _onReceiveTimeout)) { + fifoFull = 120; + } + uartSetRxFIFOFull(_uart, fifoFull); + _rxFIFOFull = fifoFull; + } + + HSERIAL_MUTEX_UNLOCK(); +} + +void HardwareSerial::updateBaudRate(unsigned long baud) +{ + uartSetBaudRate(_uart, baud); +} + +void HardwareSerial::end(bool fullyTerminate) +{ + // default Serial.end() will completely disable HardwareSerial, + // including any tasks or debug message channel (log_x()) - but not for IDF log messages! + if(fullyTerminate) { + _onReceiveCB = NULL; + _onReceiveErrorCB = NULL; + if (uartGetDebug() == _uart_nr) { + uartSetDebug(0); + } + _rxFIFOFull = 0; + uartEnd(_uart_nr); // fully detach all pins and delete the UART driver + } else { + // do not invalidate callbacks, detach pins, invalidate DBG output + uart_driver_delete(_uart_nr); + } + + uartEnd(_uart_nr); + _uart = 0; + _destroyEventTask(); +} + +void HardwareSerial::setDebugOutput(bool en) +{ + if(_uart == 0) { + return; + } + if(en) { + uartSetDebug(_uart); + } else { + if(uartGetDebug() == _uart_nr) { + uartSetDebug(NULL); + } + } +} + +int HardwareSerial::available(void) +{ + return uartAvailable(_uart); +} +int HardwareSerial::availableForWrite(void) +{ + return uartAvailableForWrite(_uart); +} + +int HardwareSerial::peek(void) +{ + if (available()) { + return uartPeek(_uart); + } + return -1; +} + +int HardwareSerial::read(void) +{ + uint8_t c = 0; + if (uartReadBytes(_uart, &c, 1, 0) == 1) { + return c; + } else { + return -1; + } +} + +// read characters into buffer +// terminates if size characters have been read, or no further are pending +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +size_t HardwareSerial::read(uint8_t *buffer, size_t size) +{ + return uartReadBytes(_uart, buffer, size, 0); +} + +// Overrides Stream::readBytes() to be faster using IDF +size_t HardwareSerial::readBytes(uint8_t *buffer, size_t length) +{ + return uartReadBytes(_uart, buffer, length, (uint32_t)getTimeout()); +} + +void HardwareSerial::flush(void) +{ + uartFlush(_uart); +} + +void HardwareSerial::flush(bool txOnly) +{ + uartFlushTxOnly(_uart, txOnly); +} + +size_t HardwareSerial::write(uint8_t c) +{ + uartWrite(_uart, c); + return 1; +} + +size_t HardwareSerial::write(const uint8_t *buffer, size_t size) +{ + uartWriteBuf(_uart, buffer, size); + return size; +} + +uint32_t HardwareSerial::baudRate() +{ + return uartGetBaudRate(_uart); +} +HardwareSerial::operator bool() const +{ + return uartIsDriverInstalled(_uart); +} + +void HardwareSerial::setRxInvert(bool invert) +{ + uartSetRxInvert(_uart, invert); +} + +// negative Pin value will keep it unmodified +// can be called after or before begin() +bool HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + // uartSetPins() checks if pins are valid and, if necessary, detaches the previous ones + return uartSetPins(_uart_nr, rxPin, txPin, ctsPin, rtsPin); +} + +// Enables or disables Hardware Flow Control using RTS and/or CTS pins +// must use setAllPins() in order to set RTS/CTS pins +// SerialHwFlowCtrl = UART_HW_FLOWCTRL_DISABLE, UART_HW_FLOWCTRL_RTS, +// UART_HW_FLOWCTRL_CTS, UART_HW_FLOWCTRL_CTS_RTS +bool HardwareSerial::setHwFlowCtrlMode(SerialHwFlowCtrl mode, uint8_t threshold) +{ + return uartSetHwFlowCtrlMode(_uart, mode, threshold); +} + +// Sets the uart mode in the esp32 uart for use with RS485 modes +// HwFlowCtrl must be disabled and RTS pin set +// SerialMode = UART_MODE_UART, UART_MODE_RS485_HALF_DUPLEX, UART_MODE_IRDA, +// or testing mode: UART_MODE_RS485_COLLISION_DETECT, UART_MODE_RS485_APP_CTRL +bool HardwareSerial::setMode(SerialMode mode) +{ + return uartSetMode(_uart, mode); +} + +size_t HardwareSerial::setRxBufferSize(size_t new_size) { + + if (_uart) { + log_e("RX Buffer can't be resized when Serial is already running.\n"); + return 0; + } + + if (new_size <= SOC_UART_FIFO_LEN) { + log_e("RX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN); // ESP32, S2, S3 and C3 means higher than 128 + return 0; + } + + _rxBufferSize = new_size; + return _rxBufferSize; +} + +size_t HardwareSerial::setTxBufferSize(size_t new_size) { + + if (_uart) { + log_e("TX Buffer can't be resized when Serial is already running.\n"); + return 0; + } + + if (new_size <= SOC_UART_FIFO_LEN) { + log_e("TX Buffer must be higher than %d.\n", SOC_UART_FIFO_LEN); // ESP32, S2, S3 and C3 means higher than 128 + return 0; + } + + _txBufferSize = new_size; + return _txBufferSize; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HardwareSerial.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HardwareSerial.h new file mode 100644 index 0000000..459d5f3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/HardwareSerial.h @@ -0,0 +1,260 @@ +/* + HardwareSerial.h - Hardware serial library for Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 28 September 2010 by Mark Sproul + Modified 14 August 2012 by Alarus + Modified 3 December 2013 by Matthijs Kooijman + Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support) + Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266) + Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266) + Modified 13 October 2018 by Jeroen Döll (add baudrate detection) + Baudrate detection example usage (detection on Serial1): + void setup() { + Serial.begin(115200); + delay(100); + Serial.println(); + + Serial1.begin(0, SERIAL_8N1, -1, -1, true, 11000UL); // Passing 0 for baudrate to detect it, the last parameter is a timeout in ms + + unsigned long detectedBaudRate = Serial1.baudRate(); + if(detectedBaudRate) { + Serial.printf("Detected baudrate is %lu\n", detectedBaudRate); + } else { + Serial.println("No baudrate detected, Serial1 will not work!"); + } + } + + Pay attention: the baudrate returned by baudRate() may be rounded, eg 115200 returns 115201 + */ + +#ifndef HardwareSerial_h +#define HardwareSerial_h + +#include +#include +#include "Stream.h" +#include "esp32-hal.h" +#include "soc/soc_caps.h" +#include "HWCDC.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +enum SerialConfig { + SERIAL_5N1 = 0x8000010, + SERIAL_6N1 = 0x8000014, + SERIAL_7N1 = 0x8000018, + SERIAL_8N1 = 0x800001c, + SERIAL_5N2 = 0x8000030, + SERIAL_6N2 = 0x8000034, + SERIAL_7N2 = 0x8000038, + SERIAL_8N2 = 0x800003c, + SERIAL_5E1 = 0x8000012, + SERIAL_6E1 = 0x8000016, + SERIAL_7E1 = 0x800001a, + SERIAL_8E1 = 0x800001e, + SERIAL_5E2 = 0x8000032, + SERIAL_6E2 = 0x8000036, + SERIAL_7E2 = 0x800003a, + SERIAL_8E2 = 0x800003e, + SERIAL_5O1 = 0x8000013, + SERIAL_6O1 = 0x8000017, + SERIAL_7O1 = 0x800001b, + SERIAL_8O1 = 0x800001f, + SERIAL_5O2 = 0x8000033, + SERIAL_6O2 = 0x8000037, + SERIAL_7O2 = 0x800003b, + SERIAL_8O2 = 0x800003f +}; + +typedef uart_mode_t SerialMode; +typedef uart_hw_flowcontrol_t SerialHwFlowCtrl; + +typedef enum { + UART_NO_ERROR, + UART_BREAK_ERROR, + UART_BUFFER_FULL_ERROR, + UART_FIFO_OVF_ERROR, + UART_FRAME_ERROR, + UART_PARITY_ERROR +} hardwareSerial_error_t; + +typedef std::function OnReceiveCb; +typedef std::function OnReceiveErrorCb; + +class HardwareSerial: public Stream +{ +public: + HardwareSerial(uint8_t uart_nr); + ~HardwareSerial(); + + // setRxTimeout sets the timeout after which onReceive callback will be called (after receiving data, it waits for this time of UART rx inactivity to call the callback fnc) + // param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout. + // Maximum timeout setting is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console). + // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). + // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. + // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms + bool setRxTimeout(uint8_t symbols_timeout); + + // setRxFIFOFull(uint8_t fifoBytes) will set the number of bytes that will trigger UART_INTR_RXFIFO_FULL interrupt and fill up RxRingBuffer + // This affects some functions such as Serial::available() and Serial.read() because, in a UART flow of receiving data, Serial internal + // RxRingBuffer will be filled only after these number of bytes arrive or a RX Timeout happens. + // This parameter can be set to 1 in order to receive byte by byte, but it will also consume more CPU time as the ISR will be activates often. + bool setRxFIFOFull(uint8_t fifoBytes); + + // onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT) + // UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF) + // UART_INTR_RXFIFO_TOUT interrupt triggers at UART_TOUT_THRESH_DEFAULT symbols passed without any reception (defined as 10 symbos by default in IDF) + // onlyOnTimeout parameter will define how onReceive will behave: + // Default: true -- The callback will only be called when RX Timeout happens. + // Whole stream of bytes will be ready for being read on the callback function at once. + // This option may lead to Rx Overflow depending on the Rx Buffer Size and number of bytes received in the streaming + // false -- The callback will be called when FIFO reaches 120 bytes and also on RX Timeout. + // The stream of incommig bytes will be "split" into blocks of 120 bytes on each callback. + // This option avoid any sort of Rx Overflow, but leaves the UART packet reassembling work to the Application. + void onReceive(OnReceiveCb function, bool onlyOnTimeout = false); + + // onReceive will be called on error events (see hardwareSerial_error_t) + void onReceiveError(OnReceiveErrorCb function); + + // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - maybe usefull in some use cases + void eventQueueReset(); + + // When pins are changed, it will detach the previous ones + // if pin is negative, it won't be set/changed and will be kept as is + // timeout_ms is used in baudrate detection (ESP32, ESP32S2 only) + // invert will invert RX/TX polarity + // rxfifo_full_thrhd if the UART Flow Control Threshold in the UART FIFO (max 127) + void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112); + void end(bool fullyTerminate = true); + void updateBaudRate(unsigned long baud); + int available(void); + int availableForWrite(void); + int peek(void); + int read(void); + size_t read(uint8_t *buffer, size_t size); + inline size_t read(char * buffer, size_t size) + { + return read((uint8_t*) buffer, size); + } + // Overrides Stream::readBytes() to be faster using IDF + size_t readBytes(uint8_t *buffer, size_t length); + size_t readBytes(char *buffer, size_t length) + { + return readBytes((uint8_t *) buffer, length); + } + void flush(void); + void flush( bool txOnly); + size_t write(uint8_t); + size_t write(const uint8_t *buffer, size_t size); + inline size_t write(const char * buffer, size_t size) + { + return write((uint8_t*) buffer, size); + } + inline size_t write(const char * s) + { + return write((uint8_t*) s, strlen(s)); + } + inline size_t write(unsigned long n) + { + return write((uint8_t) n); + } + inline size_t write(long n) + { + return write((uint8_t) n); + } + inline size_t write(unsigned int n) + { + return write((uint8_t) n); + } + inline size_t write(int n) + { + return write((uint8_t) n); + } + uint32_t baudRate(); + operator bool() const; + + void setDebugOutput(bool); + + void setRxInvert(bool); + + // Negative Pin Number will keep it unmodified, thus this function can set individual pins + // setPins() can be called after or before begin() + // When pins are changed, it will detach the previous ones + bool setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); + // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) + // UART_HW_FLOWCTRL_DISABLE = 0x0 disable hardware flow control + // UART_HW_FLOWCTRL_RTS = 0x1 enable RX hardware flow control (rts) + // UART_HW_FLOWCTRL_CTS = 0x2 enable TX hardware flow control (cts) + // UART_HW_FLOWCTRL_CTS_RTS = 0x3 enable hardware flow control + bool setHwFlowCtrlMode(SerialHwFlowCtrl mode = UART_HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length + // Used to set RS485 modes such as UART_MODE_RS485_HALF_DUPLEX for Auto RTS function on ESP32 + // UART_MODE_UART = 0x00 mode: regular UART mode + // UART_MODE_RS485_HALF_DUPLEX = 0x01 mode: half duplex RS485 UART mode control by RTS pin + // UART_MODE_IRDA = 0x02 mode: IRDA UART mode + // UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes) + // UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) + bool setMode(SerialMode mode); + size_t setRxBufferSize(size_t new_size); + size_t setTxBufferSize(size_t new_size); + +protected: + uint8_t _uart_nr; + uart_t* _uart; + size_t _rxBufferSize; + size_t _txBufferSize; + OnReceiveCb _onReceiveCB; + OnReceiveErrorCb _onReceiveErrorCB; + // _onReceive and _rxTimeout have be consistent when timeout is disabled + bool _onReceiveTimeout; + uint8_t _rxTimeout, _rxFIFOFull; + TaskHandle_t _eventTask; +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t _lock; +#endif + + void _createEventTask(void *args); + void _destroyEventTask(void); + static void _uartEventTask(void *args); +}; + +extern void serialEventRun(void) __attribute__((weak)); + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL) +#ifndef ARDUINO_USB_CDC_ON_BOOT +#define ARDUINO_USB_CDC_ON_BOOT 0 +#endif +#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC +#if !ARDUINO_USB_MODE +#include "USB.h" +#include "USBCDC.h" +#endif +extern HardwareSerial Serial0; +#else +extern HardwareSerial Serial; +#endif +#if SOC_UART_NUM > 1 +extern HardwareSerial Serial1; +#endif +#if SOC_UART_NUM > 2 +extern HardwareSerial Serial2; +#endif +#endif + +#endif // HardwareSerial_h diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPAddress.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPAddress.cpp new file mode 100644 index 0000000..0575363 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPAddress.cpp @@ -0,0 +1,125 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +IPAddress::IPAddress() +{ + _address.dword = 0; +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + _address.dword = address; +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + _address.dword = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPAddress::printTo(Print& p) const +{ + size_t n = 0; + for(int i = 0; i < 3; i++) { + n += p.print(_address.bytes[i], DEC); + n += p.print('.'); + } + n += p.print(_address.bytes[3], DEC); + return n; +} + +String IPAddress::toString() const +{ + char szRet[16]; + sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]); + return String(szRet); +} + +bool IPAddress::fromString(const char *address) +{ + // TODO: add support for "a", "a.b", "a.b.c" formats + + uint16_t acc = 0; // Accumulator + uint8_t dots = 0; + + while (*address) + { + char c = *address++; + if (c >= '0' && c <= '9') + { + acc = acc * 10 + (c - '0'); + if (acc > 255) { + // Value out of [0..255] range + return false; + } + } + else if (c == '.') + { + if (dots == 3) { + // Too much dots (there must be 3 dots) + return false; + } + _address.bytes[dots++] = acc; + acc = 0; + } + else + { + // Invalid char + return false; + } + } + + if (dots != 3) { + // Too few dots (there must be 3 dots) + return false; + } + _address.bytes[3] = acc; + return true; +} + +// declared one time - as external in IPAddress.h +IPAddress INADDR_NONE(0, 0, 0, 0); diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPAddress.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPAddress.h new file mode 100644 index 0000000..3bedd4f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPAddress.h @@ -0,0 +1,96 @@ +/* + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef IPAddress_h +#define IPAddress_h + +#include +#include +#include + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress: public Printable +{ +private: + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() + { + return _address.bytes; + } + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + virtual ~IPAddress() {} + + bool fromString(const char *address); + bool fromString(const String &address) { return fromString(address.c_str()); } + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() const + { + return _address.dword; + } + bool operator==(const IPAddress& addr) const + { + return _address.dword == addr._address.dword; + } + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const + { + return _address.bytes[index]; + } + uint8_t& operator[](int index) + { + return _address.bytes[index]; + } + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + virtual size_t printTo(Print& p) const; + String toString() const; + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; + +// changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it +extern IPAddress INADDR_NONE; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPv6Address.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPv6Address.cpp new file mode 100644 index 0000000..7d3c0de --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPv6Address.cpp @@ -0,0 +1,90 @@ +/* + IPv6Address.cpp - Base class that provides IPv6Address + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +IPv6Address::IPv6Address() +{ + memset(_address.bytes, 0, sizeof(_address.bytes)); +} + +IPv6Address::IPv6Address(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +IPv6Address::IPv6Address(const uint32_t *address) +{ + memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes)); +} + +IPv6Address& IPv6Address::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +bool IPv6Address::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPv6Address::printTo(Print& p) const +{ + size_t n = 0; + for(int i = 0; i < 16; i+=2) { + if(i){ + n += p.print(':'); + } + n += p.printf("%02x", _address.bytes[i]); + n += p.printf("%02x", _address.bytes[i+1]); + + } + return n; +} + +String IPv6Address::toString() const +{ + char szRet[40]; + sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3], + _address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7], + _address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11], + _address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]); + return String(szRet); +} + +bool IPv6Address::fromString(const char *address) +{ + //format 0011:2233:4455:6677:8899:aabb:ccdd:eeff + if(strlen(address) != 39){ + return false; + } + char * pos = (char *)address; + size_t i = 0; + for(i = 0; i < 16; i+=2) { + if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){ + return false; + } + pos += 5; + } + return true; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPv6Address.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPv6Address.h new file mode 100644 index 0000000..e61d0e7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/IPv6Address.h @@ -0,0 +1,94 @@ +/* + IPv6Address.h - Base class that provides IPv6Address + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef IPv6Address_h +#define IPv6Address_h + +#include +#include +#include + +// A class to make it easier to handle and pass around IP addresses + +class IPv6Address: public Printable +{ +private: + union { + uint8_t bytes[16]; // IPv4 address + uint32_t dword[4]; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() + { + return _address.bytes; + } + +public: + // Constructors + IPv6Address(); + IPv6Address(const uint8_t *address); + IPv6Address(const uint32_t *address); + virtual ~IPv6Address() {} + + bool fromString(const char *address); + bool fromString(const String &address) { return fromString(address.c_str()); } + + operator const uint8_t*() const + { + return _address.bytes; + } + operator const uint32_t*() const + { + return _address.dword; + } + bool operator==(const IPv6Address& addr) const + { + return (_address.dword[0] == addr._address.dword[0]) + && (_address.dword[1] == addr._address.dword[1]) + && (_address.dword[2] == addr._address.dword[2]) + && (_address.dword[3] == addr._address.dword[3]); + } + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const + { + return _address.bytes[index]; + } + uint8_t& operator[](int index) + { + return _address.bytes[index]; + } + + // Overloaded copy operators to allow initialisation of IPv6Address objects from other types + IPv6Address& operator=(const uint8_t *address); + + virtual size_t printTo(Print& p) const; + String toString() const; + + friend class UDP; + friend class Client; + friend class Server; +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/MD5Builder.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/MD5Builder.cpp new file mode 100644 index 0000000..e242c37 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/MD5Builder.cpp @@ -0,0 +1,118 @@ +/* + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include + +static uint8_t hex_char_to_byte(uint8_t c) +{ + return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : + (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : + (c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0; +} + +void MD5Builder::begin(void) +{ + memset(_buf, 0x00, ESP_ROM_MD5_DIGEST_LEN); + esp_rom_md5_init(&_ctx); +} + +void MD5Builder::add(uint8_t * data, uint16_t len) +{ + esp_rom_md5_update(&_ctx, data, len); +} + +void MD5Builder::addHexString(const char * data) +{ + uint16_t i, len = strlen(data); + uint8_t * tmp = (uint8_t*)malloc(len/2); + if(tmp == NULL) { + return; + } + for(i=0; i 0) && (maxLengthLeft > 0)) { + + // determine number of bytes to read + int readBytes = bytesAvailable; + if(readBytes > maxLengthLeft) { + readBytes = maxLengthLeft ; // read only until max_len + } + if(readBytes > buf_size) { + readBytes = buf_size; // not read more the buffer can handle + } + + // read data and check if we got something + int numBytesRead = stream.readBytes(buf, readBytes); + if(numBytesRead< 1) { + free(buf); + return false; + } + + // Update MD5 with buffer payload + esp_rom_md5_update(&_ctx, buf, numBytesRead); + + // update available number of bytes + maxLengthLeft -= numBytesRead; + bytesAvailable = stream.available(); + } + free(buf); + return true; +} + +void MD5Builder::calculate(void) +{ + esp_rom_md5_final(_buf, &_ctx); +} + +void MD5Builder::getBytes(uint8_t * output) +{ + memcpy(output, _buf, ESP_ROM_MD5_DIGEST_LEN); +} + +void MD5Builder::getChars(char * output) +{ + for(uint8_t i = 0; i < ESP_ROM_MD5_DIGEST_LEN; i++) { + sprintf(output + (i * 2), "%02x", _buf[i]); + } +} + +String MD5Builder::toString(void) +{ + char out[(ESP_ROM_MD5_DIGEST_LEN * 2) + 1]; + getChars(out); + return String(out); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/MD5Builder.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/MD5Builder.h new file mode 100644 index 0000000..4285384 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/MD5Builder.h @@ -0,0 +1,65 @@ +/* + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __ESP8266_MD5_BUILDER__ +#define __ESP8266_MD5_BUILDER__ + +#include +#include + +#include "esp_system.h" +#include "esp_rom_md5.h" + +class MD5Builder +{ +private: + md5_context_t _ctx; + uint8_t _buf[ESP_ROM_MD5_DIGEST_LEN]; +public: + void begin(void); + void add(uint8_t * data, uint16_t len); + void add(const char * data) + { + add((uint8_t*)data, strlen(data)); + } + void add(char * data) + { + add((const char*)data); + } + void add(String data) + { + add(data.c_str()); + } + void addHexString(const char * data); + void addHexString(char * data) + { + addHexString((const char*)data); + } + void addHexString(String data) + { + addHexString(data.c_str()); + } + bool addStream(Stream & stream, const size_t maxLen); + void calculate(void); + void getBytes(uint8_t * output); + void getChars(char * output); + String toString(void); +}; + + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Print.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Print.cpp new file mode 100644 index 0000000..b1b9c0a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Print.cpp @@ -0,0 +1,379 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified December 2014 by Ivan Grokhotkov + Modified May 2015 by Michael C. Miller - ESP31B progmem support + */ + +#include +#include +#include +#include +#include "Arduino.h" + +#include "Print.h" +extern "C" { + #include "time.h" +} + +// Public Methods ////////////////////////////////////////////////////////////// + +/* default implementation: may be overridden */ +size_t Print::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + while(size--) { + n += write(*buffer++); + } + return n; +} + +size_t Print::vprintf(const char *format, va_list arg) +{ + char loc_buf[64]; + char * temp = loc_buf; + va_list copy; + va_copy(copy, arg); + int len = vsnprintf(temp, sizeof(loc_buf), format, copy); + va_end(copy); + if(len < 0) { + va_end(arg); + return 0; + } + if(len >= (int)sizeof(loc_buf)){ // comparation of same sign type for the compiler + temp = (char*) malloc(len+1); + if(temp == NULL) { + va_end(arg); + return 0; + } + len = vsnprintf(temp, len+1, format, arg); + } + va_end(arg); + len = write((uint8_t*)temp, len); + if(temp != loc_buf){ + free(temp); + } + return len; +} + +size_t Print::printf(const __FlashStringHelper *ifsh, ...) +{ + va_list arg; + va_start(arg, ifsh); + const char * format = (reinterpret_cast(ifsh)); + size_t ret = vprintf(format, arg); + va_end(arg); + return ret; +} + +size_t Print::printf(const char *format, ...) +{ + va_list arg; + va_start(arg, format); + size_t ret = vprintf(format, arg); + va_end(arg); + return ret; +} + +size_t Print::print(const String &s) +{ + return write(s.c_str(), s.length()); +} + +size_t Print::print(const char str[]) +{ + return write(str); +} + +size_t Print::print(char c) +{ + return write(c); +} + +size_t Print::print(unsigned char b, int base) +{ + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) +{ + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) +{ + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) +{ + int t = 0; + if (base == 10 && n < 0) { + t = print('-'); + n = -n; + } + return printNumber(static_cast(n), base) + t; +} + +size_t Print::print(unsigned long n, int base) +{ + if(base == 0) { + return write(n); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(long long n, int base) +{ + int t = 0; + if (base == 10 && n < 0) { + t = print('-'); + n = -n; + } + return printNumber(static_cast(n), base) + t; +} + +size_t Print::print(unsigned long long n, int base) +{ + if (base == 0) { + return write(n); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(double n, int digits) +{ + return printFloat(n, digits); +} + +size_t Print::print(const Printable& x) +{ + return x.printTo(*this); +} + +size_t Print::print(struct tm * timeinfo, const char * format) +{ + const char * f = format; + if(!f){ + f = "%c"; + } + char buf[64]; + size_t written = strftime(buf, 64, f, timeinfo); + if(written == 0){ + return written; + } + return print(buf); +} + +size_t Print::println(void) +{ + return print("\r\n"); +} + +size_t Print::println(const String &s) +{ + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) +{ + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) +{ + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long long num, int base) +{ + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) +{ + size_t n = print(num, digits); + n += println(); + return n; +} + +size_t Print::println(const Printable& x) +{ + size_t n = print(x); + n += println(); + return n; +} + +size_t Print::println(struct tm * timeinfo, const char * format) +{ + size_t n = print(timeinfo, format); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) +{ + char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if(base < 2) { + base = 10; + } + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while (n); + + return write(str); +} + +size_t Print::printNumber(unsigned long long n, uint8_t base) +{ + char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte. + char* str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if (base < 2) { + base = 10; + } + + do { + auto m = n; + n /= base; + char c = m - base * n; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while (n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) +{ + size_t n = 0; + + if(isnan(number)) { + return print("nan"); + } + if(isinf(number)) { + return print("inf"); + } + if(number > 4294967040.0) { + return print("ovf"); // constant determined empirically + } + if(number < -4294967040.0) { + return print("ovf"); // constant determined empirically + } + + // Handle negative numbers + if(number < 0.0) { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) { + rounding /= 10.0; + } + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long) number; + double remainder = number - (double) int_part; + n += print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + n += print("."); + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + int toPrint = int(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Print.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Print.h new file mode 100644 index 0000000..a543e8c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Print.h @@ -0,0 +1,120 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Print_h +#define Print_h + +#include +#include +#include + +#include "WString.h" +#include "Printable.h" + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +class Print +{ +private: + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printNumber(unsigned long long, uint8_t); + size_t printFloat(double, uint8_t); +protected: + void setWriteError(int err = 1) + { + write_error = err; + } +public: + Print() : + write_error(0) + { + } + virtual ~Print() {} + int getWriteError() + { + return write_error; + } + void clearWriteError() + { + setWriteError(0); + } + + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) + { + if(str == NULL) { + return 0; + } + return write((const uint8_t *) str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) + { + return write((const uint8_t *) buffer, size); + } + + size_t vprintf(const char *format, va_list arg); + + size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); + size_t printf(const __FlashStringHelper *ifsh, ...); + + // add availableForWrite to make compatible with Arduino Print.h + // default to zero, meaning "a single write may block" + // should be overriden by subclasses with buffering + virtual int availableForWrite() { return 0; } + size_t print(const __FlashStringHelper *ifsh) { return print(reinterpret_cast(ifsh)); } + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(long long, int = DEC); + size_t print(unsigned long long, int = DEC); + size_t print(double, int = 2); + size_t print(const Printable&); + size_t print(struct tm * timeinfo, const char * format = NULL); + + size_t println(const __FlashStringHelper *ifsh) { return println(reinterpret_cast(ifsh)); } + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(long long, int = DEC); + size_t println(unsigned long long, int = DEC); + size_t println(double, int = 2); + size_t println(const Printable&); + size_t println(struct tm * timeinfo, const char * format = NULL); + size_t println(void); + + virtual void flush() { /* Empty implementation for backward compatibility */ } + +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Printable.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Printable.h new file mode 100644 index 0000000..aa4e62f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Printable.h @@ -0,0 +1,41 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Printable_h +#define Printable_h + +#include + +class Print; + +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. + */ + +class Printable +{ +public: + virtual ~Printable() {} + virtual size_t printTo(Print& p) const = 0; +}; + +#endif + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Server.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Server.h new file mode 100644 index 0000000..6a940a0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Server.h @@ -0,0 +1,31 @@ +/* + Server.h - Base class that provides Server + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef server_h +#define server_h + +#include "Print.h" + +class Server: public Print +{ +public: + virtual void begin(uint16_t port=0) =0; +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Stream.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Stream.cpp new file mode 100644 index 0000000..f412e46 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Stream.cpp @@ -0,0 +1,337 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + */ + +#include "Arduino.h" +#include "Stream.h" +#include "esp32-hal.h" + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait +#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field + +// private method to read stream with timeout +int Stream::timedRead() +{ + int c; + _startMillis = millis(); + do { + c = read(); + if(c >= 0) { + return c; + } + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// private method to peek stream with timeout +int Stream::timedPeek() +{ + int c; + _startMillis = millis(); + do { + c = peek(); + if(c >= 0) { + return c; + } + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit() +{ + int c; + while(1) { + c = timedPeek(); + if(c < 0) { + return c; // timeout + } + if(c == '-') { + return c; + } + if(c >= '0' && c <= '9') { + return c; + } + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} +unsigned long Stream::getTimeout(void) { + return _timeout; +} + +// find returns true if the target string is found +bool Stream::find(const char *target) +{ + return findUntil(target, strlen(target), NULL, 0); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(const char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(const char *target, const char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) +{ + if (terminator == NULL) { + MultiTarget t[1] = {{target, targetLen, 0}}; + return findMulti(t, 1) == 0 ? true : false; + } else { + MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}}; + return findMulti(t, 2) == 0 ? true : false; + } +} + +int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) { + // any zero length target string automatically matches and would make + // a mess of the rest of the algorithm. + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + if (t->len <= 0) + return t - targets; + } + + while (1) { + int c = timedRead(); + if (c < 0) + return -1; + + for (struct MultiTarget *t = targets; t < targets+tCount; ++t) { + // the simple case is if we match, deal with that first. + if (c == t->str[t->index]) { + if (++t->index == t->len) + return t - targets; + else + continue; + } + + // if not we need to walk back and see if we could have matched further + // down the stream (ie '1112' doesn't match the first position in '11112' + // but it will match the second position so we can't just reset the current + // index to 0 when we find a mismatch. + if (t->index == 0) + continue; + + int origIndex = t->index; + do { + --t->index; + // first check if current char works against the new current index + if (c != t->str[t->index]) + continue; + + // if it's the only char then we're good, nothing more to check + if (t->index == 0) { + t->index++; + break; + } + + // otherwise we need to check the rest of the found string + int diff = origIndex - t->index; + size_t i; + for (i = 0; i < t->index; ++i) { + if (t->str[i] != t->str[i + diff]) + break; + } + + // if we successfully got through the previous loop then our current + // index is good. + if (i == t->index) { + t->index++; + break; + } + + // otherwise we just try the next index + } while (t->index); + } + } + // unreachable + return -1; +} + +// returns the first valid (long) integer value from the current position. +// initial characters that are not digits (or the minus sign) are skipped +// function is terminated by the first character that is not a digit. +long Stream::parseInt() +{ + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +} + +// as above but a given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +long Stream::parseInt(char skipChar) +{ + boolean isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) { + return 0; // zero returned if timeout + } + + do { + if(c == skipChar) { + } // ignore this charactor + else if(c == '-') { + isNegative = true; + } else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + } + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == skipChar); + + if(isNegative) { + value = -value; + } + return value; +} + +// as parseInt but returns a floating point value +float Stream::parseFloat() +{ + return parseFloat(NO_SKIP_CHAR); +} + +// as above but the given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +float Stream::parseFloat(char skipChar) +{ + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) { + return 0; // zero returned if timeout + } + + do { + if(c == skipChar) { + } // ignore + else if(c == '-') { + isNegative = true; + } else if(c == '.') { + isFraction = true; + } else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) { + fraction *= 0.1f; + } + } + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); + + if(isNegative) { + value = -value; + } + if(isFraction) { + return value * fraction; + } else { + return value; + } +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) +{ + size_t count = 0; + while(count < length) { + int c = timedRead(); + if(c < 0) { + break; + } + *buffer++ = (char) c; + count++; + } + return count; +} + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) +{ + if(length < 1) { + return 0; + } + size_t index = 0; + while(index < length) { + int c = timedRead(); + if(c < 0 || c == terminator) { + break; + } + *buffer++ = (char) c; + index++; + } + return index; // return number of characters, not including null terminator +} + +String Stream::readString() +{ + String ret; + int c = timedRead(); + while(c >= 0) { + ret += (char) c; + c = timedRead(); + } + return ret; +} + +String Stream::readStringUntil(char terminator) +{ + String ret; + int c = timedRead(); + while(c >= 0 && c != terminator) { + ret += (char) c; + c = timedRead(); + } + return ret; +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Stream.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Stream.h new file mode 100644 index 0000000..8df8226 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Stream.h @@ -0,0 +1,139 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis + */ + +#ifndef Stream_h +#define Stream_h + +#include +#include "Print.h" + +// compatability macros for testing +/* + #define getInt() parseInt() + #define getInt(skipChar) parseInt(skipchar) + #define getFloat() parseFloat() + #define getFloat(skipChar) parseFloat(skipChar) + #define getString( pre_string, post_string, buffer, length) + readBytesBetween( pre_string, terminator, buffer, length) + */ + +class Stream: public Print +{ +protected: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + +public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + + Stream():_startMillis(0) + { + _timeout = 1000; + } + virtual ~Stream() {} + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + unsigned long getTimeout(void); + + bool find(const char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) + { + return find((char *) target); + } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found + bool find(const uint8_t *target, size_t length) + { + return find((char *) target, length); + } + // returns true if target string is found, false if timed out + + bool find(char target) + { + return find (&target, 1); + } + + bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found + bool findUntil(const uint8_t *target, const char *terminator) + { + return findUntil((char *) target, terminator); + } + + bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) + { + return findUntil((char *) target, targetLen, terminate, termLen); + } + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + float parseFloat(); // float version of parseInt + + virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer + virtual size_t readBytes(uint8_t *buffer, size_t length) + { + return readBytes((char *) buffer, length); + } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character + size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) + { + return readBytesUntil(terminator, (char *) buffer, length); + } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + virtual String readString(); + String readStringUntil(char terminator); + +protected: + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(char skipChar); // as above but the given skipChar is ignored + + struct MultiTarget { + const char *str; // string you're searching for + size_t len; // length of string you're searching for + size_t index; // index used by the search routine. + }; + + // This allows you to search for an arbitrary number of strings. + // Returns index of the target that is found first or -1 if timeout occurs. + int findMulti(struct MultiTarget *targets, int tCount); + +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/StreamString.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/StreamString.cpp new file mode 100644 index 0000000..f50b682 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/StreamString.cpp @@ -0,0 +1,67 @@ +/** + StreamString.cpp + + Copyright (c) 2015 Markus Sattler. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + */ + +#include +#include "StreamString.h" + +size_t StreamString::write(const uint8_t *data, size_t size) { + if(size && data) { + const unsigned int newlen = length() + size; + if(reserve(newlen + 1)) { + memcpy((void *) (wbuffer() + len()), (const void *) data, size); + setLen(newlen); + *(wbuffer() + newlen) = 0x00; // add null for string end + return size; + } + } + return 0; +} + +size_t StreamString::write(uint8_t data) { + return concat((char) data); +} + +int StreamString::available() { + return length(); +} + +int StreamString::read() { + if(length()) { + char c = charAt(0); + remove(0, 1); + return c; + + } + return -1; +} + +int StreamString::peek() { + if(length()) { + char c = charAt(0); + return c; + } + return -1; +} + +void StreamString::flush() { +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/StreamString.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/StreamString.h new file mode 100644 index 0000000..dbdf3fb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/StreamString.h @@ -0,0 +1,39 @@ +/** + StreamString.h + + Copyright (c) 2015 Markus Sattler. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef STREAMSTRING_H_ +#define STREAMSTRING_H_ + + +class StreamString: public Stream, public String +{ +public: + size_t write(const uint8_t *buffer, size_t size) override; + size_t write(uint8_t data) override; + + int available() override; + int read() override; + int peek() override; + void flush() override; +}; + + +#endif /* STREAMSTRING_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Tone.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Tone.cpp new file mode 100644 index 0000000..77a254c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Tone.cpp @@ -0,0 +1,129 @@ +#include +#include "esp32-hal-ledc.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +static TaskHandle_t _tone_task = NULL; +static QueueHandle_t _tone_queue = NULL; +static int8_t _pin = -1; + +typedef enum{ + TONE_START, + TONE_END +} tone_cmd_t; + +typedef struct{ + tone_cmd_t tone_cmd; + uint8_t pin; + unsigned int frequency; + unsigned long duration; +} tone_msg_t; + +static void tone_task(void*){ + tone_msg_t tone_msg; + while(1){ + xQueueReceive(_tone_queue, &tone_msg, portMAX_DELAY); + switch(tone_msg.tone_cmd){ + case TONE_START: + log_d("Task received from queue TONE_START: pin=%d, frequency=%u Hz, duration=%lu ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration); + + if (_pin == -1) { + if (ledcAttach(tone_msg.pin, tone_msg.frequency, 10) == 0) { + log_e("Tone start failed"); + break; + } + _pin = tone_msg.pin; + } + ledcWriteTone(tone_msg.pin, tone_msg.frequency); + + if(tone_msg.duration){ + delay(tone_msg.duration); + ledcWriteTone(tone_msg.pin, 0); + } + break; + + case TONE_END: + log_d("Task received from queue TONE_END: pin=%d", tone_msg.pin); + ledcWriteTone(tone_msg.pin, 0); + ledcDetach(tone_msg.pin); + _pin = -1; + break; + + default: ; // do nothing + } // switch + } // infinite loop +} + +static int tone_init(){ + if(_tone_queue == NULL){ + log_v("Creating tone queue"); + _tone_queue = xQueueCreate(128, sizeof(tone_msg_t)); + if(_tone_queue == NULL){ + log_e("Could not create tone queue"); + return 0; // ERR + } + log_v("Tone queue created"); + } + + if(_tone_task == NULL){ + log_v("Creating tone task"); + xTaskCreate( + tone_task, // Function to implement the task + "toneTask", // Name of the task + 3500, // Stack size in words + NULL, // Task input parameter + 1, // Priority of the task + &_tone_task // Task handle. + ); + if(_tone_task == NULL){ + log_e("Could not create tone task"); + return 0; // ERR + } + log_v("Tone task created"); + } + return 1; // OK +} + +void noTone(uint8_t pin){ + log_d("noTone was called"); + if(_pin == pin) { + if(tone_init()){ + tone_msg_t tone_msg = { + .tone_cmd = TONE_END, + .pin = pin, + .frequency = 0, // Ignored + .duration = 0, // Ignored + }; + xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY); + } + } + else { + log_e("Tone is not running on given pin %d", pin); + } +} + +// parameters: +// pin - pin number which will output the signal +// frequency - PWM frequency in Hz +// duration - time in ms - how long will the signal be outputted. +// If not provided, or 0 you must manually call noTone to end output +void tone(uint8_t pin, unsigned int frequency, unsigned long duration){ + log_d("pin=%d, frequency=%u Hz, duration=%lu ms", pin, frequency, duration); + if(_pin == -1 || _pin == pin) { + if(tone_init()){ + tone_msg_t tone_msg = { + .tone_cmd = TONE_START, + .pin = pin, + .frequency = frequency, + .duration = duration, + }; + xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY); + return; + } + } + else { + log_e("Tone is still running on pin %d, call noTone(%d) first!", _pin, _pin); + return; + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USB.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USB.cpp new file mode 100644 index 0000000..247f688 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USB.cpp @@ -0,0 +1,362 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "USB.h" + +#if SOC_USB_OTG_SUPPORTED +#if CONFIG_TINYUSB_ENABLED + +#include "pins_arduino.h" +#include "esp32-hal.h" +#include "esp32-hal-tinyusb.h" +#include "common/tusb_common.h" +#include "StreamString.h" +#include "rom/ets_sys.h" +#include "esp_mac.h" + +#ifndef USB_VID +#define USB_VID USB_ESPRESSIF_VID +#endif +#ifndef USB_PID +#define USB_PID 0x0002 +#endif +#ifndef USB_MANUFACTURER +#define USB_MANUFACTURER "Espressif Systems" +#endif +#ifndef USB_PRODUCT +#define USB_PRODUCT ARDUINO_BOARD +#endif +#ifndef USB_SERIAL +#if CONFIG_IDF_TARGET_ESP32S3 +#define USB_SERIAL "__MAC__" +#else +#define USB_SERIAL "0" +#endif +#endif +#ifndef USB_WEBUSB_ENABLED +#define USB_WEBUSB_ENABLED false +#endif +#ifndef USB_WEBUSB_URL +#define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html" +#endif + +#if CFG_TUD_DFU_RUNTIME +static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf) +{ +#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) + + uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT"); + uint8_t descriptor[TUD_DFU_RT_DESC_LEN] = { + // Interface number, string index, attributes, detach timeout, transfer size */ + TUD_DFU_RT_DESCRIPTOR(*itf, str_index, DFU_ATTRS, 700, 64) + }; + *itf+=1; + memcpy(dst, descriptor, TUD_DFU_RT_DESC_LEN); + return TUD_DFU_RT_DESC_LEN; +} +// Invoked on DFU_DETACH request to reboot to the bootloader +void tud_dfu_runtime_reboot_to_dfu_cb(void) +{ + usb_persist_restart(RESTART_BOOTLOADER_DFU); +} +#endif /* CFG_TUD_DFU_RUNTIME */ + +ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS); + +static esp_event_loop_handle_t arduino_usb_event_loop_handle = NULL; + +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait){ + if(arduino_usb_event_loop_handle == NULL){ + return ESP_FAIL; + } + return esp_event_post_to(arduino_usb_event_loop_handle, event_base, event_id, event_data, event_data_size, ticks_to_wait); +} +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){ + if(arduino_usb_event_loop_handle == NULL){ + return ESP_FAIL; + } + return esp_event_handler_register_with(arduino_usb_event_loop_handle, event_base, event_id, event_handler, event_handler_arg); +} + +static bool tinyusb_device_mounted = false; +static bool tinyusb_device_suspended = false; + +// Invoked when device is mounted (configured) +void tud_mount_cb(void){ + tinyusb_device_mounted = true; + arduino_usb_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); +} + +// Invoked when device is unmounted +void tud_umount_cb(void){ + tinyusb_device_mounted = false; + arduino_usb_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); +} + +// Invoked when usb bus is suspended +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en){ + tinyusb_device_suspended = true; + arduino_usb_event_data_t p; + p.suspend.remote_wakeup_en = remote_wakeup_en; + arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void){ + tinyusb_device_suspended = false; + arduino_usb_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY); +} + +ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority) +:vid(USB_VID) +,pid(USB_PID) +,product_name(USB_PRODUCT) +,manufacturer_name(USB_MANUFACTURER) +,serial_number(USB_SERIAL) +,fw_version(0x0100) +,usb_version(0x0200)// at least 2.1 or 3.x for BOS & webUSB +,usb_class(TUSB_CLASS_MISC) +,usb_subclass(MISC_SUBCLASS_COMMON) +,usb_protocol(MISC_PROTOCOL_IAD) +,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED) +,usb_power_ma(500) +,webusb_enabled(USB_WEBUSB_ENABLED) +,webusb_url(USB_WEBUSB_URL) +,_started(false) +,_task_stack_size(task_stack_size) +,_event_task_priority(event_task_priority) +{ + if (!arduino_usb_event_loop_handle) { + esp_event_loop_args_t event_task_args = { + .queue_size = 5, + .task_name = "arduino_usb_events", + .task_priority = _event_task_priority, + .task_stack_size = _task_stack_size, + .task_core_id = tskNO_AFFINITY + }; + if (esp_event_loop_create(&event_task_args, &arduino_usb_event_loop_handle) != ESP_OK) { + log_e("esp_event_loop_create failed"); + } + } +} + +ESPUSB::~ESPUSB(){ + if (arduino_usb_event_loop_handle) { + esp_event_loop_delete(arduino_usb_event_loop_handle); + arduino_usb_event_loop_handle = NULL; + } +} + +bool ESPUSB::begin(){ + if(!_started){ +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + if(serial_number == "__MAC__"){ + StreamString s; + uint8_t m[6]; + esp_efuse_mac_get_default(m); + s.printf("%02X%02X%02X%02X%02X%02X", m[0], m[1], m[2], m[3], m[4], m[5]); + serial_number = s; + } +#endif + tinyusb_device_config_t tinyusb_device_config = { + .vid = vid, + .pid = pid, + .product_name = product_name.c_str(), + .manufacturer_name = manufacturer_name.c_str(), + .serial_number = serial_number.c_str(), + .fw_version = fw_version, + .usb_version = usb_version, + .usb_class = usb_class, + .usb_subclass = usb_subclass, + .usb_protocol = usb_protocol, + .usb_attributes = usb_attributes, + .usb_power_ma = usb_power_ma, + .webusb_enabled = webusb_enabled, + .webusb_url = webusb_url.c_str() + }; + _started = tinyusb_init(&tinyusb_device_config) == ESP_OK; + } + return _started; +} + +void ESPUSB::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_USB_ANY_EVENT, callback); +} +void ESPUSB::onEvent(arduino_usb_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, event, callback, this); +} + +ESPUSB::operator bool() const +{ + return _started && tinyusb_device_mounted; +} + +bool ESPUSB::enableDFU(){ +#if CFG_TUD_DFU_RUNTIME + return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK; +#endif /* CFG_TUD_DFU_RUNTIME */ + return false; +} + +bool ESPUSB::VID(uint16_t v){ + if(!_started){ + vid = v; + } + return !_started; +} +uint16_t ESPUSB::VID(void){ + return vid; +} + +bool ESPUSB::PID(uint16_t p){ + if(!_started){ + pid = p; + } + return !_started; +} +uint16_t ESPUSB::PID(void){ + return pid; +} + +bool ESPUSB::firmwareVersion(uint16_t version){ + if(!_started){ + fw_version = version; + } + return !_started; +} +uint16_t ESPUSB::firmwareVersion(void){ + return fw_version; +} + +bool ESPUSB::usbVersion(uint16_t version){ + if(!_started){ + usb_version = version; + } + return !_started; +} +uint16_t ESPUSB::usbVersion(void){ + return usb_version; +} + +bool ESPUSB::usbPower(uint16_t mA){ + if(!_started){ + usb_power_ma = mA; + } + return !_started; +} +uint16_t ESPUSB::usbPower(void){ + return usb_power_ma; +} + +bool ESPUSB::usbClass(uint8_t _class){ + if(!_started){ + usb_class = _class; + } + return !_started; +} +uint8_t ESPUSB::usbClass(void){ + return usb_class; +} + +bool ESPUSB::usbSubClass(uint8_t subClass){ + if(!_started){ + usb_subclass = subClass; + } + return !_started; +} +uint8_t ESPUSB::usbSubClass(void){ + return usb_subclass; +} + +bool ESPUSB::usbProtocol(uint8_t protocol){ + if(!_started){ + usb_protocol = protocol; + } + return !_started; +} +uint8_t ESPUSB::usbProtocol(void){ + return usb_protocol; +} + +bool ESPUSB::usbAttributes(uint8_t attr){ + if(!_started){ + usb_attributes = attr; + } + return !_started; +} +uint8_t ESPUSB::usbAttributes(void){ + return usb_attributes; +} + +bool ESPUSB::webUSB(bool enabled){ + if(!_started){ + webusb_enabled = enabled; + if(enabled && usb_version < 0x0210){ + usb_version = 0x0210; + } + } + return !_started; +} +bool ESPUSB::webUSB(void){ + return webusb_enabled; +} + +bool ESPUSB::productName(const char * name){ + if(!_started){ + product_name = name; + } + return !_started; +} +const char * ESPUSB::productName(void){ + return product_name.c_str(); +} + +bool ESPUSB::manufacturerName(const char * name){ + if(!_started){ + manufacturer_name = name; + } + return !_started; +} +const char * ESPUSB::manufacturerName(void){ + return manufacturer_name.c_str(); +} + +bool ESPUSB::serialNumber(const char * name){ + if(!_started){ + serial_number = name; + } + return !_started; +} +const char * ESPUSB::serialNumber(void){ + return serial_number.c_str(); +} + +bool ESPUSB::webUSBURL(const char * name){ + if(!_started){ + webusb_url = name; + } + return !_started; +} +const char * ESPUSB::webUSBURL(void){ + return webusb_url.c_str(); +} + +ESPUSB USB; + +#endif /* CONFIG_TINYUSB_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USB.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USB.h new file mode 100644 index 0000000..762ad17 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USB.h @@ -0,0 +1,123 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "soc/soc_caps.h" +#if SOC_USB_OTG_SUPPORTED + +#include "sdkconfig.h" +#if CONFIG_TINYUSB_ENABLED + +#include "esp_event.h" +#include "USBCDC.h" + +#define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) + +ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS); + +typedef enum { + ARDUINO_USB_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_USB_STARTED_EVENT = 0, + ARDUINO_USB_STOPPED_EVENT, + ARDUINO_USB_SUSPEND_EVENT, + ARDUINO_USB_RESUME_EVENT, + ARDUINO_USB_MAX_EVENT, +} arduino_usb_event_t; + +typedef union { + struct { + bool remote_wakeup_en; + } suspend; +} arduino_usb_event_data_t; + +class ESPUSB { + public: + ESPUSB(size_t event_task_stack_size=2048, uint8_t event_task_priority=5); + ~ESPUSB(); + + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_usb_event_t event, esp_event_handler_t callback); + + bool VID(uint16_t v); + uint16_t VID(void); + + bool PID(uint16_t p); + uint16_t PID(void); + + bool firmwareVersion(uint16_t version); + uint16_t firmwareVersion(void); + + bool usbVersion(uint16_t version); + uint16_t usbVersion(void); + + bool usbPower(uint16_t mA); + uint16_t usbPower(void); + + bool usbClass(uint8_t _class); + uint8_t usbClass(void); + + bool usbSubClass(uint8_t subClass); + uint8_t usbSubClass(void); + + bool usbProtocol(uint8_t protocol); + uint8_t usbProtocol(void); + + bool usbAttributes(uint8_t attr); + uint8_t usbAttributes(void); + + bool webUSB(bool enabled); + bool webUSB(void); + + bool productName(const char * name); + const char * productName(void); + + bool manufacturerName(const char * name); + const char * manufacturerName(void); + + bool serialNumber(const char * name); + const char * serialNumber(void); + + bool webUSBURL(const char * name); + const char * webUSBURL(void); + + bool enableDFU(); + bool begin(); + operator bool() const; + + private: + uint16_t vid; + uint16_t pid; + String product_name; + String manufacturer_name; + String serial_number; + uint16_t fw_version; + uint16_t usb_version; + uint8_t usb_class; + uint8_t usb_subclass; + uint8_t usb_protocol; + uint8_t usb_attributes; + uint16_t usb_power_ma; + bool webusb_enabled; + String webusb_url; + + bool _started; + size_t _task_stack_size; + uint8_t _event_task_priority; +}; + +extern ESPUSB USB; + + +#endif /* CONFIG_TINYUSB_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBCDC.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBCDC.cpp new file mode 100644 index 0000000..4fd0508 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBCDC.cpp @@ -0,0 +1,463 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "USBCDC.h" + +#if SOC_USB_OTG_SUPPORTED +#include "USB.h" +#if CONFIG_TINYUSB_CDC_ENABLED + + +#include "esp32-hal-tinyusb.h" +#include "rom/ets_sys.h" + +ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS); +esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait); +esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg); + +#define MAX_USB_CDC_DEVICES 2 +USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL}; + +static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf) +{ + uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC"); + uint8_t descriptor[TUD_CDC_DESC_LEN] = { + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64) + }; + *itf+=2; + memcpy(dst, descriptor, TUD_CDC_DESC_LEN); + return TUD_CDC_DESC_LEN; +} + +// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) +{ + if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ + devices[itf]->_onLineState(dtr, rts); + } +} + +// Invoked when line coding is change via SET_LINE_CODING +void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) +{ + if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ + devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits); + } +} + +// Invoked when received new data +void tud_cdc_rx_cb(uint8_t itf) +{ + if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ + devices[itf]->_onRX(); + } +} + +// Invoked when received send break +void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms){ + //log_v("itf: %u, duration_ms: %u", itf, duration_ms); +} + +// Invoked when space becomes available in TX buffer +void tud_cdc_tx_complete_cb(uint8_t itf){ + if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){ + devices[itf]->_onTX(); + } +} + +static void ARDUINO_ISR_ATTR cdc0_write_char(char c){ + if(devices[0] != NULL){ + devices[0]->write(c); + } +} + +static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + ((USBCDC*)arg)->_onUnplugged(); +} + +USBCDC::USBCDC(uint8_t itfn) +: itf(itfn) +, bit_rate(0) +, stop_bits(0) +, parity(0) +, data_bits(0) +, dtr(false) +, rts(false) +, connected(false) +, reboot_enable(true) +, rx_queue(NULL) +, tx_lock(NULL) +, tx_timeout_ms(250) +{ + tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor); + if(itf < MAX_USB_CDC_DEVICES){ + arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this); + } +} + +USBCDC::~USBCDC(){ + end(); +} + +void USBCDC::onEvent(esp_event_handler_t callback){ + onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback); +} +void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback){ + arduino_usb_event_handler_register_with(ARDUINO_USB_CDC_EVENTS, event, callback, this); +} + +size_t USBCDC::setRxBufferSize(size_t rx_queue_len){ + size_t currentQueueSize = rx_queue ? + uxQueueSpacesAvailable(rx_queue) + uxQueueMessagesWaiting(rx_queue) : 0; + + if (rx_queue_len != currentQueueSize) { + QueueHandle_t new_rx_queue = NULL; + if (rx_queue_len) { + new_rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t)); + if(!new_rx_queue){ + log_e("CDC Queue creation failed."); + return 0; + } + if (rx_queue) { + size_t copySize = uxQueueMessagesWaiting(rx_queue); + if (copySize > 0) { + for(size_t i = 0; i < copySize; i++) { + uint8_t ch = 0; + xQueueReceive(rx_queue, &ch, 0); + if (!xQueueSend(new_rx_queue, &ch, 0)) { + arduino_usb_cdc_event_data_t p; + p.rx_overflow.dropped_bytes = copySize - i; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + log_e("CDC RX Overflow."); + break; + } + } + } + vQueueDelete(rx_queue); + } + rx_queue = new_rx_queue; + return rx_queue_len; + } else { + if (rx_queue) { + vQueueDelete(rx_queue); + rx_queue = NULL; + } + } + } + return rx_queue_len; +} + +void USBCDC::begin(unsigned long baud) +{ + if(tx_lock == NULL) { + tx_lock = xSemaphoreCreateMutex(); + } + // if rx_queue was set before begin(), keep it + if (!rx_queue) setRxBufferSize(256); //default if not preset + devices[itf] = this; +} + +void USBCDC::end() +{ + connected = false; + devices[itf] = NULL; + setRxBufferSize(0); + if(tx_lock != NULL) { + vSemaphoreDelete(tx_lock); + tx_lock = NULL; + } +} + +void USBCDC::setTxTimeoutMs(uint32_t timeout){ + tx_timeout_ms = timeout; +} + +void USBCDC::_onUnplugged(void){ + if(connected){ + connected = false; + dtr = false; + rts = false; + arduino_usb_cdc_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } +} + +enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 }; +void USBCDC::_onLineState(bool _dtr, bool _rts){ + static uint8_t lineState = CDC_LINE_IDLE; + + if(dtr == _dtr && rts == _rts){ + return; // Skip duplicate events + } + + dtr = _dtr; + rts = _rts; + + if(reboot_enable){ + if(!dtr && rts){ + if(lineState == CDC_LINE_IDLE){ + lineState++; + if(connected){ + connected = false; + arduino_usb_cdc_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } + // } else if(lineState == CDC_LINE_2){//esptool.js + // lineState++; + } else { + lineState = CDC_LINE_IDLE; + } + } else if(dtr && rts){ + if(lineState == CDC_LINE_1){ + lineState++; + } else { + lineState = CDC_LINE_IDLE; + } + } else if(dtr && !rts){ + if(lineState == CDC_LINE_2){ + lineState++; + // } else if(lineState == CDC_LINE_IDLE){//esptool.js + // lineState++; + } else { + lineState = CDC_LINE_IDLE; + } + } else if(!dtr && !rts){ + if(lineState == CDC_LINE_3){ + usb_persist_restart(RESTART_BOOTLOADER); + } else { + lineState = CDC_LINE_IDLE; + } + } + } + + if(lineState == CDC_LINE_IDLE){ + if(dtr && rts && !connected){ + connected = true; + arduino_usb_cdc_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } else if(!dtr && connected){ + connected = false; + arduino_usb_cdc_event_data_t p; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } + arduino_usb_cdc_event_data_t l; + l.line_state.dtr = dtr; + l.line_state.rts = rts; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } + +} + +void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){ + if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){ + // ArduinoIDE sends LineCoding with 1200bps baud to reset the device + if(reboot_enable && _bit_rate == 1200){ + usb_persist_restart(RESTART_BOOTLOADER); + } else { + bit_rate = _bit_rate; + data_bits = _data_bits; + stop_bits = _stop_bits; + parity = _parity; + arduino_usb_cdc_event_data_t p; + p.line_coding.bit_rate = bit_rate; + p.line_coding.data_bits = data_bits; + p.line_coding.stop_bits = stop_bits; + p.line_coding.parity = parity; + arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY); + } + } +} + +void USBCDC::_onRX(){ + arduino_usb_cdc_event_data_t p; + uint8_t buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE+1]; + uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_TINYUSB_CDC_RX_BUFSIZE); + for(uint32_t i=0; i= MAX_USB_CDC_DEVICES || rx_queue == NULL){ + return -1; + } + return uxQueueMessagesWaiting(rx_queue); +} + +int USBCDC::peek(void) +{ + if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ + return -1; + } + uint8_t c; + if(xQueuePeek(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +int USBCDC::read(void) +{ + if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + if(xQueueReceive(rx_queue, &c, 0)) { + return c; + } + return -1; +} + +size_t USBCDC::read(uint8_t *buffer, size_t size) +{ + if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){ + return -1; + } + uint8_t c = 0; + size_t count = 0; + while(count < size && xQueueReceive(rx_queue, &c, 0)){ + buffer[count++] = c; + } + return count; +} + +void USBCDC::flush(void) +{ + if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){ + return; + } + if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ + return; + } + tud_cdc_n_write_flush(itf); + xSemaphoreGive(tx_lock); +} + +int USBCDC::availableForWrite(void) +{ + if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || !tud_cdc_n_connected(itf)){ + return 0; + } + if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ + return 0; + } + size_t a = tud_cdc_n_write_available(itf); + xSemaphoreGive(tx_lock); + return a; +} + +size_t USBCDC::write(const uint8_t *buffer, size_t size) +{ + if(itf >= MAX_USB_CDC_DEVICES || tx_lock == NULL || buffer == NULL || size == 0 || !tud_cdc_n_connected(itf)){ + return 0; + } + if(xPortInIsrContext()){ + BaseType_t taskWoken = false; + if(xSemaphoreTakeFromISR(tx_lock, &taskWoken) != pdPASS){ + return 0; + } + } else if(xSemaphoreTake(tx_lock, tx_timeout_ms / portTICK_PERIOD_MS) != pdPASS){ + return 0; + } + size_t to_send = size, so_far = 0; + while(to_send){ + if(!tud_cdc_n_connected(itf)){ + size = so_far; + break; + } + size_t space = tud_cdc_n_write_available(itf); + if(!space){ + tud_cdc_n_write_flush(itf); + continue; + } + if(space > to_send){ + space = to_send; + } + size_t sent = tud_cdc_n_write(itf, buffer+so_far, space); + if(sent){ + so_far += sent; + to_send -= sent; + tud_cdc_n_write_flush(itf); + } else { + size = so_far; + break; + } + } + if(xPortInIsrContext()){ + BaseType_t taskWoken = false; + xSemaphoreGiveFromISR(tx_lock, &taskWoken); + } else { + xSemaphoreGive(tx_lock); + } + return size; +} + +size_t USBCDC::write(uint8_t c) +{ + return write(&c, 1); +} + +uint32_t USBCDC::baudRate() +{ + return bit_rate; +} + +void USBCDC::setDebugOutput(bool en) +{ + if(en) { + uartSetDebug(NULL); + ets_install_putc1((void (*)(char)) &cdc0_write_char); + } else { + ets_install_putc1(NULL); + } +} + +USBCDC::operator bool() const +{ + if(itf >= MAX_USB_CDC_DEVICES){ + return false; + } + return connected; +} + +#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE //Serial used for USB CDC +USBCDC Serial(0); +#endif + +#endif /* CONFIG_TINYUSB_CDC_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBCDC.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBCDC.h new file mode 100644 index 0000000..e5d1bb1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBCDC.h @@ -0,0 +1,149 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "soc/soc_caps.h" +#if SOC_USB_OTG_SUPPORTED + +#include "sdkconfig.h" +#if CONFIG_TINYUSB_CDC_ENABLED + +#include +#include "esp_event.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "Stream.h" + +ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS); + +typedef enum { + ARDUINO_USB_CDC_ANY_EVENT = ESP_EVENT_ANY_ID, + ARDUINO_USB_CDC_CONNECTED_EVENT = 0, + ARDUINO_USB_CDC_DISCONNECTED_EVENT, + ARDUINO_USB_CDC_LINE_STATE_EVENT, + ARDUINO_USB_CDC_LINE_CODING_EVENT, + ARDUINO_USB_CDC_RX_EVENT, + ARDUINO_USB_CDC_TX_EVENT, + ARDUINO_USB_CDC_RX_OVERFLOW_EVENT, + ARDUINO_USB_CDC_MAX_EVENT, +} arduino_usb_cdc_event_t; + +typedef union { + struct { + bool dtr; + bool rts; + } line_state; + struct { + uint32_t bit_rate; + uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits + uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space + uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16 + } line_coding; + struct { + size_t len; + } rx; + struct { + size_t dropped_bytes; + } rx_overflow; +} arduino_usb_cdc_event_data_t; + +class USBCDC: public Stream +{ +public: + USBCDC(uint8_t itf=0); + ~USBCDC(); + + void onEvent(esp_event_handler_t callback); + void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback); + + size_t setRxBufferSize(size_t size); + void setTxTimeoutMs(uint32_t timeout); + void begin(unsigned long baud=0); + void end(); + + int available(void); + int availableForWrite(void); + int peek(void); + int read(void); + size_t read(uint8_t *buffer, size_t size); + size_t write(uint8_t); + size_t write(const uint8_t *buffer, size_t size); + void flush(void); + + inline size_t read(char * buffer, size_t size) + { + return read((uint8_t*) buffer, size); + } + inline size_t write(const char * buffer, size_t size) + { + return write((uint8_t*) buffer, size); + } + inline size_t write(const char * s) + { + return write((uint8_t*) s, strlen(s)); + } + inline size_t write(unsigned long n) + { + return write((uint8_t) n); + } + inline size_t write(long n) + { + return write((uint8_t) n); + } + inline size_t write(unsigned int n) + { + return write((uint8_t) n); + } + inline size_t write(int n) + { + return write((uint8_t) n); + } + uint32_t baudRate(); + void setDebugOutput(bool); + operator bool() const; + + void enableReboot(bool enable); + bool rebootEnabled(void); + + //internal methods + void _onDFU(void); + void _onLineState(bool _dtr, bool _rts); + void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits); + void _onRX(void); + void _onTX(void); + void _onUnplugged(void); + +protected: + uint8_t itf; + uint32_t bit_rate; + uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits + uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space + uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16 + bool dtr; + bool rts; + bool connected; + bool reboot_enable; + QueueHandle_t rx_queue; + SemaphoreHandle_t tx_lock; + uint32_t tx_timeout_ms; + +}; + +#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE //Serial used for USB CDC +extern USBCDC Serial; +#endif + +#endif /* CONFIG_TINYUSB_CDC_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBMSC.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBMSC.cpp new file mode 100644 index 0000000..8b615d9 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBMSC.cpp @@ -0,0 +1,263 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "USBMSC.h" + +#if SOC_USB_OTG_SUPPORTED +#if CONFIG_TINYUSB_MSC_ENABLED + +#include "esp32-hal-tinyusb.h" + +extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf) +{ + uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC"); + uint8_t ep_num = tinyusb_get_free_duplex_endpoint(); + TU_VERIFY (ep_num != 0); + uint8_t descriptor[TUD_MSC_DESC_LEN] = { + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64) + }; + *itf+=1; + memcpy(dst, descriptor, TUD_MSC_DESC_LEN); + return TUD_MSC_DESC_LEN; +} + +typedef struct { + bool media_present; + uint8_t vendor_id[8]; + uint8_t product_id[16]; + uint8_t product_rev[4]; + uint16_t block_size; + uint32_t block_count; + bool (*start_stop)(uint8_t power_condition, bool start, bool load_eject); + int32_t (*read)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + int32_t (*write)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); +} msc_lun_t; + +static const uint8_t MSC_MAX_LUN = 3; +static uint8_t MSC_ACTIVE_LUN = 0; +static msc_lun_t msc_luns[MSC_MAX_LUN]; + +static void cplstr(void *dst, const void * src, size_t max_len){ + if(!src || !dst || !max_len){ + return; + } + size_t l = strlen((const char *)src); + if(l > max_len){ + l = max_len; + } + memcpy(dst, src, l); +} + +// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation +uint8_t tud_msc_get_maxlun_cb(void) +{ + log_v("%u", MSC_ACTIVE_LUN); + return MSC_ACTIVE_LUN; +} + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + log_v("[%u]", lun); + cplstr(vendor_id , msc_luns[lun].vendor_id, 8); + cplstr(product_id , msc_luns[lun].product_id, 16); + cplstr(product_rev, msc_luns[lun].product_rev, 4); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + log_v("[%u]: %u", lun, msc_luns[lun].media_present); + return msc_luns[lun].media_present; // RAM disk is always ready +} + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) +{ + log_v("[%u]", lun); + if(!msc_luns[lun].media_present){ + *block_count = 0; + *block_size = 0; + return; + } + + *block_count = msc_luns[lun].block_count; + *block_size = msc_luns[lun].block_size; +} + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) +{ + log_v("[%u] power: %u, start: %u, eject: %u", lun, power_condition, start, load_eject); + if(msc_luns[lun].start_stop){ + return msc_luns[lun].start_stop(power_condition, start, load_eject); + } + return true; +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) +{ + log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize); + if(!msc_luns[lun].media_present){ + return 0; + } + if(msc_luns[lun].read){ + return msc_luns[lun].read(lba, offset, buffer, bufsize); + } + return 0; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and return number of written bytes +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) +{ + log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize); + if(!msc_luns[lun].media_present){ + return 0; + } + if(msc_luns[lun].write){ + return msc_luns[lun].write(lba, offset, buffer, bufsize); + } + return 0; +} + +// Callback invoked when received an SCSI command not in built-in list below +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ10 and WRITE10 has their own callbacks +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) +{ + // read10 & write10 has their own callback and MUST not be handled here + log_v("[%u] cmd: %u, bufsize: %u", lun, scsi_cmd[0], bufsize); + + void const* response = NULL; + uint16_t resplen = 0; + + // most scsi handled is input + bool in_xfer = true; + + if(!msc_luns[lun].media_present){ + return -1; + } + + switch (scsi_cmd[0]) { + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + // Host is about to read/write etc ... better not to disconnect disk + resplen = 0; + break; + + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed status + resplen = -1; + break; + } + + // return resplen must not larger than bufsize + if (resplen > bufsize) resplen = bufsize; + + if (response && (resplen > 0)) { + if (in_xfer) { + memcpy(buffer, response, resplen); + } else { + // SCSI output + } + } + + return resplen; +} + +USBMSC::USBMSC(){ + if(MSC_ACTIVE_LUN < MSC_MAX_LUN){ + _lun = MSC_ACTIVE_LUN; + MSC_ACTIVE_LUN++; + msc_luns[_lun].media_present = false; + msc_luns[_lun].vendor_id[0] = 0; + msc_luns[_lun].product_id[0] = 0; + msc_luns[_lun].product_rev[0] = 0; + msc_luns[_lun].block_size = 0; + msc_luns[_lun].block_count = 0; + msc_luns[_lun].start_stop = NULL; + msc_luns[_lun].read = NULL; + msc_luns[_lun].write = NULL; + } + if(_lun == 0){ + tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, tusb_msc_load_descriptor); + } +} + +USBMSC::~USBMSC(){ + end(); +} + +bool USBMSC::begin(uint32_t block_count, uint16_t block_size){ + msc_luns[_lun].block_size = block_size; + msc_luns[_lun].block_count = block_count; + if(!msc_luns[_lun].block_size || !msc_luns[_lun].block_count || !msc_luns[_lun].read || !msc_luns[_lun].write){ + return false; + } + return true; +} + +void USBMSC::end(){ + msc_luns[_lun].media_present = false; + msc_luns[_lun].vendor_id[0] = 0; + msc_luns[_lun].product_id[0] = 0; + msc_luns[_lun].product_rev[0] = 0; + msc_luns[_lun].block_size = 0; + msc_luns[_lun].block_count = 0; + msc_luns[_lun].start_stop = NULL; + msc_luns[_lun].read = NULL; + msc_luns[_lun].write = NULL; +} + +void USBMSC::vendorID(const char * vid){ + cplstr(msc_luns[_lun].vendor_id, vid, 8); +} + +void USBMSC::productID(const char * pid){ + cplstr(msc_luns[_lun].product_id, pid, 16); +} + +void USBMSC::productRevision(const char * rev){ + cplstr(msc_luns[_lun].product_rev, rev, 4); +} + +void USBMSC::onStartStop(msc_start_stop_cb cb){ + msc_luns[_lun].start_stop = cb; +} + +void USBMSC::onRead(msc_read_cb cb){ + msc_luns[_lun].read = cb; +} + +void USBMSC::onWrite(msc_write_cb cb){ + msc_luns[_lun].write = cb; +} + +void USBMSC::mediaPresent(bool media_present){ + msc_luns[_lun].media_present = media_present; +} + +#endif /* CONFIG_TINYUSB_MSC_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBMSC.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBMSC.h new file mode 100644 index 0000000..b21a955 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/USBMSC.h @@ -0,0 +1,56 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_USB_OTG_SUPPORTED + +#include +#include +#include "sdkconfig.h" + +#if CONFIG_TINYUSB_MSC_ENABLED + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +typedef bool (*msc_start_stop_cb)(uint8_t power_condition, bool start, bool load_eject); + +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +typedef int32_t (*msc_read_cb)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); + +// Process data in buffer to disk's storage and return number of written bytes +typedef int32_t (*msc_write_cb)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); + +class USBMSC +{ +public: + USBMSC(); + ~USBMSC(); + bool begin(uint32_t block_count, uint16_t block_size); + void end(); + void vendorID(const char * vid);//max 8 chars + void productID(const char * pid);//max 16 chars + void productRevision(const char * ver);//max 4 chars + void mediaPresent(bool media_present); + void onStartStop(msc_start_stop_cb cb); + void onRead(msc_read_cb cb); + void onWrite(msc_write_cb cb); +private: + uint8_t _lun; +}; + +#endif /* CONFIG_TINYUSB_MSC_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Udp.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Udp.h new file mode 100644 index 0000000..fd79975 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/Udp.h @@ -0,0 +1,93 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP: public Stream +{ + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) + { + return addr.raw_address(); + } +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WCharacter.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WCharacter.h new file mode 100644 index 0000000..5342887 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WCharacter.h @@ -0,0 +1,154 @@ +/* + WCharacter.h - Character utility functions for Wiring & Arduino + Copyright (c) 2010 Hernando Barragan. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Character_h +#define Character_h + +#include +#define isascii(__c) ((unsigned)(__c)<=0177) +#define toascii(__c) ((__c)&0177) + +// WCharacter.h prototypes +inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); +inline boolean isAlpha(int c) __attribute__((always_inline)); +inline boolean isAscii(int c) __attribute__((always_inline)); +inline boolean isWhitespace(int c) __attribute__((always_inline)); +inline boolean isControl(int c) __attribute__((always_inline)); +inline boolean isDigit(int c) __attribute__((always_inline)); +inline boolean isGraph(int c) __attribute__((always_inline)); +inline boolean isLowerCase(int c) __attribute__((always_inline)); +inline boolean isPrintable(int c) __attribute__((always_inline)); +inline boolean isPunct(int c) __attribute__((always_inline)); +inline boolean isSpace(int c) __attribute__((always_inline)); +inline boolean isUpperCase(int c) __attribute__((always_inline)); +inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); +inline int toAscii(int c) __attribute__((always_inline)); +inline int toLowerCase(int c) __attribute__((always_inline)); +inline int toUpperCase(int c) __attribute__((always_inline)); + +// Checks for an alphanumeric character. +// It is equivalent to (isalpha(c) || isdigit(c)). +inline boolean isAlphaNumeric(int c) +{ + return (isalnum(c) == 0 ? false : true); +} + +// Checks for an alphabetic character. +// It is equivalent to (isupper(c) || islower(c)). +inline boolean isAlpha(int c) +{ + return (isalpha(c) == 0 ? false : true); +} + +// Checks whether c is a 7-bit unsigned char value +// that fits into the ASCII character set. +inline boolean isAscii(int c) +{ + return ( isascii (c) == 0 ? false : true); +} + +// Checks for a blank character, that is, a space or a tab. +inline boolean isWhitespace(int c) +{ + return (isblank(c) == 0 ? false : true); +} + +// Checks for a control character. +inline boolean isControl(int c) +{ + return (iscntrl(c) == 0 ? false : true); +} + +// Checks for a digit (0 through 9). +inline boolean isDigit(int c) +{ + return (isdigit(c) == 0 ? false : true); +} + +// Checks for any printable character except space. +inline boolean isGraph(int c) +{ + return (isgraph(c) == 0 ? false : true); +} + +// Checks for a lower-case character. +inline boolean isLowerCase(int c) +{ + return (islower(c) == 0 ? false : true); +} + +// Checks for any printable character including space. +inline boolean isPrintable(int c) +{ + return (isprint(c) == 0 ? false : true); +} + +// Checks for any printable character which is not a space +// or an alphanumeric character. +inline boolean isPunct(int c) +{ + return (ispunct(c) == 0 ? false : true); +} + +// Checks for white-space characters. For the avr-libc library, +// these are: space, formfeed ('\f'), newline ('\n'), carriage +// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). +inline boolean isSpace(int c) +{ + return (isspace(c) == 0 ? false : true); +} + +// Checks for an uppercase letter. +inline boolean isUpperCase(int c) +{ + return (isupper(c) == 0 ? false : true); +} + +// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f A B C D E F. +inline boolean isHexadecimalDigit(int c) +{ + return (isxdigit(c) == 0 ? false : true); +} + +// Converts c to a 7-bit unsigned char value that fits into the +// ASCII character set, by clearing the high-order bits. +inline int toAscii(int c) +{ + return toascii(c); +} + +// Warning: +// Many people will be unhappy if you use this function. +// This function will convert accented letters into random +// characters. + +// Converts the letter c to lower case, if possible. +inline int toLowerCase(int c) +{ + return tolower(c); +} + +// Converts the letter c to upper case, if possible. +inline int toUpperCase(int c) +{ + return toupper(c); +} + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WMath.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WMath.cpp new file mode 100644 index 0000000..eb51cb4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WMath.cpp @@ -0,0 +1,95 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + Copyright (c) 2004-06 Hernando Barragan + Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ + */ + +extern "C" { +#include +#include "esp_system.h" +} +#include "esp32-hal-log.h" +#include "esp_random.h" + +// Allows the user to choose between Real Hardware +// or Software Pseudo random generators for the +// Arduino random() functions +static bool s_useRandomHW = true; +void useRealRandomGenerator(bool useRandomHW) { + s_useRandomHW = useRandomHW; +} + +// Calling randomSeed() will force the +// Pseudo Random generator like in +// Arduino mainstream API +void randomSeed(unsigned long seed) +{ + if(seed != 0) { + srand(seed); + s_useRandomHW = false; + } +} + +long random( long howsmall, long howbig ); +long random( long howbig ) +{ + if ( howbig == 0 ) + { + return 0 ; + } + if (howbig < 0) { + return (random(0, -howbig)); + } + // if randomSeed was called, fall back to software PRNG + uint32_t val = (s_useRandomHW) ? esp_random() : rand(); + return val % howbig; +} + +long random(long howsmall, long howbig) +{ + if(howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return random(diff) + howsmall; +} + +long map(long x, long in_min, long in_max, long out_min, long out_max) { + const long run = in_max - in_min; + if(run == 0){ + log_e("map(): Invalid input range, min == max"); + return -1; // AVR returns -1, SAM returns 0 + } + const long rise = out_max - out_min; + const long delta = x - in_min; + return (delta * rise) / run + out_min; +} + +uint16_t makeWord(uint16_t w) +{ + return w; +} + +uint16_t makeWord(uint8_t h, uint8_t l) +{ + return (h << 8) | l; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WString.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WString.cpp new file mode 100644 index 0000000..6f0a4fc --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WString.cpp @@ -0,0 +1,861 @@ +/* + WString.cpp - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + Modified by Ivan Grokhotkov, 2014 - esp8266 support + Modified by Michael C. Miller, 2015 - esp8266 progmem support + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Arduino.h" +#include "WString.h" +#include "stdlib_noniso.h" +#include "esp32-hal-log.h" + +/*********************************************/ +/* Constructors */ +/*********************************************/ + +String::String(const char *cstr) { + init(); + if (cstr) + copy(cstr, strlen(cstr)); +} + +String::String(const char *cstr, unsigned int length) { + init(); + if (cstr) + copy(cstr, length); +} + +String::String(const String &value) { + init(); + *this = value; +} + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +String::String(String &&rval) { + init(); + move(rval); +} + +String::String(StringSumHelper &&rval) { + init(); + move(rval); +} +#endif + +String::String(char c) { + init(); + char buf[] = { c, '\0' }; + *this = buf; +} + +String::String(unsigned char value, unsigned char base) { + init(); + char buf[1 + 8 * sizeof(unsigned char)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(int value, unsigned char base) { + init(); + char buf[2 + 8 * sizeof(int)]; + itoa(value, buf, base); + *this = buf; +} + +String::String(unsigned int value, unsigned char base) { + init(); + char buf[1 + 8 * sizeof(unsigned int)]; + utoa(value, buf, base); + *this = buf; +} + +String::String(long value, unsigned char base) { + init(); + char buf[2 + 8 * sizeof(long)]; + ltoa(value, buf, base); + *this = buf; +} + +String::String(unsigned long value, unsigned char base) { + init(); + char buf[1 + 8 * sizeof(unsigned long)]; + ultoa(value, buf, base); + *this = buf; +} + +String::String(float value, unsigned int decimalPlaces) { + init(); + char *buf = (char*)malloc(decimalPlaces + 42); + if (buf) { + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + free(buf); + } else { + *this = "nan"; + log_e("No enought memory for the operation."); + } +} + +String::String(double value, unsigned int decimalPlaces) { + init(); + char *buf = (char*)malloc(decimalPlaces + 312); + if (buf) { + *this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf); + free(buf); + } else { + *this = "nan"; + log_e("No enought memory for the operation."); + } +} + +String::String(long long value, unsigned char base) { + init(); + char buf[2 + 8 * sizeof(long long)]; + lltoa(value, buf, base); + *this = buf; +} + +String::String(unsigned long long value, unsigned char base) { + init(); + char buf[1 + 8 * sizeof(unsigned long long)]; + ulltoa(value, buf, base); + *this = buf; +} + +String::~String() { + invalidate(); +} + +/*********************************************/ +/* Memory Management */ +/*********************************************/ + +inline void String::init(void) { + setSSO(false); + setBuffer(nullptr); + setCapacity(0); + setLen(0); +} + +void String::invalidate(void) { + if(!isSSO() && wbuffer()) + free(wbuffer()); + init(); +} + +bool String::reserve(unsigned int size) { + if(buffer() && capacity() >= size) + return true; + if(changeBuffer(size)) { + if(len() == 0) + wbuffer()[0] = 0; + return true; + } + return false; +} + +bool String::changeBuffer(unsigned int maxStrLen) { + // Can we use SSO here to avoid allocation? + if (maxStrLen < sizeof(sso.buff) - 1) { + if (isSSO() || !buffer()) { + // Already using SSO, nothing to do + uint16_t oldLen = len(); + setSSO(true); + setLen(oldLen); + } else { // if bufptr && !isSSO() + // Using bufptr, need to shrink into sso.buff + char temp[sizeof(sso.buff)]; + memcpy(temp, buffer(), maxStrLen); + free(wbuffer()); + uint16_t oldLen = len(); + setSSO(true); + memcpy(wbuffer(), temp, maxStrLen); + setLen(oldLen); + } + return true; + } + // Fallthrough to normal allocator + size_t newSize = (maxStrLen + 16) & (~0xf); + // Make sure we can fit newsize in the buffer + if (newSize > CAPACITY_MAX) { + return false; + } + uint16_t oldLen = len(); + char *newbuffer = (char *) realloc(isSSO() ? nullptr : wbuffer(), newSize); + if (newbuffer) { + size_t oldSize = capacity() + 1; // include NULL. + if (isSSO()) { + // Copy the SSO buffer into allocated space + memmove(newbuffer, sso.buff, sizeof(sso.buff)); + } + if (newSize > oldSize) { + memset(newbuffer + oldSize, 0, newSize - oldSize); + } + setSSO(false); + setCapacity(newSize - 1); + setBuffer(newbuffer); + setLen(oldLen); // Needed in case of SSO where len() never existed + return true; + } + return false; +} + +/*********************************************/ +/* Copy and Move */ +/*********************************************/ + +String & String::copy(const char *cstr, unsigned int length) { + if(!reserve(length)) { + invalidate(); + return *this; + } + memmove(wbuffer(), cstr, length + 1); + setLen(length); + return *this; +} + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +void String::move(String &rhs) { + if(buffer()) { + if(capacity() >= rhs.len()) { + memmove(wbuffer(), rhs.buffer(), rhs.length() + 1); + setLen(rhs.len()); + rhs.invalidate(); + return; + } else { + if (!isSSO()) { + free(wbuffer()); + setBuffer(nullptr); + } + } + } + if (rhs.isSSO()) { + setSSO(true); + memmove(sso.buff, rhs.sso.buff, sizeof(sso.buff)); + } else { + setSSO(false); + setBuffer(rhs.wbuffer()); + } + setCapacity(rhs.capacity()); + setLen(rhs.len()); + rhs.setSSO(false); + rhs.setCapacity(0); + rhs.setBuffer(nullptr); + rhs.setLen(0); +} +#endif + +String & String::operator =(const String &rhs) { + if(this == &rhs) + return *this; + if(rhs.buffer()) + copy(rhs.buffer(), rhs.len()); + else + invalidate(); + return *this; +} + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +String & String::operator =(String &&rval) { + if(this != &rval) + move(rval); + return *this; +} + +String & String::operator =(StringSumHelper &&rval) { + if(this != &rval) + move(rval); + return *this; +} +#endif + +String & String::operator =(const char *cstr) { + if(cstr) + copy(cstr, strlen(cstr)); + else + invalidate(); + return *this; +} + +/*********************************************/ +/* concat */ +/*********************************************/ + +bool String::concat(const String &s) { + // Special case if we're concatting ourself (s += s;) since we may end up + // realloc'ing the buffer and moving s.buffer in the method called + if (&s == this) { + unsigned int newlen = 2 * len(); + if (!s.buffer()) + return false; + if (s.len() == 0) + return true; + if (!reserve(newlen)) + return false; + memmove(wbuffer() + len(), buffer(), len()); + setLen(newlen); + wbuffer()[len()] = 0; + return true; + } else { + return concat(s.buffer(), s.len()); + } +} + +bool String::concat(const char *cstr, unsigned int length) { + unsigned int newlen = len() + length; + if(!cstr) + return false; + if(length == 0) + return true; + if(!reserve(newlen)) + return false; + if (cstr >= wbuffer() && cstr < wbuffer() + len()) + // compatible with SSO in ram #6155 (case "x += x.c_str()") + memmove(wbuffer() + len(), cstr, length + 1); + else + // compatible with source in flash #6367 + memcpy_P(wbuffer() + len(), cstr, length + 1); + setLen(newlen); + return true; +} + +bool String::concat(const char *cstr) { + if(!cstr) + return false; + return concat(cstr, strlen(cstr)); +} + +bool String::concat(char c) { + char buf[] = { c, '\0' }; + return concat(buf, 1); +} + +bool String::concat(unsigned char num) { + char buf[1 + 3 * sizeof(unsigned char)]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(int num) { + char buf[2 + 3 * sizeof(int)]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(unsigned int num) { + char buf[1 + 3 * sizeof(unsigned int)]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(long num) { + char buf[2 + 3 * sizeof(long)]; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(unsigned long num) { + char buf[1 + 3 * sizeof(unsigned long)]; + ultoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(long long num) { + char buf[2 + 3 * sizeof(long long)]; + lltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(unsigned long long num) { + char buf[1 + 3 * sizeof(unsigned long long)]; + ulltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +bool String::concat(float num) { + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +bool String::concat(double num) { + char buf[20]; + char* string = dtostrf(num, 4, 2, buf); + return concat(string, strlen(string)); +} + +/*********************************************/ +/* Concatenate */ +/*********************************************/ + +StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(rhs.buffer(), rhs.len())) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr) { + StringSumHelper &a = const_cast(lhs); + if(!cstr || !a.concat(cstr, strlen(cstr))) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, char c) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(c)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, int num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, long num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, float num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, double num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, long long num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num) { + StringSumHelper &a = const_cast(lhs); + if(!a.concat(num)) + a.invalidate(); + return a; +} + +/*********************************************/ +/* Comparison */ +/*********************************************/ + +int String::compareTo(const String &s) const { + if(!buffer() || !s.buffer()) { + if(s.buffer() && s.len() > 0) + return 0 - *(unsigned char *) s.buffer(); + if(buffer() && len() > 0) + return *(unsigned char *) buffer(); + return 0; + } + return strcmp(buffer(), s.buffer()); +} + +bool String::equals(const String &s2) const { + return (len() == s2.len() && compareTo(s2) == 0); +} + +bool String::equals(const char *cstr) const { + if(len() == 0) + return (cstr == NULL || *cstr == 0); + if(cstr == NULL) + return buffer()[0] == 0; + return strcmp(buffer(), cstr) == 0; +} + +bool String::operator<(const String &rhs) const { + return compareTo(rhs) < 0; +} + +bool String::operator>(const String &rhs) const { + return compareTo(rhs) > 0; +} + +bool String::operator<=(const String &rhs) const { + return compareTo(rhs) <= 0; +} + +bool String::operator>=(const String &rhs) const { + return compareTo(rhs) >= 0; +} + +bool String::equalsIgnoreCase(const String &s2) const { + if(this == &s2) + return true; + if(len() != s2.len()) + return false; + if(len() == 0) + return true; + const char *p1 = buffer(); + const char *p2 = s2.buffer(); + while(*p1) { + if(tolower(*p1++) != tolower(*p2++)) + return false; + } + return true; +} + +unsigned char String::equalsConstantTime(const String &s2) const { + // To avoid possible time-based attacks present function + // compares given strings in a constant time. + if(len() != s2.len()) + return 0; + //at this point lengths are the same + if(len() == 0) + return 1; + //at this point lengths are the same and non-zero + const char *p1 = buffer(); + const char *p2 = s2.buffer(); + unsigned int equalchars = 0; + unsigned int diffchars = 0; + while(*p1) { + if(*p1 == *p2) + ++equalchars; + else + ++diffchars; + ++p1; + ++p2; + } + //the following should force a constant time eval of the condition without a compiler "logical shortcut" + unsigned char equalcond = (equalchars == len()); + unsigned char diffcond = (diffchars == 0); + return (equalcond & diffcond); //bitwise AND +} + +bool String::startsWith(const String &s2) const { + if(len() < s2.len()) + return false; + return startsWith(s2, 0); +} + +bool String::startsWith(const String &s2, unsigned int offset) const { + if(offset > (unsigned)(len() - s2.len()) || !buffer() || !s2.buffer()) + return false; + return strncmp(&buffer()[offset], s2.buffer(), s2.len()) == 0; +} + +bool String::endsWith(const String &s2) const { + if(len() < s2.len() || !buffer() || !s2.buffer()) + return false; + return strcmp(&buffer()[len() - s2.len()], s2.buffer()) == 0; +} + +/*********************************************/ +/* Character Access */ +/*********************************************/ + +char String::charAt(unsigned int loc) const { + return operator[](loc); +} + +void String::setCharAt(unsigned int loc, char c) { + if(loc < len()) + wbuffer()[loc] = c; +} + +char & String::operator[](unsigned int index) { + static char dummy_writable_char; + if(index >= len() || !buffer()) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return wbuffer()[index]; +} + +char String::operator[](unsigned int index) const { + if(index >= len() || !buffer()) + return 0; + return buffer()[index]; +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const { + if(!bufsize || !buf) + return; + if(index >= len()) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if(n > len() - index) + n = len() - index; + strncpy((char *) buf, buffer() + index, n); + buf[n] = 0; +} + +/*********************************************/ +/* Search */ +/*********************************************/ + +int String::indexOf(char c) const { + return indexOf(c, 0); +} + +int String::indexOf(char ch, unsigned int fromIndex) const { + if(fromIndex >= len()) + return -1; + const char *temp = strchr(buffer() + fromIndex, ch); + if(temp == NULL) + return -1; + return temp - buffer(); +} + +int String::indexOf(const String &s2) const { + return indexOf(s2, 0); +} + +int String::indexOf(const String &s2, unsigned int fromIndex) const { + if(fromIndex >= len()) + return -1; + const char *found = strstr(buffer() + fromIndex, s2.buffer()); + if(found == NULL) + return -1; + return found - buffer(); +} + +int String::lastIndexOf(char theChar) const { + return lastIndexOf(theChar, len() - 1); +} + +int String::lastIndexOf(char ch, unsigned int fromIndex) const { + if(fromIndex >= len()) + return -1; + char tempchar = buffer()[fromIndex + 1]; + wbuffer()[fromIndex + 1] = '\0'; + char* temp = strrchr(wbuffer(), ch); + wbuffer()[fromIndex + 1] = tempchar; + if(temp == NULL) + return -1; + return temp - buffer(); +} + +int String::lastIndexOf(const String &s2) const { + return lastIndexOf(s2, len() - s2.len()); +} + +int String::lastIndexOf(const String &s2, unsigned int fromIndex) const { + if(s2.len() == 0 || len() == 0 || s2.len() > len()) + return -1; + if(fromIndex >= len()) + fromIndex = len() - 1; + int found = -1; + for(char *p = wbuffer(); p <= wbuffer() + fromIndex; p++) { + p = strstr(p, s2.buffer()); + if(!p) + break; + if((unsigned int) (p - wbuffer()) <= fromIndex) + found = p - buffer(); + } + return found; +} + +String String::substring(unsigned int left, unsigned int right) const { + if(left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if(left >= len()) + return out; + if(right > len()) + right = len(); + out.copy(buffer() + left, right - left); + return out; +} + +/*********************************************/ +/* Modification */ +/*********************************************/ + +void String::replace(char find, char replace) { + if(!buffer()) + return; + for(char *p = wbuffer(); *p; p++) { + if(*p == find) + *p = replace; + } +} + +void String::replace(const String &find, const String &replace) { + if(len() == 0 || find.len() == 0) + return; + int diff = replace.len() - find.len(); + char *readFrom = wbuffer(); + char *foundAt; + if(diff == 0) { + while((foundAt = strstr(readFrom, find.buffer())) != NULL) { + memmove(foundAt, replace.buffer(), replace.len()); + readFrom = foundAt + replace.len(); + } + } else if(diff < 0) { + char *writeTo = wbuffer(); + unsigned int l = len(); + while((foundAt = strstr(readFrom, find.buffer())) != NULL) { + unsigned int n = foundAt - readFrom; + memmove(writeTo, readFrom, n); + writeTo += n; + memmove(writeTo, replace.buffer(), replace.len()); + writeTo += replace.len(); + readFrom = foundAt + find.len(); + l += diff; + } + memmove(writeTo, readFrom, strlen(readFrom)+1); + setLen(l); + } else { + unsigned int size = len(); // compute size needed for result + while((foundAt = strstr(readFrom, find.buffer())) != NULL) { + readFrom = foundAt + find.len(); + size += diff; + } + if(size == len()) + return; + if(size > capacity() && !changeBuffer(size)) { + log_w("String.Replace() Insufficient space to replace string"); + return; + } + int index = len() - 1; + while(index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + readFrom = wbuffer() + index + find.len(); + memmove(readFrom + diff, readFrom, len() - (readFrom - buffer())); + int newLen = len() + diff; + memmove(wbuffer() + index, replace.buffer(), replace.len()); + setLen(newLen); + wbuffer()[newLen] = 0; + index--; + } + } +} + +void String::remove(unsigned int index) { + // Pass the biggest integer as the count. The remove method + // below will take care of truncating it at the end of the + // string. + remove(index, (unsigned int) -1); +} + +void String::remove(unsigned int index, unsigned int count) { + if(index >= len()) { + return; + } + if(count <= 0) { + return; + } + if(count > len() - index) { + count = len() - index; + } + char *writeTo = wbuffer() + index; + unsigned int newlen = len() - count; + memmove(writeTo, wbuffer() + index + count, newlen - index); + setLen(newlen); + wbuffer()[newlen] = 0; +} + +void String::toLowerCase(void) { + if(!buffer()) + return; + for(char *p = wbuffer(); *p; p++) { + *p = tolower(*p); + } +} + +void String::toUpperCase(void) { + if(!buffer()) + return; + for(char *p = wbuffer(); *p; p++) { + *p = toupper(*p); + } +} + +void String::trim(void) { + if(!buffer() || len() == 0) + return; + char *begin = wbuffer(); + while(isspace(*begin)) + begin++; + char *end = wbuffer() + len() - 1; + while(isspace(*end) && end >= begin) + end--; + unsigned int newlen = end + 1 - begin; + if(begin > buffer()) + memmove(wbuffer(), begin, newlen); + setLen(newlen); + wbuffer()[newlen] = 0; +} + +/*********************************************/ +/* Parsing / Conversion */ +/*********************************************/ + +long String::toInt(void) const { + if (buffer()) + return atol(buffer()); + return 0; +} + +float String::toFloat(void) const { + if (buffer()) + return atof(buffer()); + return 0; +} + +double String::toDouble(void) const { + if (buffer()) + return atof(buffer()); + return 0.0; +} + +// global empty string to allow returning const String& with nothing + +const String emptyString; diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WString.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WString.h new file mode 100644 index 0000000..6517109 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/WString.h @@ -0,0 +1,404 @@ +/* + WString.h - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... + Copyright (c) 2009-10 Hernando Barragan. All right reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef String_class_h +#define String_class_h +#ifdef __cplusplus + +#include + +#include +#include +#include +#include + + +// A pure abstract class forward used as a means to proide a unique pointer type +// but really is never defined. +class __FlashStringHelper; +#define FPSTR(str_pointer) (reinterpret_cast(str_pointer)) +#define F(string_literal) (FPSTR(PSTR(string_literal))) + +// An inherited class for holding the result of a concatenation. These +// result objects are assumed to be writable by subsequent concatenations. +class StringSumHelper; + +// The string class +class String { + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const { + } + + public: + // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). + String(const char *cstr = ""); + String(const char *cstr, unsigned int length); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + String(const uint8_t *cstr, unsigned int length) : String(reinterpret_cast(cstr), length) {} +#endif + String(const String &str); + String(const __FlashStringHelper *str) : String(reinterpret_cast(str)) {} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + String(String &&rval); + String(StringSumHelper &&rval); +#endif + explicit String(char c); + explicit String(unsigned char, unsigned char base = 10); + explicit String(int, unsigned char base = 10); + explicit String(unsigned int, unsigned char base = 10); + explicit String(long, unsigned char base = 10); + explicit String(unsigned long, unsigned char base = 10); + explicit String(float, unsigned int decimalPlaces = 2); + explicit String(double, unsigned int decimalPlaces = 2); + explicit String(long long, unsigned char base = 10); + explicit String(unsigned long long, unsigned char base = 10); + ~String(void); + + // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., "if (s)" will be true afterwards) + bool reserve(unsigned int size); + inline unsigned int length(void) const { + if(buffer()) { + return len(); + } else { + return 0; + } + } + inline void clear(void) { + setLen(0); + } + inline bool isEmpty(void) const { + return length() == 0; + } + + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid ("if (s)" will be false). + String & operator =(const String &rhs); + String & operator =(const char *cstr); + String & operator = (const __FlashStringHelper *str) {return *this = reinterpret_cast(str);} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + String & operator =(String &&rval); + String & operator =(StringSumHelper &&rval); +#endif + + // concatenate (works w/ built-in types, same as assignment) + + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsuccessful. + bool concat(const String &str); + bool concat(const char *cstr); + bool concat(const char *cstr, unsigned int length); + bool concat(const uint8_t *cstr, unsigned int length) {return concat(reinterpret_cast(cstr), length);} + bool concat(char c); + bool concat(unsigned char c); + bool concat(int num); + bool concat(unsigned int num); + bool concat(long num); + bool concat(unsigned long num); + bool concat(float num); + bool concat(double num); + bool concat(long long num); + bool concat(unsigned long long num); + bool concat(const __FlashStringHelper * str) {return concat(reinterpret_cast(str));} + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) + String & operator +=(const String &rhs) { + concat(rhs); + return (*this); + } + String & operator +=(const char *cstr) { + concat(cstr); + return (*this); + } + String & operator +=(char c) { + concat(c); + return (*this); + } + String & operator +=(unsigned char num) { + concat(num); + return (*this); + } + String & operator +=(int num) { + concat(num); + return (*this); + } + String & operator +=(unsigned int num) { + concat(num); + return (*this); + } + String & operator +=(long num) { + concat(num); + return (*this); + } + String & operator +=(unsigned long num) { + concat(num); + return (*this); + } + String & operator +=(float num) { + concat(num); + return (*this); + } + String & operator +=(double num) { + concat(num); + return (*this); + } + String & operator +=(long long num) { + concat(num); + return (*this); + } + String & operator +=(unsigned long long num) { + concat(num); + return (*this); + } + String & operator += (const __FlashStringHelper *str) {return *this += reinterpret_cast(str);} + + friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator +(const StringSumHelper &lhs, char c); + friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, int num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, long num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, float num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, double num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, long long num); + friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num); + + // comparison (only works w/ Strings and "strings") + operator StringIfHelperType() const { + return buffer() ? &String::StringIfHelper : 0; + } + int compareTo(const String &s) const; + bool equals(const String &s) const; + bool equals(const char *cstr) const; + bool operator ==(const String &rhs) const { + return equals(rhs); + } + bool operator ==(const char *cstr) const { + return equals(cstr); + } + bool operator !=(const String &rhs) const { + return !equals(rhs); + } + bool operator !=(const char *cstr) const { + return !equals(cstr); + } + bool operator <(const String &rhs) const; + bool operator >(const String &rhs) const; + bool operator <=(const String &rhs) const; + bool operator >=(const String &rhs) const; + bool equalsIgnoreCase(const String &s) const; + unsigned char equalsConstantTime(const String &s) const; + bool startsWith(const String &prefix) const; + bool startsWith(const char *prefix) const { + return this->startsWith(String(prefix)); + } + bool startsWith(const __FlashStringHelper *prefix) const { + return this->startsWith(reinterpret_cast(prefix)); + } + bool startsWith(const String &prefix, unsigned int offset) const; + bool endsWith(const String &suffix) const; + bool endsWith(const char *suffix) const { + return this->endsWith(String(suffix)); + } + bool endsWith(const __FlashStringHelper * suffix) const { + return this->endsWith(reinterpret_cast(suffix)); + } + + // character access + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [](unsigned int index) const; + char& operator [](unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const { + getBytes((unsigned char *) buf, bufsize, index); + } + const char* c_str() const { return buffer(); } + char* begin() { return wbuffer(); } + char* end() { return wbuffer() + length(); } + const char* begin() const { return c_str(); } + const char* end() const { return c_str() + length(); } + + // search + int indexOf(char ch) const; + int indexOf(char ch, unsigned int fromIndex) const; + int indexOf(const String &str) const; + int indexOf(const String &str, unsigned int fromIndex) const; + int lastIndexOf(char ch) const; + int lastIndexOf(char ch, unsigned int fromIndex) const; + int lastIndexOf(const String &str) const; + int lastIndexOf(const String &str, unsigned int fromIndex) const; + String substring(unsigned int beginIndex) const { + return substring(beginIndex, len()); + } + String substring(unsigned int beginIndex, unsigned int endIndex) const; + + // modification + void replace(char find, char replace); + void replace(const String &find, const String &replace); + void replace(const char *find, const String &replace) { + this->replace(String(find), replace); + } + void replace(const __FlashStringHelper *find, const String &replace) { + this->replace(reinterpret_cast(find), replace); + } + void replace(const char *find, const char *replace) { + this->replace(String(find), String(replace)); + } + void replace(const __FlashStringHelper *find, const char *replace) { + this->replace(reinterpret_cast(find), String(replace)); + } + void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) { + this->replace(reinterpret_cast(find), reinterpret_cast(replace)); + } + void remove(unsigned int index); + void remove(unsigned int index, unsigned int count); + void toLowerCase(void); + void toUpperCase(void); + void trim(void); + + // parsing/conversion + long toInt(void) const; + float toFloat(void) const; + double toDouble(void) const; + + protected: + // Contains the string info when we're not in SSO mode + struct _ptr { + char * buff; + uint32_t cap; + uint32_t len; + }; + // This allows strings up up to 11 (10 + \0 termination) without any extra space. + enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more + struct _sso { + char buff[SSOSIZE]; + unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields + unsigned char isSSO : 1; + } __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues +#ifdef BOARD_HAS_PSRAM + enum { CAPACITY_MAX = 3145728 }; +#else + enum { CAPACITY_MAX = 65535 }; +#endif + union { + struct _ptr ptr; + struct _sso sso; + }; + // Accessor functions + inline bool isSSO() const { return sso.isSSO; } + inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; } + inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL + inline void setSSO(bool set) { sso.isSSO = set; } + inline void setLen(int len) { + if (isSSO()) { + sso.len = len; + sso.buff[len] = 0; + } else { + ptr.len = len; + if (ptr.buff) { + ptr.buff[len] = 0; + } + } + } + inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; } + inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; } + // Buffer accessor functions + inline const char *buffer() const { return reinterpret_cast(isSSO() ? sso.buff : ptr.buff); } + inline char *wbuffer() const { return isSSO() ? const_cast(sso.buff) : ptr.buff; } // Writable version of buffer + + protected: + void init(void); + void invalidate(void); + bool changeBuffer(unsigned int maxStrLen); + + // copy and move + String & copy(const char *cstr, unsigned int length); + String & copy(const __FlashStringHelper *pstr, unsigned int length) { + return copy(reinterpret_cast(pstr), length); + } +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + void move(String &rhs); +#endif +}; + +class StringSumHelper: public String { + public: + StringSumHelper(const String &s) : + String(s) { + } + StringSumHelper(const char *p) : + String(p) { + } + StringSumHelper(char c) : + String(c) { + } + StringSumHelper(unsigned char num) : + String(num) { + } + StringSumHelper(int num) : + String(num) { + } + StringSumHelper(unsigned int num) : + String(num) { + } + StringSumHelper(long num) : + String(num) { + } + StringSumHelper(unsigned long num) : + String(num) { + } + StringSumHelper(float num) : + String(num) { + } + StringSumHelper(double num) : + String(num) { + } + StringSumHelper(long long num) : + String(num) { + } + StringSumHelper(unsigned long long num) : + String(num) { + } +}; + +inline StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs) { + return lhs + reinterpret_cast(rhs); +} + +extern const String emptyString; + +#endif // __cplusplus +#endif // String_class_h diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/apps/sntp/sntp.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/apps/sntp/sntp.h new file mode 100644 index 0000000..8a940f8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/apps/sntp/sntp.h @@ -0,0 +1 @@ +#include "lwip/apps/sntp.h" diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/base64.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/base64.cpp new file mode 100644 index 0000000..1fc144e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/base64.cpp @@ -0,0 +1,64 @@ +/** + * base64.cpp + * + * Created on: 09.12.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP31B core for Arduino. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "Arduino.h" +extern "C" { +#include "libb64/cdecode.h" +#include "libb64/cencode.h" +} +#include "base64.h" + +/** + * convert input data to base64 + * @param data const uint8_t * + * @param length size_t + * @return String + */ +String base64::encode(const uint8_t * data, size_t length) +{ + size_t size = base64_encode_expected_len(length) + 1; + char * buffer = (char *) malloc(size); + if(buffer) { + base64_encodestate _state; + base64_init_encodestate(&_state); + int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state); + len = base64_encode_blockend((buffer + len), &_state); + + String base64 = String(buffer); + free(buffer); + return base64; + } + return String("-FAIL-"); +} + +/** + * convert input data to base64 + * @param text const String& + * @return String + */ +String base64::encode(const String& text) +{ + return base64::encode((uint8_t *) text.c_str(), text.length()); +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/base64.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/base64.h new file mode 100644 index 0000000..9709581 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/base64.h @@ -0,0 +1,13 @@ +#ifndef CORE_BASE64_H_ +#define CORE_BASE64_H_ + +class base64 +{ +public: + static String encode(const uint8_t * data, size_t length); + static String encode(const String& text); +private: +}; + + +#endif /* CORE_BASE64_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/binary.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/binary.h new file mode 100644 index 0000000..c2f189d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/binary.h @@ -0,0 +1,534 @@ +/* + binary.h - Definitions for binary constants + Copyright (c) 2006 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/cbuf.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/cbuf.cpp new file mode 100644 index 0000000..ef7370a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/cbuf.cpp @@ -0,0 +1,196 @@ +/* + cbuf.cpp - Circular buffer implementation + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "cbuf.h" + +cbuf::cbuf(size_t size) : + next(NULL), _size(size+1), _buf(new char[size+1]), _bufend(_buf + size + 1), _begin(_buf), _end(_begin) +{ +} + +cbuf::~cbuf() +{ + delete[] _buf; +} + +size_t cbuf::resizeAdd(size_t addSize) +{ + return resize(_size + addSize); +} + +size_t cbuf::resize(size_t newSize) +{ + + size_t bytes_available = available(); + newSize += 1; + // not lose any data + // if data can be lost use remove or flush before resize + if((newSize < bytes_available) || (newSize == _size)) { + return _size; + } + + char *newbuf = new char[newSize]; + char *oldbuf = _buf; + + if(!newbuf) { + return _size; + } + + if(_buf) { + read(newbuf, bytes_available); + memset((newbuf + bytes_available), 0x00, (newSize - bytes_available)); + } + + _begin = newbuf; + _end = newbuf + bytes_available; + _bufend = newbuf + newSize; + _size = newSize; + + _buf = newbuf; + delete[] oldbuf; + + return _size; +} + +size_t cbuf::available() const +{ + if(_end >= _begin) { + return _end - _begin; + } + return _size - (_begin - _end); +} + +size_t cbuf::size() +{ + return _size; +} + +size_t cbuf::room() const +{ + if(_end >= _begin) { + return _size - (_end - _begin) - 1; + } + return _begin - _end - 1; +} + +int cbuf::peek() +{ + if(empty()) { + return -1; + } + + return static_cast(*_begin); +} + +size_t cbuf::peek(char *dst, size_t size) +{ + size_t bytes_available = available(); + size_t size_to_read = (size < bytes_available) ? size : bytes_available; + size_t size_read = size_to_read; + char * begin = _begin; + if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { + size_t top_size = _bufend - _begin; + memcpy(dst, _begin, top_size); + begin = _buf; + size_to_read -= top_size; + dst += top_size; + } + memcpy(dst, begin, size_to_read); + return size_read; +} + +int cbuf::read() +{ + if(empty()) { + return -1; + } + + char result = *_begin; + _begin = wrap_if_bufend(_begin + 1); + return static_cast(result); +} + +size_t cbuf::read(char* dst, size_t size) +{ + size_t bytes_available = available(); + size_t size_to_read = (size < bytes_available) ? size : bytes_available; + size_t size_read = size_to_read; + if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) { + size_t top_size = _bufend - _begin; + memcpy(dst, _begin, top_size); + _begin = _buf; + size_to_read -= top_size; + dst += top_size; + } + memcpy(dst, _begin, size_to_read); + _begin = wrap_if_bufend(_begin + size_to_read); + return size_read; +} + +size_t cbuf::write(char c) +{ + if(full()) { + return 0; + } + + *_end = c; + _end = wrap_if_bufend(_end + 1); + return 1; +} + +size_t cbuf::write(const char* src, size_t size) +{ + size_t bytes_available = room(); + size_t size_to_write = (size < bytes_available) ? size : bytes_available; + size_t size_written = size_to_write; + if(_end >= _begin && size_to_write > (size_t) (_bufend - _end)) { + size_t top_size = _bufend - _end; + memcpy(_end, src, top_size); + _end = _buf; + size_to_write -= top_size; + src += top_size; + } + memcpy(_end, src, size_to_write); + _end = wrap_if_bufend(_end + size_to_write); + return size_written; +} + +void cbuf::flush() +{ + _begin = _buf; + _end = _buf; +} + +size_t cbuf::remove(size_t size) +{ + size_t bytes_available = available(); + if(size >= bytes_available) { + flush(); + return 0; + } + size_t size_to_remove = (size < bytes_available) ? size : bytes_available; + if(_end < _begin && size_to_remove > (size_t) (_bufend - _begin)) { + size_t top_size = _bufend - _begin; + _begin = _buf; + size_to_remove -= top_size; + } + _begin = wrap_if_bufend(_begin + size_to_remove); + return available(); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/cbuf.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/cbuf.h new file mode 100644 index 0000000..490352e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/cbuf.h @@ -0,0 +1,79 @@ +/* + cbuf.h - Circular buffer implementation + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __cbuf_h +#define __cbuf_h + +#include +#include +#include + +class cbuf +{ +public: + cbuf(size_t size); + ~cbuf(); + + size_t resizeAdd(size_t addSize); + size_t resize(size_t newSize); + size_t available() const; + size_t size(); + + size_t room() const; + + inline bool empty() const + { + return _begin == _end; + } + + inline bool full() const + { + return wrap_if_bufend(_end + 1) == _begin; + } + + int peek(); + size_t peek(char *dst, size_t size); + + int read(); + size_t read(char* dst, size_t size); + + size_t write(char c); + size_t write(const char* src, size_t size); + + void flush(); + size_t remove(size_t size); + + cbuf *next; + +protected: + inline char* wrap_if_bufend(char* ptr) const + { + return (ptr == _bufend) ? _buf : ptr; + } + + size_t _size; + char* _buf; + const char* _bufend; + char* _begin; + char* _end; + +}; + +#endif//__cbuf_h diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/chip-debug-report.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/chip-debug-report.cpp new file mode 100644 index 0000000..a8821b9 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/chip-debug-report.cpp @@ -0,0 +1,349 @@ +#include "esp_heap_caps.h" +#include "esp_chip_info.h" +#include "esp_idf_version.h" +#include "esp_arduino_version.h" +#include "esp_rom_spiflash.h" +#include "esp_flash.h" +#include "esp_partition.h" +#include "esp_app_format.h" +#include "soc/efuse_reg.h" +#include "soc/rtc.h" +#include "soc/spi_reg.h" +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/spi_flash.h" +#endif +#include "esp_bit_defs.h" + +#include "Arduino.h" +#include "esp32-hal-periman.h" + +#define chip_report_printf log_printf + +#define printMemCapsInfo(caps) _printMemCapsInfo(MALLOC_CAP_##caps, #caps) +#define b2kb(b) ((float)b/1024.0) +#define b2mb(b) ((float)b/(1024.0*1024.0)) +static void _printMemCapsInfo(uint32_t caps, const char * caps_str){ + multi_heap_info_t info; + size_t total = heap_caps_get_total_size(caps); + heap_caps_get_info(&info, caps); + chip_report_printf("%s Memory Info:\n", caps_str); + chip_report_printf("------------------------------------------\n"); + chip_report_printf(" Total Size : %8u B (%6.1f KB)\n", total, b2kb(total)); + chip_report_printf(" Free Bytes : %8u B (%6.1f KB)\n", info.total_free_bytes, b2kb(info.total_free_bytes)); + chip_report_printf(" Allocated Bytes : %8u B (%6.1f KB)\n", info.total_allocated_bytes, b2kb(info.total_allocated_bytes)); + chip_report_printf(" Minimum Free Bytes: %8u B (%6.1f KB)\n", info.minimum_free_bytes, b2kb(info.minimum_free_bytes)); + chip_report_printf(" Largest Free Block: %8u B (%6.1f KB)\n", info.largest_free_block, b2kb(info.largest_free_block)); +} + +static void printPkgVersion(void){ + chip_report_printf(" Package : "); +#if CONFIG_IDF_TARGET_ESP32 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); + switch(pkg_ver){ + case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDR2V3: chip_report_printf("D0WD-R2-V3"); break; + case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6 : chip_report_printf("D0WD-Q6"); break; + case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ5 : chip_report_printf("D0WD-Q5"); break; + case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 : chip_report_printf("D2WD-Q5"); break; + case EFUSE_RD_CHIP_VER_PKG_ESP32U4WDH : chip_report_printf("U4WD-H"); break; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 : chip_report_printf("PICO-D4"); break; + case EFUSE_RD_CHIP_VER_PKG_ESP32PICOV302: chip_report_printf("PICO-V3-02"); break; + } +#elif CONFIG_IDF_TARGET_ESP32S2 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION); + switch (pkg_ver) { + case 1: chip_report_printf("FH16"); break; + case 2: chip_report_printf("FH32"); break; + default: chip_report_printf("%lu", pkg_ver); break; + } +#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION); + chip_report_printf("%lu", pkg_ver); +#elif CONFIG_IDF_TARGET_ESP32C2 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_BLK2_DATA1_REG, EFUSE_PKG_VERSION); + chip_report_printf("%lu", pkg_ver); +#elif CONFIG_IDF_TARGET_ESP32H2 + uint32_t pkg_ver = REG_GET_FIELD(EFUSE_RD_MAC_SYS_4_REG, EFUSE_PKG_VERSION); + chip_report_printf("%lu", pkg_ver); +#else + chip_report_printf("Unknown"); +#endif + chip_report_printf("\n"); +} + +static void printChipInfo(void){ + esp_chip_info_t info; + esp_chip_info(&info); + chip_report_printf("Chip Info:\n"); + chip_report_printf("------------------------------------------\n"); + chip_report_printf(" Model : "); + switch(info.model){ + case CHIP_ESP32: chip_report_printf("ESP32\n"); break; + case CHIP_ESP32S2: chip_report_printf("ESP32-S2\n"); break; + case CHIP_ESP32S3: chip_report_printf("ESP32-S3\n"); break; + case CHIP_ESP32C2: chip_report_printf("ESP32-C2\n"); break; + case CHIP_ESP32C3: chip_report_printf("ESP32-C3\n"); break; + case CHIP_ESP32C6: chip_report_printf("ESP32-C6\n"); break; + case CHIP_ESP32H2: chip_report_printf("ESP32-H2\n"); break; + default: chip_report_printf("Unknown %d\n", info.model); break; + } + printPkgVersion(); + chip_report_printf(" Revision : "); + if(info.revision > 0xFF){ + chip_report_printf("%d.%d\n", info.revision >> 8, info.revision & 0xFF); + } else { + chip_report_printf("%d\n", info.revision); + } + chip_report_printf(" Cores : %d\n", info.cores); + rtc_cpu_freq_config_t conf; + rtc_clk_cpu_freq_get_config(&conf); + chip_report_printf(" Frequency : %lu MHz\n", conf.freq_mhz); + chip_report_printf(" Embedded Flash : %s\n", (info.features & CHIP_FEATURE_EMB_FLASH)?"Yes":"No"); + chip_report_printf(" Embedded PSRAM : %s\n", (info.features & CHIP_FEATURE_EMB_PSRAM)?"Yes":"No"); + chip_report_printf(" 2.4GHz WiFi : %s\n", (info.features & CHIP_FEATURE_WIFI_BGN)?"Yes":"No"); + chip_report_printf(" Classic BT : %s\n", (info.features & CHIP_FEATURE_BT)?"Yes":"No"); + chip_report_printf(" BT Low Energy : %s\n", (info.features & CHIP_FEATURE_BLE)?"Yes":"No"); + chip_report_printf(" IEEE 802.15.4 : %s\n", (info.features & CHIP_FEATURE_IEEE802154)?"Yes":"No"); +} + +static void printFlashInfo(void){ +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + #define ESP_FLASH_IMAGE_BASE 0x1000 +#else + #define ESP_FLASH_IMAGE_BASE 0x0000 +#endif +// REG_SPI_BASE is not defined for S3/C3 ?? +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 + #ifndef REG_SPI_BASE + #define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 ))) + #endif // REG_SPI_BASE +#endif // TARGET + + chip_report_printf("Flash Info:\n"); + chip_report_printf("------------------------------------------\n"); + uint32_t hw_size = 1 << (g_rom_flashchip.device_id & 0xFF); + chip_report_printf(" Chip Size : %8lu B (%.0f MB)\n", hw_size, b2mb(hw_size)); + chip_report_printf(" Block Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.block_size, b2kb(g_rom_flashchip.block_size)); + chip_report_printf(" Sector Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.sector_size, b2kb(g_rom_flashchip.sector_size)); + chip_report_printf(" Page Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.page_size, b2kb(g_rom_flashchip.page_size)); + esp_image_header_t fhdr; + esp_flash_read(esp_flash_default_chip, (void*)&fhdr, ESP_FLASH_IMAGE_BASE, sizeof(esp_image_header_t)); + if(fhdr.magic == ESP_IMAGE_HEADER_MAGIC) { + uint32_t f_freq = 0; + switch(fhdr.spi_speed) { +#if CONFIG_IDF_TARGET_ESP32H2 + case 0x0: f_freq = 32; break; + case 0x2: f_freq = 16; break; + case 0xf: f_freq = 64; break; +#else + case 0x0: f_freq = 40; break; + case 0x1: f_freq = 26; break; + case 0x2: f_freq = 20; break; + case 0xf: f_freq = 80; break; +#endif + default: f_freq = fhdr.spi_speed; break; + } + chip_report_printf(" Bus Speed : %lu MHz\n", f_freq); + } + chip_report_printf(" Bus Mode : "); +#if CONFIG_ESPTOOLPY_OCT_FLASH + chip_report_printf("OPI\n"); +#elif CONFIG_ESPTOOLPY_FLASHMODE_QIO + chip_report_printf("QIO\n"); +#elif CONFIG_ESPTOOLPY_FLASHMODE_QOUT + chip_report_printf("QOUT\n"); +#elif CONFIG_ESPTOOLPY_FLASHMODE_DIO + chip_report_printf("DIO\n"); +#elif CONFIG_ESPTOOLPY_FLASHMODE_DOUT + chip_report_printf("DOUT\n"); +#endif +} + +static void printPartitionsInfo(void){ + chip_report_printf("Partitions Info:\n"); + chip_report_printf("------------------------------------------\n"); + esp_partition_iterator_t iterator = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); + if(iterator != NULL){ + esp_partition_iterator_t it = iterator; + while(it != NULL){ + const esp_partition_t* partition = esp_partition_get(it); + if(partition){ + chip_report_printf(" %17s : addr: 0x%08X, size: %7.1f KB", partition->label, partition->address, b2kb(partition->size)); + if(partition->type == ESP_PARTITION_TYPE_APP){ + chip_report_printf(", type: APP"); + if(partition->subtype == 0){ + chip_report_printf(", subtype: FACTORY"); + } else if(partition->subtype >= 0x10 && partition->subtype < 0x20){ + chip_report_printf(", subtype: OTA_%lu", partition->subtype - 0x10); + } else if(partition->subtype == 0x20){ + chip_report_printf(", subtype: TEST"); + } else { + chip_report_printf(", subtype: 0x%02X", partition->subtype); + } + } else { + chip_report_printf(", type: DATA"); + chip_report_printf(", subtype: "); + switch(partition->subtype){ + case ESP_PARTITION_SUBTYPE_DATA_OTA: chip_report_printf("OTA"); break; + case ESP_PARTITION_SUBTYPE_DATA_PHY: chip_report_printf("PHY"); break; + case ESP_PARTITION_SUBTYPE_DATA_NVS: chip_report_printf("NVS"); break; + case ESP_PARTITION_SUBTYPE_DATA_COREDUMP: chip_report_printf("COREDUMP"); break; + case ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS: chip_report_printf("NVS_KEYS"); break; + case ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM: chip_report_printf("EFUSE_EM"); break; + case ESP_PARTITION_SUBTYPE_DATA_UNDEFINED: chip_report_printf("UNDEFINED"); break; + case ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD: chip_report_printf("ESPHTTPD"); break; + case ESP_PARTITION_SUBTYPE_DATA_FAT: chip_report_printf("FAT"); break; + case ESP_PARTITION_SUBTYPE_DATA_SPIFFS: chip_report_printf("SPIFFS"); break; + default: chip_report_printf("0x%02X", partition->subtype); break; + } + } + chip_report_printf("\n"); + } + it = esp_partition_next(it); + } + //esp_partition_iterator_release(iterator); + } +} + +static void printSoftwareInfo(void){ + chip_report_printf("Software Info:\n"); + chip_report_printf("------------------------------------------\n"); + chip_report_printf(" Compile Date/Time : %s %s\n", __DATE__, __TIME__); +#ifdef ARDUINO_HOST_OS + chip_report_printf(" Compile Host OS : %s\n", ARDUINO_HOST_OS); +#endif + chip_report_printf(" ESP-IDF Version : %s\n", esp_get_idf_version()); + chip_report_printf(" Arduino Version : %s\n", ESP_ARDUINO_VERSION_STR); +} + +static void printBoardInfo(void){ + chip_report_printf("Board Info:\n"); + chip_report_printf("------------------------------------------\n"); + chip_report_printf(" Arduino Board : %s\n", ARDUINO_BOARD); + chip_report_printf(" Arduino Variant : %s\n", ARDUINO_VARIANT); +#ifdef ARDUINO_FQBN + chip_report_printf(" Arduino FQBN : %s\n", ARDUINO_FQBN); +#else +#ifdef CORE_DEBUG_LEVEL + chip_report_printf(" Core Debug Level : %d\n", CORE_DEBUG_LEVEL); +#endif +#ifdef ARDUINO_RUNNING_CORE + chip_report_printf(" Arduino Runs Core : %d\n", ARDUINO_RUNNING_CORE); + chip_report_printf(" Arduino Events on : %d\n", ARDUINO_EVENT_RUNNING_CORE); +#endif +#ifdef ARDUINO_USB_MODE + chip_report_printf(" Arduino USB Mode : %d\n", ARDUINO_USB_MODE); +#endif +#ifdef ARDUINO_USB_CDC_ON_BOOT + chip_report_printf(" CDC On Boot : %d\n", ARDUINO_USB_CDC_ON_BOOT); +#endif +#endif /* ARDUINO_FQBN */ +} + +static void printPerimanInfo(void){ + chip_report_printf("GPIO Info:\n"); + chip_report_printf("------------------------------------------\n"); + for(uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++){ + if(!perimanPinIsValid(i)){ + continue;//invalid pin + } + peripheral_bus_type_t type = perimanGetPinBusType(i); + if(type == ESP32_BUS_TYPE_INIT){ + continue;//unused pin + } + chip_report_printf(" %17u : ", i); + switch(type){ + case ESP32_BUS_TYPE_GPIO: chip_report_printf("GPIO\n"); break; + case ESP32_BUS_TYPE_UART_RX: chip_report_printf("UART_RX\n"); break; + case ESP32_BUS_TYPE_UART_TX: chip_report_printf("UART_TX\n"); break; + case ESP32_BUS_TYPE_UART_CTS: chip_report_printf("UART_CTS\n"); break; + case ESP32_BUS_TYPE_UART_RTS: chip_report_printf("UART_RTS\n"); break; +#if SOC_SDM_SUPPORTED + case ESP32_BUS_TYPE_SIGMADELTA: chip_report_printf("SIGMADELTA\n"); break; +#endif +#if SOC_ADC_SUPPORTED + case ESP32_BUS_TYPE_ADC_ONESHOT: chip_report_printf("ADC_ONESHOT\n"); break; + case ESP32_BUS_TYPE_ADC_CONT: chip_report_printf("ADC_CONT\n"); break; +#endif +#if SOC_DAC_SUPPORTED + case ESP32_BUS_TYPE_DAC_ONESHOT: chip_report_printf("DAC_ONESHOT\n"); break; + case ESP32_BUS_TYPE_DAC_CONT: chip_report_printf("DAC_CONT\n"); break; + case ESP32_BUS_TYPE_DAC_COSINE: chip_report_printf("DAC_COSINE\n"); break; +#endif +#if SOC_LEDC_SUPPORTED + case ESP32_BUS_TYPE_LEDC: chip_report_printf("LEDC\n"); break; +#endif +#if SOC_RMT_SUPPORTED + case ESP32_BUS_TYPE_RMT_TX: chip_report_printf("RMT_TX\n"); break; + case ESP32_BUS_TYPE_RMT_RX: chip_report_printf("RMT_RX\n"); break; +#endif +#if SOC_I2S_SUPPORTED + case ESP32_BUS_TYPE_I2S_STD: chip_report_printf("I2S_STD\n"); break; + case ESP32_BUS_TYPE_I2S_PDM: chip_report_printf("I2S_PDM\n"); break; + case ESP32_BUS_TYPE_I2S_TDM: chip_report_printf("I2S_TDM\n"); break; +#endif +#if SOC_I2C_SUPPORTED + case ESP32_BUS_TYPE_I2C_MASTER: chip_report_printf("I2C_MASTER\n"); break; + case ESP32_BUS_TYPE_I2C_SLAVE: chip_report_printf("I2C_SLAVE\n"); break; +#endif +#if SOC_GPSPI_SUPPORTED + case ESP32_BUS_TYPE_SPI_MASTER: chip_report_printf("SPI_MASTER\n"); break; +#endif +#if SOC_SDMMC_HOST_SUPPORTED + case ESP32_BUS_TYPE_SDMMC: chip_report_printf("SDMMC\n"); break; +#endif +#if SOC_TOUCH_SENSOR_SUPPORTED + case ESP32_BUS_TYPE_TOUCH: chip_report_printf("TOUCH\n"); break; +#endif +#if SOC_USB_SERIAL_JTAG_SUPPORTED || SOC_USB_OTG_SUPPORTED + case ESP32_BUS_TYPE_USB: chip_report_printf("USB\n"); break; +#endif + default: chip_report_printf("%d\n", type); break; + } + } +} + +void printBeforeSetupInfo(void){ +#if ARDUINO_USB_CDC_ON_BOOT + Serial.begin(0); + Serial.setDebugOutput(true); + uint8_t t = 0; + while(!Serial && (t++ < 200)) delay(10); //wait up to 2 seconds for the IDE to connect +#endif + chip_report_printf("=========== Before Setup Start ===========\n"); + printChipInfo(); + chip_report_printf("------------------------------------------\n"); + printMemCapsInfo(INTERNAL); + chip_report_printf("------------------------------------------\n"); + if(psramFound()){ + printMemCapsInfo(SPIRAM); + chip_report_printf(" Bus Mode : "); +#if CONFIG_SPIRAM_MODE_OCT + chip_report_printf("OPI\n"); +#else + chip_report_printf("QSPI\n"); +#endif + chip_report_printf("------------------------------------------\n"); + } + printFlashInfo(); + chip_report_printf("------------------------------------------\n"); + printPartitionsInfo(); + chip_report_printf("------------------------------------------\n"); + printSoftwareInfo(); + chip_report_printf("------------------------------------------\n"); + printBoardInfo(); + chip_report_printf("============ Before Setup End ============\n"); + delay(100); //allow the print to finish +} + +void printAfterSetupInfo(void){ + chip_report_printf("=========== After Setup Start ============\n"); + printMemCapsInfo(INTERNAL); + chip_report_printf("------------------------------------------\n"); + if(psramFound()){ + printMemCapsInfo(SPIRAM); + chip_report_printf("------------------------------------------\n"); + } + printPerimanInfo(); + chip_report_printf("============ After Setup End =============\n"); + delay(20); //allow the print to finish +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/chip-debug-report.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/chip-debug-report.h new file mode 100644 index 0000000..5c2c849 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/chip-debug-report.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +void printBeforeSetupInfo(void); +void printAfterSetupInfo(void); diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-adc.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-adc.c new file mode 100644 index 0000000..4278b2d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-adc.c @@ -0,0 +1,692 @@ +// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-adc.h" + +#if SOC_ADC_SUPPORTED +#include "esp32-hal.h" +#include "esp32-hal-periman.h" +#include "esp_adc/adc_oneshot.h" +#include "esp_adc/adc_continuous.h" +#include "esp_adc/adc_cali_scheme.h" + +static uint8_t __analogAttenuation = ADC_11db; +static uint8_t __analogWidth = SOC_ADC_RTC_MAX_BITWIDTH; +static uint8_t __analogReturnedWidth = SOC_ADC_RTC_MAX_BITWIDTH; + +typedef struct { + voidFuncPtr fn; + void* arg; +} interrupt_config_t; + +typedef struct { + adc_oneshot_unit_handle_t adc_oneshot_handle; + adc_continuous_handle_t adc_continuous_handle; + interrupt_config_t adc_interrupt_handle; + adc_cali_handle_t adc_cali_handle; + uint32_t buffer_size; + uint32_t conversion_frame_size; +} adc_handle_t; + +adc_handle_t adc_handle[SOC_ADC_PERIPH_NUM]; + +static bool adcDetachBus(void * pin){ + adc_channel_t adc_channel; + adc_unit_t adc_unit; + uint8_t used_channels = 0; + + adc_oneshot_io_to_channel((int)(pin-1), &adc_unit, &adc_channel); + for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(adc_unit); channel++){ + int io_pin; + adc_oneshot_channel_to_io(adc_unit, channel, &io_pin); + if(perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_ONESHOT){ + used_channels++; + } + } + + if(used_channels == 1){ //only 1 channel is used + esp_err_t err = adc_oneshot_del_unit(adc_handle[adc_unit].adc_oneshot_handle); + if(err != ESP_OK){ + return false; + } + adc_handle[adc_unit].adc_oneshot_handle = NULL; + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #endif + adc_handle[adc_unit].adc_cali_handle = NULL; + } + return true; +} + +esp_err_t __analogChannelConfig(adc_bitwidth_t width, adc_attenuation_t atten, int8_t pin){ + esp_err_t err = ESP_OK; + adc_oneshot_chan_cfg_t config = { + .bitwidth = width, + .atten = (atten & 3), + }; + if(pin == -1){ //Reconfigure all used analog pins/channels + for(int adc_unit = 0 ; adc_unit < SOC_ADC_PERIPH_NUM; adc_unit++){ + if(adc_handle[adc_unit].adc_oneshot_handle != NULL){ + for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(adc_unit); channel++){ + int io_pin; + adc_oneshot_channel_to_io( adc_unit, channel, &io_pin); + if(perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_ONESHOT){ + err = adc_oneshot_config_channel(adc_handle[adc_unit].adc_oneshot_handle, channel, &config); + if(err != ESP_OK){ + log_e("adc_oneshot_config_channel failed with error: %d", err); + return err; + } + } + } + //ADC calibration reconfig only if all channels are updated + if(adc_handle[adc_unit].adc_cali_handle != NULL){ + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + log_d("Deleting ADC_UNIT_%d cali handle",adc_unit); + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + log_e("adc_cali_delete_scheme_curve_fitting failed with error: %d", err); + return err; + } + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = adc_unit, + .atten = atten, + .bitwidth = width, + }; + log_d("Creating ADC_UNIT_%d curve cali handle",adc_unit); + err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + log_e("adc_cali_create_scheme_curve_fitting failed with error: %d", err); + return err; + } + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + log_d("Deleting ADC_UNIT_%d line cali handle",adc_unit); + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + log_e("adc_cali_delete_scheme_line_fitting failed with error: %d", err); + return err; + } + adc_cali_line_fitting_config_t cali_config = { + .unit_id = adc_unit, + .atten = atten, + .bitwidth = width, + }; + log_d("Creating ADC_UNIT_%d line cali handle",adc_unit); + err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + log_e("adc_cali_create_scheme_line_fitting failed with error: %d", err); + return err; + } + #endif + } + } + } + + //make it default for next channels + __analogWidth = width; + __analogAttenuation = atten; + } + else{ //Reconfigure single channel + if(perimanGetPinBusType(pin) == ESP32_BUS_TYPE_ADC_ONESHOT){ + adc_channel_t channel; + adc_unit_t adc_unit; + + adc_oneshot_io_to_channel(pin, &adc_unit, &channel); + if(err != ESP_OK){ + log_e("Pin %u is not ADC pin!", pin); + return err; + } + err = adc_oneshot_config_channel(adc_handle[adc_unit].adc_oneshot_handle, channel, &config); + if(err != ESP_OK){ + log_e("adc_oneshot_config_channel failed with error: %d", err); + return err; + } + } + else { + log_e("Pin is not configured as analog channel"); + } + } + return ESP_OK; +} + +static inline uint16_t mapResolution(uint16_t value){ + uint8_t from = __analogWidth; + if (from == __analogReturnedWidth){ + return value; + } + if (from > __analogReturnedWidth){ + return value >> (from - __analogReturnedWidth); + } + return value << (__analogReturnedWidth - from); +} + +void __analogSetAttenuation(adc_attenuation_t attenuation){ + if(__analogChannelConfig(__analogWidth, attenuation, -1) != ESP_OK){ + log_e("__analogChannelConfig failed!"); + } +} + +#if CONFIG_IDF_TARGET_ESP32 +void __analogSetWidth(uint8_t bits){ + if(bits < SOC_ADC_RTC_MIN_BITWIDTH){ + bits = SOC_ADC_RTC_MIN_BITWIDTH; + } + else if(bits > SOC_ADC_RTC_MAX_BITWIDTH){ + bits = SOC_ADC_RTC_MAX_BITWIDTH; + } + if(__analogChannelConfig(bits, __analogAttenuation, -1) != ESP_OK){ + log_e("__analogChannelConfig failed!"); + } +} +#endif + +esp_err_t __analogInit(uint8_t pin, adc_channel_t channel, adc_unit_t adc_unit){ + esp_err_t err = ESP_OK; + if(adc_handle[adc_unit].adc_oneshot_handle == NULL) { + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = adc_unit, + .ulp_mode = ADC_ULP_MODE_DISABLE, + }; + err = adc_oneshot_new_unit(&init_config1, &adc_handle[adc_unit].adc_oneshot_handle); + + if(err != ESP_OK){ + log_e("adc_oneshot_new_unit failed with error: %d", err); + return err; + } + } + + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_ADC_ONESHOT, (void *)(pin+1))){ + adcDetachBus((void *)(pin+1)); + return err; + } + + adc_oneshot_chan_cfg_t config = { + .bitwidth = __analogWidth, + .atten = __analogAttenuation, + }; + + err = adc_oneshot_config_channel(adc_handle[adc_unit].adc_oneshot_handle, channel, &config); + if(err != ESP_OK){ + log_e("adc_oneshot_config_channel failed with error: %d", err); + return err; + } + perimanSetBusDeinit(ESP32_BUS_TYPE_ADC_ONESHOT, adcDetachBus); + return ESP_OK; +} + +void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation){ + if(__analogChannelConfig(__analogWidth, attenuation, pin) != ESP_OK) + { + log_e("__analogChannelConfig failed!"); + } +} + +void __analogReadResolution(uint8_t bits){ + if(!bits || bits > 16){ + return; + } + __analogReturnedWidth = bits; + +#if CONFIG_IDF_TARGET_ESP32 + __analogSetWidth(bits); // hardware analog resolution from 9 to 12 +#endif +} + +uint16_t __analogRead(uint8_t pin){ + int value = 0; + adc_channel_t channel; + adc_unit_t adc_unit; + + esp_err_t err = ESP_OK; + err = adc_oneshot_io_to_channel(pin, &adc_unit, &channel); + if(err != ESP_OK){ + log_e("Pin %u is not ADC pin!", pin); + return value; + } + + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_ADC_ONESHOT) == NULL){ + log_d("Calling __analogInit! pin = %d", pin); + err = __analogInit(pin, channel, adc_unit); + if(err != ESP_OK){ + log_e("Analog initialization failed!"); + return value; + } + } + + adc_oneshot_read(adc_handle[adc_unit].adc_oneshot_handle, channel, &value); + return mapResolution(value); +} + +uint32_t __analogReadMilliVolts(uint8_t pin){ + int value = 0; + adc_channel_t channel; + adc_unit_t adc_unit; + esp_err_t err = ESP_OK; + + adc_oneshot_io_to_channel(pin, &adc_unit, &channel); + if(err != ESP_OK){ + log_e("Pin %u is not ADC pin!", pin); + return value; + } + + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_ADC_ONESHOT) == NULL){ + err = __analogInit(pin, channel, adc_unit); + if(err != ESP_OK){ + log_e("Analog initialization failed!"); + return value; + } + } + + if(adc_handle[adc_unit].adc_cali_handle == NULL){ + log_d("Creating cali handle for ADC_%d", adc_unit); + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = adc_unit, + .atten = __analogAttenuation, + .bitwidth = __analogWidth, + }; + err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + adc_cali_line_fitting_config_t cali_config = { + .unit_id = adc_unit, + .bitwidth = __analogWidth, + .atten = __analogAttenuation, + }; + err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #endif + if(err != ESP_OK){ + log_e("adc_cali_create_scheme_x failed!"); + return value; + } + } + + err = adc_oneshot_get_calibrated_result(adc_handle[adc_unit].adc_oneshot_handle, adc_handle[adc_unit].adc_cali_handle, channel, &value); + if(err != ESP_OK){ + log_e("adc_oneshot_get_calibrated_result failed!"); + return 0; + } + return value; +} + +extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead"))); +extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts"))); +extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution"))); +extern void analogSetAttenuation(adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetAttenuation"))); +extern void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetPinAttenuation"))); + +#if CONFIG_IDF_TARGET_ESP32 +extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth"))); +#endif + +/* + * ADC Continuous mode + */ + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + #define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE1 + #define ADC_GET_CHANNEL(p_data) ((p_data)->type1.channel) + #define ADC_GET_DATA(p_data) ((p_data)->type1.data) +#else + #define ADC_OUTPUT_TYPE ADC_DIGI_OUTPUT_FORMAT_TYPE2 + #define ADC_GET_CHANNEL(p_data) ((p_data)->type2.channel) + #define ADC_GET_DATA(p_data) ((p_data)->type2.data) +#endif + +static uint8_t __adcContinuousAtten = ADC_11db; +static uint8_t __adcContinuousWidth = SOC_ADC_DIGI_MAX_BITWIDTH; + +static uint8_t used_adc_channels = 0; +adc_continuos_data_t * adc_result = NULL; + +static bool adcContinuousDetachBus(void * adc_unit_number){ + adc_unit_t adc_unit = (adc_unit_t)adc_unit_number - 1; + + if(adc_handle[adc_unit].adc_continuous_handle == NULL){ + return true; + } + else + { + esp_err_t err = adc_continuous_deinit(adc_handle[adc_unit].adc_continuous_handle); + if(err != ESP_OK){ + return false; + } + adc_handle[adc_unit].adc_continuous_handle = NULL; + + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + err = adc_cali_delete_scheme_curve_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) + err = adc_cali_delete_scheme_line_fitting(adc_handle[adc_unit].adc_cali_handle); + if(err != ESP_OK){ + return false; + } + #endif + adc_handle[adc_unit].adc_cali_handle = NULL; + + //set all used pins to INIT state + for (uint8_t channel = 0; channel < SOC_ADC_CHANNEL_NUM(adc_unit); channel++){ + int io_pin; + adc_oneshot_channel_to_io(adc_unit, channel, &io_pin); + if(perimanGetPinBusType(io_pin) == ESP32_BUS_TYPE_ADC_CONT){ + if(!perimanSetPinBus(io_pin, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + } + } + } + return true; +} + +bool IRAM_ATTR adcFnWrapper(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *args){ + interrupt_config_t * isr = (interrupt_config_t*)args; + //Check if edata->size matches conversion_frame_size, else just return from ISR + if(edata->size == adc_handle[0].conversion_frame_size){ + if(isr->fn) { + if(isr->arg){ + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } + } + } + return false; +} + +esp_err_t __analogContinuousInit(adc_channel_t *channel, uint8_t channel_num, adc_unit_t adc_unit, uint32_t sampling_freq_hz){ + //Create new ADC continuous handle + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = adc_handle[adc_unit].buffer_size, + .conv_frame_size = adc_handle[adc_unit].conversion_frame_size, + }; + + esp_err_t err = adc_continuous_new_handle(&adc_config, &adc_handle[adc_unit].adc_continuous_handle); + if(err != ESP_OK){ + log_e("adc_continuous_new_handle failed with error: %d", err); + return ESP_FAIL; + } + + //Configure adc pins + adc_continuous_config_t dig_cfg = { + .sample_freq_hz = sampling_freq_hz, + .conv_mode = ADC_CONV_SINGLE_UNIT_1, + .format = ADC_OUTPUT_TYPE, + }; + adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0}; + dig_cfg.pattern_num = channel_num; + for (int i = 0; i < channel_num; i++) { + adc_pattern[i].atten = __adcContinuousAtten; + adc_pattern[i].channel = channel[i] & 0x7; + adc_pattern[i].unit = ADC_UNIT_1; + adc_pattern[i].bit_width = __adcContinuousWidth; + } + dig_cfg.adc_pattern = adc_pattern; + err = adc_continuous_config(adc_handle[adc_unit].adc_continuous_handle, &dig_cfg); + + if(err != ESP_OK){ + log_e("adc_continuous_config failed with error: %d", err); + return ESP_FAIL; + } + + used_adc_channels = channel_num; + return ESP_OK; +} + + +bool analogContinuous(uint8_t pins[], size_t pins_count, uint32_t conversions_per_pin, uint32_t sampling_freq_hz, void (*userFunc)(void)){ + adc_channel_t channel[pins_count]; + adc_unit_t adc_unit; + esp_err_t err = ESP_OK; + + //Convert pins to channels and check if all are ADC1s unit + for(int i = 0; i < pins_count; i++){ + err = adc_continuous_io_to_channel(pins[i], &adc_unit, &channel[i]); + if(err != ESP_OK){ + log_e("Pin %u is not ADC pin!", pins[i]); + return false; + } + if(adc_unit != 0){ + log_e("Only ADC1 pins are supported in continuous mode!"); + return false; + } + } + + //Check if Oneshot and Continous handle exists + if(adc_handle[adc_unit].adc_oneshot_handle != NULL){ + log_e("ADC%d is running in oneshot mode. Aborting.", adc_unit+1); + return false; + } + if(adc_handle[adc_unit].adc_continuous_handle != NULL){ + log_e("ADC%d continuous is already initialized. To reconfigure call analogContinuousDeinit() first.", adc_unit+1); + return false; + } + + //Check sampling frequency + if((sampling_freq_hz < SOC_ADC_SAMPLE_FREQ_THRES_LOW) || (sampling_freq_hz > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)){ + log_e("Sampling frequency is out of range. Supported sampling frequencies are %d - %d", SOC_ADC_SAMPLE_FREQ_THRES_LOW, SOC_ADC_SAMPLE_FREQ_THRES_HIGH); + return false; + } + + //Set periman deinit function and reset all pins to init state. + perimanSetBusDeinit(ESP32_BUS_TYPE_ADC_CONT, adcContinuousDetachBus); + for(int j = 0; j < pins_count; j++){ + if(!perimanSetPinBus(pins[j], ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + } + + //Set conversion frame and buffer size (conversion frame must be in multiples of SOC_ADC_DIGI_DATA_BYTES_PER_CONV) + adc_handle[adc_unit].conversion_frame_size = conversions_per_pin * pins_count * SOC_ADC_DIGI_RESULT_BYTES; + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + uint8_t calc_multiple = adc_handle[adc_unit].conversion_frame_size % SOC_ADC_DIGI_DATA_BYTES_PER_CONV; + if(calc_multiple != 0){ + adc_handle[adc_unit].conversion_frame_size = (adc_handle[adc_unit].conversion_frame_size + calc_multiple); + } +#endif + + adc_handle[adc_unit].buffer_size = adc_handle[adc_unit].conversion_frame_size * 2; + + //Conversion frame size buffer cant be bigger than 4092 bytes + if(adc_handle[adc_unit].conversion_frame_size > 4092){ + log_e("Buffers are too big. Please set lower conversions per pin."); + return false; + } + + //Initialize continuous handle and pins + err = __analogContinuousInit(channel, sizeof(channel) / sizeof(adc_channel_t), adc_unit, sampling_freq_hz); + if(err != ESP_OK){ + log_e("Analog initialization failed!"); + return false; + } + + //Setup callbacks for complete event + adc_continuous_evt_cbs_t cbs = { + .on_conv_done = adcFnWrapper, + //.on_pool_ovf can be used in future + }; + adc_handle[adc_unit].adc_interrupt_handle.fn = (voidFuncPtr)userFunc; + err = adc_continuous_register_event_callbacks(adc_handle[adc_unit].adc_continuous_handle, &cbs, &adc_handle[adc_unit].adc_interrupt_handle); + if(err != ESP_OK){ + log_e("adc_continuous_register_event_callbacks failed!"); + return false; + } + + //Allocate and prepare result structure for adc readings + adc_result = malloc(pins_count * sizeof(adc_continuos_data_t)); + for(int k = 0; k < pins_count; k++){ + adc_result[k].pin = pins[k]; + adc_result[k].channel = channel[k]; + } + + //Initialize ADC calibration handle + if(adc_handle[adc_unit].adc_cali_handle == NULL){ + log_d("Creating cali handle for ADC_%d", adc_unit); + #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = adc_unit, + .atten = __adcContinuousAtten, + .bitwidth = __adcContinuousWidth, + }; + err = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #elif !defined(CONFIG_IDF_TARGET_ESP32H2) //ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + adc_cali_line_fitting_config_t cali_config = { + .unit_id = adc_unit, + .bitwidth = __adcContinuousWidth, + .atten = __adcContinuousAtten, + }; + err = adc_cali_create_scheme_line_fitting(&cali_config, &adc_handle[adc_unit].adc_cali_handle); + #endif + if(err != ESP_OK){ + log_e("adc_cali_create_scheme_x failed!"); + return false; + } + } + + for(int k = 0; k < pins_count; k++){ + if(!perimanSetPinBus(pins[k], ESP32_BUS_TYPE_ADC_CONT, (void *)(adc_unit+1))){ + log_e("perimanSetPinBus to ADC Continuous failed!"); + adcContinuousDetachBus((void *)(adc_unit+1)); + return false; + } + } + + return true; +} + +bool analogContinuousRead(adc_continuos_data_t ** buffer, uint32_t timeout_ms){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + uint32_t bytes_read = 0; + uint32_t read_raw[used_adc_channels]; + uint32_t read_count[used_adc_channels]; + uint8_t adc_read[adc_handle[ADC_UNIT_1].conversion_frame_size]; + memset(adc_read, 0xcc, sizeof(adc_read)); + memset(read_raw, 0, sizeof(read_raw)); + memset(read_count, 0, sizeof(read_count)); + + esp_err_t err = adc_continuous_read(adc_handle[ADC_UNIT_1].adc_continuous_handle, adc_read, adc_handle[0].conversion_frame_size, &bytes_read, timeout_ms); + if(err != ESP_OK){ + if(err == ESP_ERR_TIMEOUT){ + log_e("Reading data failed: No data, increase timeout"); + } + else { + log_e("Reading data failed with error: %X", err); + } + *buffer = NULL; + return false; + } + + for (int i = 0; i < bytes_read; i += SOC_ADC_DIGI_RESULT_BYTES) { + adc_digi_output_data_t *p = (adc_digi_output_data_t*)&adc_read[i]; + uint32_t chan_num = ADC_GET_CHANNEL(p); + uint32_t data = ADC_GET_DATA(p); + + /* Check the channel number validation, the data is invalid if the channel num exceed the maximum channel */ + if(chan_num >= SOC_ADC_CHANNEL_NUM(0)){ + log_e("Invalid data [%d_%d]", chan_num, data); + *buffer = NULL; + return false; + } + if(data >= (1 << SOC_ADC_DIGI_MAX_BITWIDTH)) + { + data = 0; + log_e("Invalid data"); + } + + for(int j = 0; j < used_adc_channels; j++){ + if(adc_result[j].channel == chan_num){ + read_raw[j] += data; + read_count[j] += 1; + break; + } + } + } + + for (int j = 0; j < used_adc_channels; j++){ + if (read_count[j] != 0){ + adc_result[j].avg_read_raw = read_raw[j] / read_count[j]; + adc_cali_raw_to_voltage(adc_handle[ADC_UNIT_1].adc_cali_handle, adc_result[j].avg_read_raw, &adc_result[j].avg_read_mvolts); + } + else { + log_w("No data read for pin %d", adc_result[j].pin); + } + } + + *buffer = adc_result; + return true; + + } + else { + log_e("ADC Continuous is not initialized!"); + return false; + } +} + +bool analogContinuousStart(){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + if(adc_continuous_start(adc_handle[ADC_UNIT_1].adc_continuous_handle) == ESP_OK){ + return true; + } + } else { + log_e("ADC Continuous is not initialized!"); + } + return false; +} + +bool analogContinuousStop(){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + if(adc_continuous_stop(adc_handle[ADC_UNIT_1].adc_continuous_handle) == ESP_OK){ + return true; + } + } else { + log_e("ADC Continuous is not initialized!"); + } + return false; +} + +bool analogContinuousDeinit(){ + if(adc_handle[ADC_UNIT_1].adc_continuous_handle != NULL){ + esp_err_t err = adc_continuous_deinit(adc_handle[ADC_UNIT_1].adc_continuous_handle); + if (err != ESP_OK){ + return false; + } + free(adc_result); + adc_handle[ADC_UNIT_1].adc_continuous_handle = NULL; + } else { + log_i("ADC Continuous was not initialized"); + } + return true; +} + +void analogContinuousSetAtten(adc_attenuation_t attenuation){ + __adcContinuousAtten = attenuation; +} + +void analogContinuousSetWidth(uint8_t bits){ + if ((bits < SOC_ADC_DIGI_MIN_BITWIDTH) && (bits > SOC_ADC_DIGI_MAX_BITWIDTH)){ + log_e("Selected width cannot be set. Range is from %d to %d", SOC_ADC_DIGI_MIN_BITWIDTH, SOC_ADC_DIGI_MAX_BITWIDTH); + return; + } + __adcContinuousWidth = bits; +} + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-adc.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-adc.h new file mode 100644 index 0000000..41122b2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-adc.h @@ -0,0 +1,134 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_ADC_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp32-hal.h" + +typedef enum { + ADC_0db, + ADC_2_5db, + ADC_6db, + ADC_11db, + ADC_ATTENDB_MAX +} adc_attenuation_t; + +/* + * Get ADC value for pin + * */ +uint16_t analogRead(uint8_t pin); + +/* + * Get MilliVolts value for pin + * */ +uint32_t analogReadMilliVolts(uint8_t pin); + +/* + * Set the resolution of analogRead return values. Default is 12 bits (range from 0 to 4096). + * If between 9 and 12, it will equal the set hardware resolution, else value will be shifted. + * Range is 1 - 16 + * + * Note: compatibility with Arduino SAM + */ +void analogReadResolution(uint8_t bits); + +/* + * Set the attenuation for all channels + * Default is 11db + * */ +void analogSetAttenuation(adc_attenuation_t attenuation); + +/* + * Set the attenuation for particular pin + * Default is 11db + * */ +void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation); + +#if CONFIG_IDF_TARGET_ESP32 +/* + * Sets the sample bits and read resolution + * Default is 12bit (0 - 4095) + * Range is 9 - 12 + * */ +void analogSetWidth(uint8_t bits); + +#endif + +/* + * Analog Continuous mode + * */ + +typedef struct { + uint8_t pin; /*!cb(r->arg, ev_type, old_apb, new_apb); + r=r->next; + } + else { // run backwards through chain + while(r->next != NULL) r = r->next; // find first added + while( r != NULL){ + r->cb(r->arg, ev_type, old_apb, new_apb); + r=r->prev; + } + } + } + xSemaphoreGive(apb_change_lock); +} + +bool addApbChangeCallback(void * arg, apb_change_cb_t cb){ + initApbChangeCallback(); + apb_change_t * c = (apb_change_t*)malloc(sizeof(apb_change_t)); + if(!c){ + log_e("Callback Object Malloc Failed"); + return false; + } + c->next = NULL; + c->prev = NULL; + c->arg = arg; + c->cb = cb; + xSemaphoreTake(apb_change_lock, portMAX_DELAY); + if(apb_change_callbacks == NULL){ + apb_change_callbacks = c; + } else { + apb_change_t * r = apb_change_callbacks; + // look for duplicate callbacks + while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next; + if (r) { + log_e("duplicate func=%8p arg=%8p",c->cb,c->arg); + free(c); + xSemaphoreGive(apb_change_lock); + return false; + } + else { + c->next = apb_change_callbacks; + apb_change_callbacks-> prev = c; + apb_change_callbacks = c; + } + } + xSemaphoreGive(apb_change_lock); + return true; +} + +bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){ + initApbChangeCallback(); + xSemaphoreTake(apb_change_lock, portMAX_DELAY); + apb_change_t * r = apb_change_callbacks; + // look for matching callback + while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next; + if ( r == NULL ) { + log_e("not found func=%8p arg=%8p",cb,arg); + xSemaphoreGive(apb_change_lock); + return false; + } + else { + // patch links + if(r->prev) r->prev->next = r->next; + else { // this is first link + apb_change_callbacks = r->next; + } + if(r->next) r->next->prev = r->prev; + free(r); + } + xSemaphoreGive(apb_change_lock); + return true; +} + +static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 + return APB_CLK_FREQ; +#else + if(conf->freq_mhz >= 80){ + return 80 * MHZ; + } + return (conf->source_freq_mhz * MHZ) / conf->div; +#endif +} + +void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF + +bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){ + rtc_cpu_freq_config_t conf, cconf; + uint32_t capb, apb; + //Get XTAL Frequency and calculate min CPU MHz +#ifndef CONFIG_IDF_TARGET_ESP32H2 + rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get(); +#endif +#if CONFIG_IDF_TARGET_ESP32 + if(xtal > RTC_XTAL_FREQ_AUTO){ + if(xtal < RTC_XTAL_FREQ_40M) { + if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2)){ + log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2); + return false; + } + } else if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2) && cpu_freq_mhz != (xtal/4)){ + log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4); + return false; + } + } +#endif +#ifndef CONFIG_IDF_TARGET_ESP32H2 + if(cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 80){ + if(xtal >= RTC_XTAL_FREQ_40M){ + log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4); + } else { + log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2); + } + return false; + } +#endif +#if CONFIG_IDF_TARGET_ESP32 + //check if cpu supports the frequency + if(cpu_freq_mhz == 240){ + //Check if ESP32 is rated for a CPU frequency of 160MHz only + if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) && + REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_LOW)) { + log_e("Can not switch to 240 MHz! Chip CPU frequency rated for 160MHz."); + cpu_freq_mhz = 160; + } + } +#endif + //Get current CPU clock configuration + rtc_clk_cpu_freq_get_config(&cconf); + //return if frequency has not changed + if(cconf.freq_mhz == cpu_freq_mhz){ + return true; + } + //Get configuration for the new CPU frequency + if(!rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &conf)){ + log_e("CPU clock could not be set to %u MHz", cpu_freq_mhz); + return false; + } + //Current APB + capb = calculateApb(&cconf); + //New APB + apb = calculateApb(&conf); + + //Call peripheral functions before the APB change + if(apb_change_callbacks){ + triggerApbChangeCallback(APB_BEFORE_CHANGE, capb, apb); + } + //Make the frequency change + rtc_clk_cpu_freq_set_config_fast(&conf); +#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) + if(capb != apb){ + //Update REF_TICK (uncomment if REF_TICK is different than 1MHz) + //if(conf.freq_mhz < 80){ + // ESP_REG(APB_CTRL_XTAL_TICK_CONF_REG) = conf.freq_mhz / (REF_CLK_FREQ / MHZ) - 1; + // } + //Update APB Freq REG + rtc_clk_apb_freq_update(apb); + //Update esp_timer divisor + esp_timer_impl_update_apb_freq(apb / MHZ); + } +#endif + //Update FreeRTOS Tick Divisor +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + +#elif CONFIG_IDF_TARGET_ESP32S3 + +#else + uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb); + _xt_tick_divisor = fcpu / XT_TICK_PER_SEC; +#endif + //Call peripheral functions after the APB change + if(apb_change_callbacks){ + triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb); + } +#ifdef SOC_CLK_APLL_SUPPORTED + log_d("%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL)?"PLL":((conf.source == RTC_CPU_FREQ_SRC_APLL)?"APLL":((conf.source == RTC_CPU_FREQ_SRC_XTAL)?"XTAL":"8M")), conf.source_freq_mhz, conf.div, conf.freq_mhz, apb); +#else + log_d("%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL)?"PLL":((conf.source == RTC_CPU_FREQ_SRC_XTAL)?"XTAL":"17.5M"), conf.source_freq_mhz, conf.div, conf.freq_mhz, apb); +#endif + return true; +} + +uint32_t getCpuFrequencyMhz(){ + rtc_cpu_freq_config_t conf; + rtc_clk_cpu_freq_get_config(&conf); + return conf.freq_mhz; +} + +uint32_t getXtalFrequencyMhz(){ + return rtc_clk_xtal_freq_get(); +} + +uint32_t getApbFrequency(){ + rtc_cpu_freq_config_t conf; + rtc_clk_cpu_freq_get_config(&conf); + return calculateApb(&conf); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-cpu.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-cpu.h new file mode 100644 index 0000000..646b598 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-cpu.h @@ -0,0 +1,48 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP32_HAL_CPU_H_ +#define _ESP32_HAL_CPU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +typedef enum { APB_BEFORE_CHANGE, APB_AFTER_CHANGE } apb_change_ev_t; + +typedef void (* apb_change_cb_t)(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb); + +bool addApbChangeCallback(void * arg, apb_change_cb_t cb); +bool removeApbChangeCallback(void * arg, apb_change_cb_t cb); + +//function takes the following frequencies as valid values: +// 240, 160, 80 <<< For all XTAL types +// 40, 20, 10 <<< For 40MHz XTAL +// 26, 13 <<< For 26MHz XTAL +// 24, 12 <<< For 24MHz XTAL +bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz); + +uint32_t getCpuFrequencyMhz(); // In MHz +uint32_t getXtalFrequencyMhz(); // In MHz +uint32_t getApbFrequency(); // In Hz + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP32_HAL_CPU_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-dac.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-dac.c new file mode 100644 index 0000000..2bf2c23 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-dac.c @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32-hal-dac.h" + +#if SOC_DAC_SUPPORTED +#include "esp32-hal.h" +#include "esp32-hal-periman.h" +#include "soc/dac_channel.h" +#include "driver/dac_oneshot.h" + +static bool dacDetachBus(void * bus){ + esp_err_t err = dac_oneshot_del_channel((dac_oneshot_handle_t)bus); + if(err != ESP_OK){ + log_e("dac_oneshot_del_channel failed with error: %d", err); + return false; + } + return true; +} + +bool __dacWrite(uint8_t pin, uint8_t value) +{ + esp_err_t err = ESP_OK; + if(pin != DAC_CHAN0_GPIO_NUM && pin != DAC_CHAN1_GPIO_NUM){ + log_e("pin %u is not a DAC pin", pin); + return false;//not dac pin + } + + dac_oneshot_handle_t bus = (dac_oneshot_handle_t)perimanGetPinBus(pin, ESP32_BUS_TYPE_DAC_ONESHOT); + if(bus == NULL){ + perimanSetBusDeinit(ESP32_BUS_TYPE_DAC_ONESHOT, dacDetachBus); + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + dac_channel_t channel = (pin == DAC_CHAN0_GPIO_NUM)?DAC_CHAN_0:DAC_CHAN_1; + dac_oneshot_config_t config = { + .chan_id = channel + }; + err = dac_oneshot_new_channel(&config, &bus); + if(err != ESP_OK){ + log_e("dac_oneshot_new_channel failed with error: %d", err); + return false; + } + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_DAC_ONESHOT, (void *)bus)){ + dacDetachBus((void *)bus); + return false; + } + } + + err = dac_oneshot_output_voltage(bus, value); + if(err != ESP_OK){ + log_e("dac_oneshot_output_voltage failed with error: %d", err); + return false; + } + return true; +} + +bool __dacDisable(uint8_t pin) +{ + if(pin != DAC_CHAN0_GPIO_NUM && pin != DAC_CHAN1_GPIO_NUM){ + log_e("pin %u is not a DAC pin", pin); + return false;//not dac pin + } + void * bus = perimanGetPinBus(pin, ESP32_BUS_TYPE_DAC_ONESHOT); + if(bus != NULL){ + // will call dacDetachBus + return perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL); + } else { + log_e("pin %u is not attached to DAC", pin); + } + return false; +} + +extern bool dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite"))); +extern bool dacDisable(uint8_t pin) __attribute__ ((weak, alias("__dacDisable"))); + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-dac.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-dac.h new file mode 100644 index 0000000..113354b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-dac.h @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_DAC_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +bool dacWrite(uint8_t pin, uint8_t value); +bool dacDisable(uint8_t pin); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_DAC_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-gpio.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-gpio.c new file mode 100644 index 0000000..3888a38 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-gpio.c @@ -0,0 +1,265 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-gpio.h" +#include "esp32-hal-periman.h" +#include "hal/gpio_hal.h" +#include "soc/soc_caps.h" + +// It fixes lack of pin definition for S3 and for any future SoC +// this function works for ESP32, ESP32-S2 and ESP32-S3 - including the C3, it will return -1 for any pin +#if SOC_TOUCH_SENSOR_NUM > 0 +#include "soc/touch_sensor_periph.h" + +int8_t digitalPinToTouchChannel(uint8_t pin) +{ + int8_t ret = -1; + if (pin < SOC_GPIO_PIN_COUNT) { + for (uint8_t i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) { + if (touch_sensor_channel_io_map[i] == pin) { + ret = i; + break; + } + } + } + return ret; +} +#else +// No Touch Sensor available +int8_t digitalPinToTouchChannel(uint8_t pin) +{ + return -1; +} +#endif + +#ifdef SOC_ADC_SUPPORTED +#include "soc/adc_periph.h" + +int8_t digitalPinToAnalogChannel(uint8_t pin) +{ + uint8_t channel = 0; + if (pin < SOC_GPIO_PIN_COUNT) { + for (uint8_t i = 0; i < SOC_ADC_PERIPH_NUM; i++) { + for (uint8_t j = 0; j < SOC_ADC_MAX_CHANNEL_NUM; j++) { + if (adc_channel_io_map[i][j] == pin) { + return channel; + } + channel++; + } + } + } + return -1; +} + +int8_t analogChannelToDigitalPin(uint8_t channel) +{ + if (channel >= (SOC_ADC_PERIPH_NUM * SOC_ADC_MAX_CHANNEL_NUM)) { + return -1; + } + uint8_t adc_unit = (channel / SOC_ADC_MAX_CHANNEL_NUM); + uint8_t adc_chan = (channel % SOC_ADC_MAX_CHANNEL_NUM); + return adc_channel_io_map[adc_unit][adc_chan]; +} +#else +// No Analog channels availible +int8_t analogChannelToDigitalPin(uint8_t channel) +{ + return -1; +} +#endif + +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); +typedef struct { + voidFuncPtr fn; + void* arg; + bool functional; +} InterruptHandle_t; +static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,}; + +#include "driver/rtc_io.h" + +static bool gpioDetachBus(void * bus){ + return true; +} + +extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode) +{ +#ifdef RGB_BUILTIN + if (pin == RGB_BUILTIN){ + __pinMode(RGB_BUILTIN-SOC_GPIO_PIN_COUNT, mode); + return; + } +#endif + + if (pin >= SOC_GPIO_PIN_COUNT) { + log_e("Invalid pin selected"); + return; + } + + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) == NULL){ + perimanSetBusDeinit(ESP32_BUS_TYPE_GPIO, gpioDetachBus); + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)){ + log_e("Deinit of previous bus failed"); + return; + } + } + + gpio_hal_context_t gpiohal; + gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); + + gpio_config_t conf = { + .pin_bit_mask = (1ULL<pin[pin].int_type /*!< GPIO interrupt type - previously set */ + }; + if (mode < 0x20) {//io + conf.mode = mode & (INPUT | OUTPUT); + if (mode & OPEN_DRAIN) { + conf.mode |= GPIO_MODE_DEF_OD; + } + if (mode & PULLUP) { + conf.pull_up_en = GPIO_PULLUP_ENABLE; + } + if (mode & PULLDOWN) { + conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + } + } + if(gpio_config(&conf) != ESP_OK) + { + log_e("GPIO config failed"); + return; + } + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) == NULL){ + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_GPIO, (void *)(pin+1))){ + //gpioDetachBus((void *)(pin+1)); + return; + } + } +} + +extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val) +{ + #ifdef RGB_BUILTIN + if(pin == RGB_BUILTIN){ + //use RMT to set all channels on/off + const uint8_t comm_val = val != 0 ? RGB_BRIGHTNESS : 0; + neopixelWrite(RGB_BUILTIN, comm_val, comm_val, comm_val); + return; + } + #endif + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) != NULL){ + gpio_set_level((gpio_num_t)pin, val); + } else { + log_e("Pin is not set as GPIO."); + } +} + +extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) +{ + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_GPIO) != NULL){ + return gpio_get_level((gpio_num_t)pin); + } + else { + log_e("Pin is not set as GPIO."); + return 0; + } +} + +static void ARDUINO_ISR_ATTR __onPinInterrupt(void * arg) { + InterruptHandle_t * isr = (InterruptHandle_t*)arg; + if(isr->fn) { + if(isr->arg){ + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } + } +} + +extern void cleanupFunctional(void* arg); + +extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional) +{ + static bool interrupt_initialized = false; + + // makes sure that pin -1 (255) will never work -- this follows Arduino standard + if (pin >= SOC_GPIO_PIN_COUNT) return; + + if(!interrupt_initialized) { + esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG); + interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE); + } + if(!interrupt_initialized) { + log_e("GPIO ISR Service Failed To Start"); + return; + } + + // if new attach without detach remove old info + if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) + { + cleanupFunctional(__pinInterruptHandlers[pin].arg); + } + __pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc; + __pinInterruptHandlers[pin].arg = arg; + __pinInterruptHandlers[pin].functional = functional; + + gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); + if(intr_type & 0x8){ + gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); + } + gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]); + + + //FIX interrupts on peripherals outputs (eg. LEDC,...) + //Enable input in GPIO register + gpio_hal_context_t gpiohal; + gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); + gpio_hal_input_enable(&gpiohal, pin); +} + +extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type) +{ + __attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false); +} + +extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) { + __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false); +} + +extern void __detachInterrupt(uint8_t pin) +{ + gpio_isr_handler_remove((gpio_num_t)pin); //remove handle and disable isr for pin + gpio_wakeup_disable((gpio_num_t)pin); + + if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) + { + cleanupFunctional(__pinInterruptHandlers[pin].arg); + } + __pinInterruptHandlers[pin].fn = NULL; + __pinInterruptHandlers[pin].arg = NULL; + __pinInterruptHandlers[pin].functional = false; + + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); +} + + +extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); +extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); +extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"))); +extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); +extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg"))); +extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-gpio.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-gpio.h new file mode 100644 index 0000000..69b5517 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-gpio.h @@ -0,0 +1,90 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MAIN_ESP32_HAL_GPIO_H_ +#define MAIN_ESP32_HAL_GPIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp32-hal.h" +#include "soc/soc_caps.h" +#include "pins_arduino.h" + +#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) +#define NUM_OUPUT_PINS 46 +#define PIN_DAC1 17 +#define PIN_DAC2 18 +#else +#define NUM_OUPUT_PINS 34 +#define PIN_DAC1 25 +#define PIN_DAC2 26 +#endif + +#define LOW 0x0 +#define HIGH 0x1 + +//GPIO FUNCTIONS +#define INPUT 0x01 +// Changed OUTPUT from 0x02 to behave the same as Arduino pinMode(pin,OUTPUT) +// where you can read the state of pin even when it is set as OUTPUT +#define OUTPUT 0x03 +#define PULLUP 0x04 +#define INPUT_PULLUP 0x05 +#define PULLDOWN 0x08 +#define INPUT_PULLDOWN 0x09 +#define OPEN_DRAIN 0x10 +#define OUTPUT_OPEN_DRAIN 0x13 +#define ANALOG 0xC0 + +//Interrupt Modes +#define DISABLED 0x00 +#define RISING 0x01 +#define FALLING 0x02 +#define CHANGE 0x03 +#define ONLOW 0x04 +#define ONHIGH 0x05 +#define ONLOW_WE 0x0C +#define ONHIGH_WE 0x0D + + +#define digitalPinIsValid(pin) GPIO_IS_VALID_GPIO(pin) +#define digitalPinCanOutput(pin) GPIO_IS_VALID_OUTPUT_GPIO(pin) + +#define digitalPinToRtcPin(pin) ((RTC_GPIO_IS_VALID_GPIO(pin))?rtc_io_number_get(pin):-1) +#define digitalPinToDacChannel(pin) (((pin) == DAC_CHANNEL_1_GPIO_NUM)?0:((pin) == DAC_CHANNEL_2_GPIO_NUM)?1:-1) + +void pinMode(uint8_t pin, uint8_t mode); +void digitalWrite(uint8_t pin, uint8_t val); +int digitalRead(uint8_t pin); + +void attachInterrupt(uint8_t pin, void (*)(void), int mode); +void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode); +void detachInterrupt(uint8_t pin); + +int8_t digitalPinToTouchChannel(uint8_t pin); +int8_t digitalPinToAnalogChannel(uint8_t pin); +int8_t analogChannelToDigitalPin(uint8_t channel); + +#ifdef __cplusplus +} +#endif + +#endif /* MAIN_ESP32_HAL_GPIO_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c-slave.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c-slave.c new file mode 100644 index 0000000..10629e4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c-slave.c @@ -0,0 +1,881 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/soc_caps.h" + +#if SOC_I2C_SUPPORT_SLAVE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sdkconfig.h" +#include "esp_attr.h" +#include "rom/gpio.h" +#include "soc/gpio_sig_map.h" +#include "hal/gpio_types.h" +#include "driver/gpio.h" +#include "esp_err.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/ringbuf.h" + +#include "esp_intr_alloc.h" +#include "soc/i2c_reg.h" +#include "soc/i2c_struct.h" +#include "hal/i2c_ll.h" +#include "hal/clk_gate_ll.h" +#include "esp32-hal-log.h" +#include "esp32-hal-i2c-slave.h" +#include "esp32-hal-periman.h" + +#define I2C_SLAVE_USE_RX_QUEUE 0 // 1: Queue, 0: RingBuffer + +#if SOC_I2C_NUM > 1 +#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0)) +#define I2C_SDA_IDX(p) ((p==0)?I2CEXT0_SDA_OUT_IDX:((p==1)?I2CEXT1_SDA_OUT_IDX:0)) +#else +#define I2C_SCL_IDX(p) I2CEXT0_SCL_OUT_IDX +#define I2C_SDA_IDX(p) I2CEXT0_SDA_OUT_IDX +#endif + +#if CONFIG_IDF_TARGET_ESP32 + #define I2C_TXFIFO_WM_INT_ENA I2C_TXFIFO_EMPTY_INT_ENA + #define I2C_RXFIFO_WM_INT_ENA I2C_RXFIFO_FULL_INT_ENA +#endif + +enum { + I2C_SLAVE_EVT_RX, I2C_SLAVE_EVT_TX +}; + +typedef struct i2c_slave_struct_t { + i2c_dev_t * dev; + uint8_t num; + int8_t sda; + int8_t scl; + i2c_slave_request_cb_t request_callback; + i2c_slave_receive_cb_t receive_callback; + void * arg; + intr_handle_t intr_handle; + TaskHandle_t task_handle; + QueueHandle_t event_queue; +#if I2C_SLAVE_USE_RX_QUEUE + QueueHandle_t rx_queue; +#else + RingbufHandle_t rx_ring_buf; +#endif + QueueHandle_t tx_queue; + uint32_t rx_data_count; +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t lock; +#endif +} i2c_slave_struct_t; + +typedef union { + struct { + uint32_t event : 2; + uint32_t stop : 1; + uint32_t param : 29; + }; + uint32_t val; +} i2c_slave_queue_event_t; + +static i2c_slave_struct_t _i2c_bus_array[SOC_I2C_NUM] = { + { &I2C0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 +#if !CONFIG_DISABLE_HAL_LOCKS + , NULL +#endif + }, +#if SOC_I2C_NUM > 1 + { &I2C1, 1, -1, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 +#if !CONFIG_DISABLE_HAL_LOCKS + , NULL +#endif + } +#endif +}; + +#if CONFIG_DISABLE_HAL_LOCKS +#define I2C_SLAVE_MUTEX_LOCK() +#define I2C_SLAVE_MUTEX_UNLOCK() +#else +#define I2C_SLAVE_MUTEX_LOCK() if(i2c->lock){xSemaphoreTake(i2c->lock, portMAX_DELAY);} +#define I2C_SLAVE_MUTEX_UNLOCK() if(i2c->lock){xSemaphoreGive(i2c->lock);} +#endif + +//-------------------------------------- HAL_LL (Missing Functions) ------------------------------------------------ +typedef enum { + I2C_STRETCH_CAUSE_MASTER_READ, + I2C_STRETCH_CAUSE_TX_FIFO_EMPTY, + I2C_STRETCH_CAUSE_RX_FIFO_FULL, + I2C_STRETCH_CAUSE_MAX +} i2c_stretch_cause_t; + +static inline i2c_stretch_cause_t i2c_ll_stretch_cause(i2c_dev_t *hw) +{ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + return hw->sr.stretch_cause; +#elif CONFIG_IDF_TARGET_ESP32S2 + return hw->status_reg.stretch_cause; +#else + return I2C_STRETCH_CAUSE_MAX; +#endif +} + +static inline void i2c_ll_set_stretch(i2c_dev_t *hw, uint16_t time) +{ +#ifndef CONFIG_IDF_TARGET_ESP32 + typeof(hw->scl_stretch_conf) scl_stretch_conf; + scl_stretch_conf.val = 0; + scl_stretch_conf.slave_scl_stretch_en = (time > 0); + scl_stretch_conf.stretch_protect_num = time; + scl_stretch_conf.slave_scl_stretch_clr = 1; + hw->scl_stretch_conf.val = scl_stretch_conf.val; + if(time > 0){ + //enable interrupt + hw->int_ena.val |= I2C_SLAVE_STRETCH_INT_ENA; + } else { + //disable interrupt + hw->int_ena.val &= (~I2C_SLAVE_STRETCH_INT_ENA); + } +#endif +} + +static inline void i2c_ll_stretch_clr(i2c_dev_t *hw) +{ +#ifndef CONFIG_IDF_TARGET_ESP32 + hw->scl_stretch_conf.slave_scl_stretch_clr = 1; +#endif +} + +static inline bool i2c_ll_slave_addressed(i2c_dev_t *hw) +{ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 + return hw->sr.slave_addressed; +#else + return hw->status_reg.slave_addressed; +#endif +} + +static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)//not exposed by hal_ll +{ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 + return hw->sr.slave_rw; +#else + return hw->status_reg.slave_rw; +#endif +} + +//-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------ +static void i2c_slave_free_resources(i2c_slave_struct_t * i2c); +static void i2c_slave_delay_us(uint64_t us); +static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode); +static bool i2c_slave_check_line_state(int8_t sda, int8_t scl); +static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl); +static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c); +static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed); +static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event); +static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c); +static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len); +static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len); +static void i2c_slave_isr_handler(void* arg); +static void i2c_slave_task(void *pv_args); +static bool i2cSlaveDetachBus(void * bus_i2c_num); + +//===================================================================================================================== +//-------------------------------------- Public Functions ------------------------------------------------------------- +//===================================================================================================================== + +esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg){ + if(num >= SOC_I2C_NUM){ + log_e("Invalid port num: %u", num); + return ESP_ERR_INVALID_ARG; + } + i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; + I2C_SLAVE_MUTEX_LOCK(); + i2c->request_callback = request_callback; + i2c->receive_callback = receive_callback; + i2c->arg = arg; + I2C_SLAVE_MUTEX_UNLOCK(); + return ESP_OK; +} + +esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) { + if(num >= SOC_I2C_NUM){ + log_e("Invalid port num: %u", num); + return ESP_ERR_INVALID_ARG; + } + + if (sda < 0 || scl < 0) { + log_e("invalid pins sda=%d, scl=%d", sda, scl); + return ESP_ERR_INVALID_ARG; + } + + if(!frequency){ + frequency = 100000; + } else if(frequency > 1000000){ + frequency = 1000000; + } + + perimanSetBusDeinit(ESP32_BUS_TYPE_I2C_SLAVE, i2cSlaveDetachBus); + if(!perimanSetPinBus(sda, ESP32_BUS_TYPE_INIT, NULL) || !perimanSetPinBus(scl, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + + log_i("Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x", sda, scl, frequency, slaveID); + + i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; + esp_err_t ret = ESP_OK; + +#if !CONFIG_DISABLE_HAL_LOCKS + if(!i2c->lock){ + i2c->lock = xSemaphoreCreateMutex(); + if (i2c->lock == NULL) { + log_e("RX queue create failed"); + return ESP_ERR_NO_MEM; + } + } +#endif + + I2C_SLAVE_MUTEX_LOCK(); + i2c_slave_free_resources(i2c); + +#if I2C_SLAVE_USE_RX_QUEUE + i2c->rx_queue = xQueueCreate(rx_len, sizeof(uint8_t)); + if (i2c->rx_queue == NULL) { + log_e("RX queue create failed"); + ret = ESP_ERR_NO_MEM; + goto fail; + } +#else + i2c->rx_ring_buf = xRingbufferCreate(rx_len, RINGBUF_TYPE_BYTEBUF); + if (i2c->rx_ring_buf == NULL) { + log_e("RX RingBuf create failed"); + ret = ESP_ERR_NO_MEM; + goto fail; + } +#endif + + i2c->tx_queue = xQueueCreate(tx_len, sizeof(uint8_t)); + if (i2c->tx_queue == NULL) { + log_e("TX queue create failed"); + ret = ESP_ERR_NO_MEM; + goto fail; + } + + i2c->event_queue = xQueueCreate(16, sizeof(i2c_slave_queue_event_t)); + if (i2c->event_queue == NULL) { + log_e("Event queue create failed"); + ret = ESP_ERR_NO_MEM; + goto fail; + } + + xTaskCreate(i2c_slave_task, "i2c_slave_task", 4096, i2c, 20, &i2c->task_handle); + if(i2c->task_handle == NULL){ + log_e("Event thread create failed"); + ret = ESP_ERR_NO_MEM; + goto fail; + } + + if (frequency == 0) { + frequency = 100000L; + } + frequency = (frequency * 5) / 4; + + if (i2c->num == 0) { + periph_ll_enable_clk_clear_rst(PERIPH_I2C0_MODULE); +#if SOC_I2C_NUM > 1 + } else { + periph_ll_enable_clk_clear_rst(PERIPH_I2C1_MODULE); +#endif + } + + i2c_ll_slave_init(i2c->dev); + i2c_ll_set_fifo_mode(i2c->dev, true); + i2c_ll_set_slave_addr(i2c->dev, slaveID, false); + i2c_ll_set_tout(i2c->dev, I2C_LL_MAX_TIMEOUT); + i2c_slave_set_frequency(i2c, frequency); + + if (!i2c_slave_check_line_state(sda, scl)) { + log_e("bad pin state"); + ret = ESP_FAIL; + goto fail; + } + + i2c_slave_attach_gpio(i2c, sda, scl); + + if (i2c_ll_is_bus_busy(i2c->dev)) { + log_w("Bus busy, reinit"); + ret = ESP_FAIL; + goto fail; + } + + i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + i2c_ll_set_fifo_mode(i2c->dev, true); + + if (!i2c->intr_handle) { + uint32_t flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED; + if(i2c->num == 0) { + ret = esp_intr_alloc(ETS_I2C_EXT0_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#if SOC_I2C_NUM > 1 + } else { + ret = esp_intr_alloc(ETS_I2C_EXT1_INTR_SOURCE, flags, &i2c_slave_isr_handler, i2c, &i2c->intr_handle); +#endif + } + + if (ret != ESP_OK) { + log_e("install interrupt handler Failed=%d", ret); + goto fail; + } + } + + i2c_ll_txfifo_rst(i2c->dev); + i2c_ll_rxfifo_rst(i2c->dev); + i2c_ll_slave_enable_rx_it(i2c->dev); + i2c_ll_set_stretch(i2c->dev, 0x3FF); + i2c_ll_update(i2c->dev); + if(!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_SLAVE, (void *)(i2c->num+1)) || !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_SLAVE, (void *)(i2c->num+1))){ + i2cSlaveDetachBus((void *)(i2c->num+1)); + ret = ESP_FAIL; + } + I2C_SLAVE_MUTEX_UNLOCK(); + return ret; + +fail: + i2c_slave_free_resources(i2c); + I2C_SLAVE_MUTEX_UNLOCK(); + return ret; +} + +esp_err_t i2cSlaveDeinit(uint8_t num){ + if(num >= SOC_I2C_NUM){ + log_e("Invalid port num: %u", num); + return ESP_ERR_INVALID_ARG; + } + + i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; +#if !CONFIG_DISABLE_HAL_LOCKS + if(!i2c->lock){ + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } +#endif + I2C_SLAVE_MUTEX_LOCK(); + int scl = i2c->scl; + int sda = i2c->sda; + i2c_slave_free_resources(i2c); + perimanSetPinBus(scl, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(sda, ESP32_BUS_TYPE_INIT, NULL); + I2C_SLAVE_MUTEX_UNLOCK(); + return ESP_OK; +} + +size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { + if(num >= SOC_I2C_NUM){ + log_e("Invalid port num: %u", num); + return 0; + } + uint32_t to_queue = 0, to_fifo = 0; + i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; +#if !CONFIG_DISABLE_HAL_LOCKS + if(!i2c->lock){ + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } +#endif + if(!i2c->tx_queue){ + return 0; + } + I2C_SLAVE_MUTEX_LOCK(); +#if CONFIG_IDF_TARGET_ESP32 + i2c_ll_slave_disable_tx_it(i2c->dev); + uint32_t txfifo_len = 0; + i2c_ll_get_txfifo_len(i2c->dev, &txfifo_len); + if (txfifo_len < SOC_I2C_FIFO_LEN) { + i2c_ll_txfifo_rst(i2c->dev); + } +#endif + i2c_ll_get_txfifo_len(i2c->dev, &to_fifo); + if(to_fifo){ + if(len < to_fifo){ + to_fifo = len; + } + i2c_ll_write_txfifo(i2c->dev, (uint8_t*)buf, to_fifo); + buf += to_fifo; + len -= to_fifo; + //reset tx_queue + xQueueReset(i2c->tx_queue); + //write the rest of the bytes to the queue + if(len){ + to_queue = uxQueueSpacesAvailable(i2c->tx_queue); + if(len < to_queue){ + to_queue = len; + } + for (size_t i = 0; i < to_queue; i++) { + if (xQueueSend(i2c->tx_queue, &buf[i], timeout_ms / portTICK_PERIOD_MS) != pdTRUE) { + xQueueReset(i2c->tx_queue); + to_queue = 0; + break; + } + } + //no need to enable TX_EMPTY if tx_queue is empty + if(to_queue){ + i2c_ll_slave_enable_tx_it(i2c->dev); + } + } + } + I2C_SLAVE_MUTEX_UNLOCK(); + return to_queue + to_fifo; +} + +//===================================================================================================================== +//-------------------------------------- Private Functions ------------------------------------------------------------ +//===================================================================================================================== + +static void i2c_slave_free_resources(i2c_slave_struct_t * i2c){ + i2c_slave_detach_gpio(i2c); + i2c_ll_set_slave_addr(i2c->dev, 0, false); + i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + i2c_ll_clear_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + + if (i2c->intr_handle) { + esp_intr_free(i2c->intr_handle); + i2c->intr_handle = NULL; + } + + if(i2c->task_handle){ + vTaskDelete(i2c->task_handle); + i2c->task_handle = NULL; + } + +#if I2C_SLAVE_USE_RX_QUEUE + if (i2c->rx_queue) { + vQueueDelete(i2c->rx_queue); + i2c->rx_queue = NULL; + } +#else + if (i2c->rx_ring_buf) { + vRingbufferDelete(i2c->rx_ring_buf); + i2c->rx_ring_buf = NULL; + } +#endif + + if (i2c->tx_queue) { + vQueueDelete(i2c->tx_queue); + i2c->tx_queue = NULL; + } + + if (i2c->event_queue) { + vQueueDelete(i2c->event_queue); + i2c->event_queue = NULL; + } + + i2c->rx_data_count = 0; +} + +static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed) +{ + if (i2c == NULL) { + log_e("no control buffer"); + return false; + } + if(clk_speed > 1100000UL){ + clk_speed = 1100000UL; + } + + // Adjust Fifo thresholds based on frequency + uint32_t a = (clk_speed / 50000L) + 2; + log_d("Fifo thresholds: rx_fifo_full = %d, tx_fifo_empty = %d", SOC_I2C_FIFO_LEN - a, a); + + i2c_hal_clk_config_t clk_cal; +#if SOC_I2C_SUPPORT_APB + i2c_ll_cal_bus_clk(APB_CLK_FREQ, clk_speed, &clk_cal); + i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_APB); /*!< I2C source clock from APB, 80M*/ +#elif SOC_I2C_SUPPORT_XTAL + i2c_ll_cal_bus_clk(XTAL_CLK_FREQ, clk_speed, &clk_cal); + i2c_ll_set_source_clk(i2c->dev, SOC_MOD_CLK_XTAL); /*!< I2C source clock from XTAL, 40M */ +#endif + i2c_ll_set_txfifo_empty_thr(i2c->dev, a); + i2c_ll_set_rxfifo_full_thr(i2c->dev, SOC_I2C_FIFO_LEN - a); + i2c_ll_set_bus_timing(i2c->dev, &clk_cal); + i2c_ll_set_filter(i2c->dev, 3); + return true; +} + +static void i2c_slave_delay_us(uint64_t us) +{ + uint64_t m = esp_timer_get_time(); + if (us) { + uint64_t e = (m + us); + if (m > e) { //overflow + while ((uint64_t)esp_timer_get_time() > e); + } + while ((uint64_t)esp_timer_get_time() < e); + } +} + +static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode) +{ + gpio_config_t conf = { + .pin_bit_mask = 1LL << pin, + .mode = mode, + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE + }; + gpio_config(&conf); +} + +static bool i2c_slave_check_line_state(int8_t sda, int8_t scl) +{ + if (sda < 0 || scl < 0) { + return false;//return false since there is nothing to do + } + // if the bus is not 'clear' try the cycling SCL until SDA goes High or 9 cycles + gpio_set_level(sda, 1); + gpio_set_level(scl, 1); + i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); + i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT | GPIO_MODE_DEF_OD); + gpio_set_level(scl, 1); + + if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state + log_w("invalid state sda(%d)=%d, scl(%d)=%d", sda, gpio_get_level(sda), scl, gpio_get_level(scl)); + for (uint8_t a=0; a<9; a++) { + i2c_slave_delay_us(5); + if (gpio_get_level(sda) && gpio_get_level(scl)) { // bus recovered + log_w("Recovered after %d Cycles",a); + gpio_set_level(sda,0); // start + i2c_slave_delay_us(5); + for (uint8_t a=0;a<9; a++) { + gpio_set_level(scl,1); + i2c_slave_delay_us(5); + gpio_set_level(scl,0); + i2c_slave_delay_us(5); + } + gpio_set_level(scl,1); + i2c_slave_delay_us(5); + gpio_set_level(sda,1); // stop + break; + } + gpio_set_level(scl, 0); + i2c_slave_delay_us(5); + gpio_set_level(scl, 1); + } + } + + if (!gpio_get_level(sda) || !gpio_get_level(scl)) { // bus in busy state + log_e("Bus Invalid State, Can't init sda=%d, scl=%d",gpio_get_level(sda),gpio_get_level(scl)); + return false; // bus is busy + } + return true; +} + +static bool i2c_slave_attach_gpio(i2c_slave_struct_t * i2c, int8_t sda, int8_t scl) +{ + if (i2c == NULL) { + log_e("no control block"); + return false; + } + + if ((sda < 0)||( scl < 0)) { + log_e("bad pins sda=%d, scl=%d",sda,scl); + return false; + } + + i2c->scl = scl; + gpio_set_level(scl, 1); + i2c_slave_gpio_mode(scl, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_matrix_out(scl, I2C_SCL_IDX(i2c->num), false, false); + gpio_matrix_in(scl, I2C_SCL_IDX(i2c->num), false); + + i2c->sda = sda; + gpio_set_level(sda, 1); + i2c_slave_gpio_mode(sda, GPIO_MODE_INPUT_OUTPUT_OD); + gpio_matrix_out(sda, I2C_SDA_IDX(i2c->num), false, false); + gpio_matrix_in(sda, I2C_SDA_IDX(i2c->num), false); + + return true; +} + +static bool i2c_slave_detach_gpio(i2c_slave_struct_t * i2c) +{ + if (i2c == NULL) { + log_e("no control Block"); + return false; + } + if (i2c->scl >= 0) { + gpio_matrix_out(i2c->scl, 0x100, false, false); + gpio_matrix_in(0x30, I2C_SCL_IDX(i2c->num), false); + i2c_slave_gpio_mode(i2c->scl, GPIO_MODE_INPUT); + i2c->scl = -1; // un attached + } + if (i2c->sda >= 0) { + gpio_matrix_out(i2c->sda, 0x100, false, false); + gpio_matrix_in(0x30, I2C_SDA_IDX(i2c->num), false); + i2c_slave_gpio_mode(i2c->sda, GPIO_MODE_INPUT); + i2c->sda = -1; // un attached + } + return true; +} + +static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event_t* event) +{ + bool pxHigherPriorityTaskWoken = false; + if(i2c->event_queue) { + if(xQueueSendFromISR(i2c->event_queue, event, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ + //log_e("event_queue_full"); + } + } + return pxHigherPriorityTaskWoken; +} + +static bool i2c_slave_handle_tx_fifo_empty(i2c_slave_struct_t * i2c) +{ + bool pxHigherPriorityTaskWoken = false; + uint32_t d = 0, moveCnt = 0; + i2c_ll_get_txfifo_len(i2c->dev, &moveCnt); + while (moveCnt > 0) { // read tx queue until Fifo is full or queue is empty + if(xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE){ + i2c_ll_write_txfifo(i2c->dev, (uint8_t*)&d, 1); + moveCnt--; + } else { + i2c_ll_slave_disable_tx_it(i2c->dev); + break; + } + } + return pxHigherPriorityTaskWoken; +} + +static bool i2c_slave_handle_rx_fifo_full(i2c_slave_struct_t * i2c, uint32_t len) +{ +#if I2C_SLAVE_USE_RX_QUEUE + uint32_t d = 0; +#else + uint8_t data[SOC_I2C_FIFO_LEN]; +#endif + bool pxHigherPriorityTaskWoken = false; +#if I2C_SLAVE_USE_RX_QUEUE + while (len > 0) { + i2c_ll_read_rxfifo(i2c->dev, (uint8_t*)&d, 1); + if(xQueueSendFromISR(i2c->rx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ + log_e("rx_queue_full"); + } else { + i2c->rx_data_count++; + } + if (--len == 0) { + len = i2c_ll_get_rxfifo_cnt(i2c->dev); + } +#else + if(len){ + i2c_ll_read_rxfifo(i2c->dev, data, len); + if(xRingbufferSendFromISR(i2c->rx_ring_buf, (void*) data, len, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ + log_e("rx_ring_buf_full"); + } else { + i2c->rx_data_count += len; + } +#endif + } + return pxHigherPriorityTaskWoken; +} + +static void i2c_slave_isr_handler(void* arg) +{ + bool pxHigherPriorityTaskWoken = false; + i2c_slave_struct_t * i2c = (i2c_slave_struct_t *) arg; // recover data + + uint32_t activeInt = 0; + i2c_ll_get_intr_mask(i2c->dev, &activeInt); + i2c_ll_clear_intr_mask(i2c->dev, activeInt); + uint32_t rx_fifo_len = 0; + i2c_ll_get_rxfifo_cnt(i2c->dev, &rx_fifo_len); + bool slave_rw = i2c_ll_slave_rw(i2c->dev); + + if(activeInt & I2C_RXFIFO_WM_INT_ENA){ // RX FiFo Full + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + i2c_ll_slave_enable_rx_it(i2c->dev);//is this necessary? + } + + if(activeInt & I2C_TRANS_COMPLETE_INT_ENA){ // STOP + if(rx_fifo_len){ //READ RX FIFO + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + } + if(i2c->rx_data_count){ //WRITE or RepeatedStart + //SEND RX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_RX; + event.stop = !slave_rw; + event.param = i2c->rx_data_count; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + //Zero RX count + i2c->rx_data_count = 0; + } + if(slave_rw){ // READ +#if CONFIG_IDF_TARGET_ESP32 + if(i2c->dev->status_reg.scl_main_state_last == 6){ + //SEND TX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_TX; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + } +#else + //reset TX data + i2c_ll_txfifo_rst(i2c->dev); + uint8_t d; + while (xQueueReceiveFromISR(i2c->tx_queue, &d, (BaseType_t * const)&pxHigherPriorityTaskWoken) == pdTRUE) ;//flush partial write +#endif + } + } + +#ifndef CONFIG_IDF_TARGET_ESP32 + if(activeInt & I2C_SLAVE_STRETCH_INT_ENA){ // STRETCH + i2c_stretch_cause_t cause = i2c_ll_stretch_cause(i2c->dev); + if(cause == I2C_STRETCH_CAUSE_MASTER_READ){ + //on C3 RX data dissapears with repeated start, so we need to get it here + if(rx_fifo_len){ + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + } + //SEND TX Event + i2c_slave_queue_event_t event; + event.event = I2C_SLAVE_EVT_TX; + pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event); + //will clear after execution + } else if(cause == I2C_STRETCH_CAUSE_TX_FIFO_EMPTY){ + pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); + i2c_ll_stretch_clr(i2c->dev); + } else if(cause == I2C_STRETCH_CAUSE_RX_FIFO_FULL){ + pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); + i2c_ll_stretch_clr(i2c->dev); + } + } +#endif + + if(activeInt & I2C_TXFIFO_WM_INT_ENA){ // TX FiFo Empty + pxHigherPriorityTaskWoken |= i2c_slave_handle_tx_fifo_empty(i2c); + } + + if(pxHigherPriorityTaskWoken){ + portYIELD_FROM_ISR(); + } +} + +static size_t i2c_slave_read_rx(i2c_slave_struct_t * i2c, uint8_t * data, size_t len){ + if(!len){ + return 0; + } +#if I2C_SLAVE_USE_RX_QUEUE + uint8_t d = 0; + BaseType_t res = pdTRUE; + for(size_t i=0; irx_queue, &data[i], 0); + } else { + res = xQueueReceive(i2c->rx_queue, &d, 0); + } + if (res != pdTRUE) { + log_e("Read Queue(%u) Failed", i); + len = i; + break; + } + } + return (data)?len:0; +#else + size_t dlen = 0, + to_read = len, + so_far = 0, + available = 0; + uint8_t * rx_data = NULL; + + vRingbufferGetInfo(i2c->rx_ring_buf, NULL, NULL, NULL, NULL, &available); + if(available < to_read){ + log_e("Less available than requested. %u < %u", available, len); + to_read = available; + } + + while(to_read){ + dlen = 0; + rx_data = (uint8_t *)xRingbufferReceiveUpTo(i2c->rx_ring_buf, &dlen, 0, to_read); + if(!rx_data){ + log_e("Receive %u Failed", to_read); + return so_far; + } + if(data){ + memcpy(data+so_far, rx_data, dlen); + } + vRingbufferReturnItem(i2c->rx_ring_buf, rx_data); + so_far+=dlen; + to_read-=dlen; + } + return (data)?so_far:0; +#endif +} + +static void i2c_slave_task(void *pv_args) +{ + i2c_slave_struct_t * i2c = (i2c_slave_struct_t *)pv_args; + i2c_slave_queue_event_t event; + size_t len = 0; + bool stop = false; + uint8_t * data = NULL; + for(;;){ + if(xQueueReceive(i2c->event_queue, &event, portMAX_DELAY) == pdTRUE){ + // Write + if(event.event == I2C_SLAVE_EVT_RX){ + len = event.param; + stop = event.stop; + data = (len > 0)?(uint8_t*)malloc(len):NULL; + + if(len && data == NULL){ + log_e("Malloc (%u) Failed", len); + } + len = i2c_slave_read_rx(i2c, data, len); + if(i2c->receive_callback){ + i2c->receive_callback(i2c->num, data, len, stop, i2c->arg); + } + free(data); + + // Read + } else if(event.event == I2C_SLAVE_EVT_TX){ + if(i2c->request_callback){ + i2c->request_callback(i2c->num, i2c->arg); + } + i2c_ll_stretch_clr(i2c->dev); + } + } + } + vTaskDelete(NULL); +} + +static bool i2cSlaveDetachBus(void * bus_i2c_num){ + uint8_t num = (int)bus_i2c_num - 1; + i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; + if (i2c->scl == -1 && i2c->sda == -1) { + return true; + } + esp_err_t err = i2cSlaveDeinit(num); + if(err != ESP_OK){ + log_e("i2cSlaveDeinit failed with error: %d", err); + return false; + } + return true; +} + +#endif /* SOC_I2C_SUPPORT_SLAVE */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c-slave.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c-slave.h new file mode 100644 index 0000000..bc68930 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c-slave.h @@ -0,0 +1,40 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_I2C_SUPPORT_SLAVE + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdint.h" +#include "stddef.h" +#include "esp_err.h" + +typedef void (*i2c_slave_request_cb_t) (uint8_t num, void * arg); +typedef void (*i2c_slave_receive_cb_t) (uint8_t num, uint8_t * data, size_t len, bool stop, void * arg); +esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg); + +esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len); +esp_err_t i2cSlaveDeinit(uint8_t num); +size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_I2C_SUPPORT_SLAVE */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c.c new file mode 100644 index 0000000..4fe09ff --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c.c @@ -0,0 +1,396 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-i2c.h" + +#if SOC_I2C_SUPPORTED +#include "esp32-hal.h" +#if !CONFIG_DISABLE_HAL_LOCKS +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#endif +#include "esp_attr.h" +#include "esp_system.h" +#include "soc/soc_caps.h" +#include "soc/i2c_periph.h" +#include "hal/i2c_hal.h" +#include "hal/i2c_ll.h" +#include "driver/i2c.h" +#include "esp32-hal-periman.h" + +typedef volatile struct { + bool initialized; + uint32_t frequency; +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t lock; + int8_t scl; + int8_t sda; +#endif +} i2c_bus_t; + +static i2c_bus_t bus[SOC_I2C_NUM]; + +static bool i2cDetachBus(void * bus_i2c_num){ + uint8_t i2c_num = (int)bus_i2c_num - 1; + if(!bus[i2c_num].initialized){ + return true; + } + esp_err_t err = i2cDeinit(i2c_num); + if(err != ESP_OK){ + log_e("i2cDeinit failed with error: %d", err); + return false; + } + return true; +} + +bool i2cIsInit(uint8_t i2c_num){ + if(i2c_num >= SOC_I2C_NUM){ + return false; + } + return bus[i2c_num].initialized; +} + +esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency){ + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } +#if !CONFIG_DISABLE_HAL_LOCKS + if(bus[i2c_num].lock == NULL){ + bus[i2c_num].lock = xSemaphoreCreateMutex(); + if(bus[i2c_num].lock == NULL){ + log_e("xSemaphoreCreateMutex failed"); + return ESP_ERR_NO_MEM; + } + } + //acquire lock + if(xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return ESP_FAIL; + } +#endif + if(bus[i2c_num].initialized){ + log_e("bus is already initialized"); + return ESP_FAIL; + } + + if(!frequency){ + frequency = 100000UL; + } else if(frequency > 1000000UL){ + frequency = 1000000UL; + } + + perimanSetBusDeinit(ESP32_BUS_TYPE_I2C_MASTER, i2cDetachBus); + if(!perimanSetPinBus(sda, ESP32_BUS_TYPE_INIT, NULL) || !perimanSetPinBus(scl, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + + log_i("Initialising I2C Master: sda=%d scl=%d freq=%d", sda, scl, frequency); + + i2c_config_t conf = { }; + conf.mode = I2C_MODE_MASTER; + conf.scl_io_num = (gpio_num_t)scl; + conf.sda_io_num = (gpio_num_t)sda; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = frequency; + conf.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL; //Any one clock source that is available for the specified frequency may be choosen + + esp_err_t ret = i2c_param_config((i2c_port_t)i2c_num, &conf); + if (ret != ESP_OK) { + log_e("i2c_param_config failed"); + } else { + ret = i2c_driver_install((i2c_port_t)i2c_num, conf.mode, 0, 0, 0); + if (ret != ESP_OK) { + log_e("i2c_driver_install failed"); + } else { + bus[i2c_num].initialized = true; + bus[i2c_num].frequency = frequency; + bus[i2c_num].scl = scl; + bus[i2c_num].sda = sda; + //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2 + i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT); + if(!perimanSetPinBus(sda, ESP32_BUS_TYPE_I2C_MASTER, (void *)(i2c_num+1)) || !perimanSetPinBus(scl, ESP32_BUS_TYPE_I2C_MASTER, (void *)(i2c_num+1))){ + i2cDetachBus((void *)(i2c_num+1)); + return false; + } + } + } +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(bus[i2c_num].lock); +#endif + return ret; +} + +esp_err_t i2cDeinit(uint8_t i2c_num){ + esp_err_t err = ESP_FAIL; + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } +#if !CONFIG_DISABLE_HAL_LOCKS + //acquire lock + if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return err; + } +#endif + if(!bus[i2c_num].initialized){ + log_e("bus is not initialized"); + } else { + err = i2c_driver_delete((i2c_port_t)i2c_num); + if(err == ESP_OK){ + bus[i2c_num].initialized = false; + perimanSetPinBus(bus[i2c_num].scl, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(bus[i2c_num].sda, ESP32_BUS_TYPE_INIT, NULL); + bus[i2c_num].scl = -1; + bus[i2c_num].sda = -1; + } + } +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(bus[i2c_num].lock); +#endif + return err; +} + +esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis){ + esp_err_t ret = ESP_FAIL; + i2c_cmd_handle_t cmd = NULL; + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } +#if !CONFIG_DISABLE_HAL_LOCKS + //acquire lock + if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return ret; + } +#endif + if(!bus[i2c_num].initialized){ + log_e("bus is not initialized"); + goto end; + } + + //short implementation does not support zero size writes (example when scanning) PR in IDF? + //ret = i2c_master_write_to_device((i2c_port_t)i2c_num, address, buff, size, timeOutMillis / portTICK_PERIOD_MS); + + ret = ESP_OK; + uint8_t cmd_buff[I2C_LINK_RECOMMENDED_SIZE(1)] = { 0 }; + cmd = i2c_cmd_link_create_static(cmd_buff, I2C_LINK_RECOMMENDED_SIZE(1)); + ret = i2c_master_start(cmd); + if (ret != ESP_OK) { + goto end; + } + ret = i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true); + if (ret != ESP_OK) { + goto end; + } + if(size){ + ret = i2c_master_write(cmd, buff, size, true); + if (ret != ESP_OK) { + goto end; + } + } + ret = i2c_master_stop(cmd); + if (ret != ESP_OK) { + goto end; + } + ret = i2c_master_cmd_begin((i2c_port_t)i2c_num, cmd, timeOutMillis / portTICK_PERIOD_MS); + +end: + if(cmd != NULL){ + i2c_cmd_link_delete_static(cmd); + } +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(bus[i2c_num].lock); +#endif + return ret; +} + +esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount){ + esp_err_t ret = ESP_FAIL; + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } +#if !CONFIG_DISABLE_HAL_LOCKS + //acquire lock + if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return ret; + } +#endif + if(!bus[i2c_num].initialized){ + log_e("bus is not initialized"); + } else { + ret = i2c_master_read_from_device((i2c_port_t)i2c_num, address, buff, size, timeOutMillis / portTICK_PERIOD_MS); + if(ret == ESP_OK){ + *readCount = size; + } else { + *readCount = 0; + } + } +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(bus[i2c_num].lock); +#endif + return ret; +} + +esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount){ + esp_err_t ret = ESP_FAIL; + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } +#if !CONFIG_DISABLE_HAL_LOCKS + //acquire lock + if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return ret; + } +#endif + if(!bus[i2c_num].initialized){ + log_e("bus is not initialized"); + } else { + ret = i2c_master_write_read_device((i2c_port_t)i2c_num, address, wbuff, wsize, rbuff, rsize, timeOutMillis / portTICK_PERIOD_MS); + if(ret == ESP_OK){ + *readCount = rsize; + } else { + *readCount = 0; + } + } +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(bus[i2c_num].lock); +#endif + return ret; +} + +esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency){ + esp_err_t ret = ESP_FAIL; + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } +#if !CONFIG_DISABLE_HAL_LOCKS + //acquire lock + if(bus[i2c_num].lock == NULL || xSemaphoreTake(bus[i2c_num].lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return ret; + } +#endif + if(!bus[i2c_num].initialized){ + log_e("bus is not initialized"); + goto end; + } + if(bus[i2c_num].frequency == frequency){ + ret = ESP_OK; + goto end; + } + if(!frequency){ + frequency = 100000UL; + } else if(frequency > 1000000UL){ + frequency = 1000000UL; + } + // Freq limitation when using different clock sources + #define I2C_CLK_LIMIT_REF_TICK (1 * 1000 * 1000 / 20) /*!< Limited by REF_TICK, no more than REF_TICK/20*/ + #define I2C_CLK_LIMIT_APB (80 * 1000 * 1000 / 20) /*!< Limited by APB, no more than APB/20*/ + #define I2C_CLK_LIMIT_RTC (20 * 1000 * 1000 / 20) /*!< Limited by RTC, no more than RTC/20*/ + #define I2C_CLK_LIMIT_XTAL (40 * 1000 * 1000 / 20) /*!< Limited by RTC, no more than XTAL/20*/ + + typedef struct { + soc_module_clk_t clk; /*!< I2C source clock */ + uint32_t clk_freq; /*!< I2C source clock frequency */ + } i2c_clk_alloc_t; + + typedef enum { + I2C_SCLK_DEFAULT = 0, /*!< I2C source clock not selected*/ + #if SOC_I2C_SUPPORT_APB + I2C_SCLK_APB, /*!< I2C source clock from APB, 80M*/ + #endif + #if SOC_I2C_SUPPORT_XTAL + I2C_SCLK_XTAL, /*!< I2C source clock from XTAL, 40M */ + #endif + #if SOC_I2C_SUPPORT_RTC + I2C_SCLK_RTC, /*!< I2C source clock from 8M RTC, 8M */ + #endif + #if SOC_I2C_SUPPORT_REF_TICK + I2C_SCLK_REF_TICK, /*!< I2C source clock from REF_TICK, 1M */ + #endif + I2C_SCLK_MAX, + } i2c_sclk_t; + + // i2c clock characteristic, The order is the same as i2c_sclk_t. + static i2c_clk_alloc_t i2c_clk_alloc[I2C_SCLK_MAX] = { + {0, 0}, + #if SOC_I2C_SUPPORT_APB + {SOC_MOD_CLK_APB, I2C_CLK_LIMIT_APB}, /*!< I2C APB clock characteristic*/ + #endif + #if SOC_I2C_SUPPORT_XTAL + {SOC_MOD_CLK_XTAL, I2C_CLK_LIMIT_XTAL}, /*!< I2C XTAL characteristic*/ + #endif + #if SOC_I2C_SUPPORT_RTC + {SOC_MOD_CLK_RC_FAST, I2C_CLK_LIMIT_RTC}, /*!< I2C 20M RTC characteristic*/ + #endif + #if SOC_I2C_SUPPORT_REF_TICK + {SOC_MOD_CLK_REF_TICK, I2C_CLK_LIMIT_REF_TICK},/*!< I2C REF_TICK characteristic*/ + #endif + }; + + i2c_sclk_t src_clk = I2C_SCLK_DEFAULT; + ret = ESP_OK; + for (i2c_sclk_t clk = I2C_SCLK_DEFAULT + 1; clk < I2C_SCLK_MAX; clk++) { +#if CONFIG_IDF_TARGET_ESP32S3 + if (clk == I2C_SCLK_RTC) { // RTC clock for s3 is unaccessable now. + continue; + } +#endif + if (frequency <= i2c_clk_alloc[clk].clk_freq) { + src_clk = clk; + break; + } + } + if(src_clk == I2C_SCLK_DEFAULT || src_clk == I2C_SCLK_MAX){ + log_e("clock source could not be selected"); + ret = ESP_FAIL; + } else { + i2c_hal_context_t hal; + hal.dev = I2C_LL_GET_HW(i2c_num); + i2c_hal_set_bus_timing(&(hal), frequency, i2c_clk_alloc[src_clk].clk, i2c_clk_alloc[src_clk].clk_freq); + bus[i2c_num].frequency = frequency; + //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2 + i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT); + } + +end: +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(bus[i2c_num].lock); +#endif + return ret; +} + +esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency){ + if(i2c_num >= SOC_I2C_NUM){ + return ESP_ERR_INVALID_ARG; + } + if(!bus[i2c_num].initialized){ + log_e("bus is not initialized"); + return ESP_FAIL; + } + *frequency = bus[i2c_num].frequency; + return ESP_OK; +} + +#endif /* SOC_I2C_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c.h new file mode 100644 index 0000000..2fa1e24 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-i2c.h @@ -0,0 +1,45 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// modified Nov 2017 by Chuck Todd to support Interrupt Driven I/O +// modified Nov 2021 by Hristo Gochkov to support ESP-IDF API + +#ifndef _ESP32_HAL_I2C_H_ +#define _ESP32_HAL_I2C_H_ + +#include "soc/soc_caps.h" +#if SOC_I2C_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +esp_err_t i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed); +esp_err_t i2cDeinit(uint8_t i2c_num); +esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency); +esp_err_t i2cGetClock(uint8_t i2c_num, uint32_t * frequency); +esp_err_t i2cWrite(uint8_t i2c_num, uint16_t address, const uint8_t* buff, size_t size, uint32_t timeOutMillis); +esp_err_t i2cRead(uint8_t i2c_num, uint16_t address, uint8_t* buff, size_t size, uint32_t timeOutMillis, size_t *readCount); +esp_err_t i2cWriteReadNonStop(uint8_t i2c_num, uint16_t address, const uint8_t* wbuff, size_t wsize, uint8_t* rbuff, size_t rsize, uint32_t timeOutMillis, size_t *readCount); +bool i2cIsInit(uint8_t i2c_num); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_I2C_SUPPORTED */ +#endif /* _ESP32_HAL_I2C_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-ledc.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-ledc.c new file mode 100644 index 0000000..cddaf7b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-ledc.c @@ -0,0 +1,389 @@ +// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/soc_caps.h" + +#if SOC_LEDC_SUPPORTED +#include "esp32-hal.h" +#include "esp32-hal-ledc.h" +#include "driver/ledc.h" +#include "esp32-hal-periman.h" + +#ifdef SOC_LEDC_SUPPORT_HS_MODE +#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM<<1) +#else +#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM) +#endif + +//Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz +//Need to be fixed in ESP-IDF +#ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK +#define LEDC_DEFAULT_CLK LEDC_USE_XTAL_CLK +#else +#define LEDC_DEFAULT_CLK LEDC_AUTO_CLK +#endif + +#define LEDC_MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDTH + +typedef struct { + int used_channels : LEDC_CHANNELS; // Used channels as a bits +} ledc_periph_t; + +ledc_periph_t ledc_handle; + +static bool fade_initialized = false; + +static bool ledcDetachBus(void * bus){ + ledc_channel_handle_t *handle = (ledc_channel_handle_t*)bus; + ledc_handle.used_channels &= ~(1UL << handle->channel); + pinMatrixOutDetach(handle->pin, false, false); + free(handle); + if(ledc_handle.used_channels == 0){ + ledc_fade_func_uninstall(); + fade_initialized = false; + } + return true; +} + +bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution) +{ + int free_channel = ~ledc_handle.used_channels & (ledc_handle.used_channels+1); + if (free_channel == 0 || resolution > LEDC_MAX_BIT_WIDTH) + { + log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH); + return false; + } + + perimanSetBusDeinit(ESP32_BUS_TYPE_LEDC, ledcDetachBus); + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL && !perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + + int channel = log2(free_channel & -free_channel); + uint8_t group=(channel/8), timer=((channel/2)%4); + + ledc_timer_config_t ledc_timer = { + .speed_mode = group, + .timer_num = timer, + .duty_resolution = resolution, + .freq_hz = freq, + .clk_cfg = LEDC_DEFAULT_CLK + }; + if(ledc_timer_config(&ledc_timer) != ESP_OK) + { + log_e("ledc setup failed!"); + return false; + } + + uint32_t duty = ledc_get_duty(group,channel); + + ledc_channel_config_t ledc_channel = { + .speed_mode = group, + .channel = (channel%8), + .timer_sel = timer, + .intr_type = LEDC_INTR_DISABLE, + .gpio_num = pin, + .duty = duty, + .hpoint = 0 + }; + ledc_channel_config(&ledc_channel); + + ledc_channel_handle_t *handle = (ledc_channel_handle_t *)malloc(sizeof(ledc_channel_handle_t)); + + handle->pin = pin; + handle->channel = channel; + handle->channel_resolution = resolution; + #ifndef SOC_LEDC_SUPPORT_FADE_STOP + handle->lock = NULL; + #endif + ledc_handle.used_channels |= 1UL << channel; + + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_LEDC, (void *)handle)){ + ledcDetachBus((void *)handle); + return false; + } + + return true; +} +bool ledcWrite(uint8_t pin, uint32_t duty) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + + uint8_t group=(bus->channel/8), channel=(bus->channel%8); + + //Fixing if all bits in resolution is set = LEDC FULL ON + uint32_t max_duty = (1 << bus->channel_resolution) - 1; + + if((duty == max_duty) && (max_duty != 1)){ + duty = max_duty + 1; + } + + ledc_set_duty(group, channel, duty); + ledc_update_duty(group, channel); + + return true; + } + return false; +} + +uint32_t ledcRead(uint8_t pin) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + + uint8_t group=(bus->channel/8), channel=(bus->channel%8); + return ledc_get_duty(group,channel); + } + return 0; +} + +uint32_t ledcReadFreq(uint8_t pin) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + if(!ledcRead(pin)){ + return 0; + } + uint8_t group=(bus->channel/8), timer=((bus->channel/2)%4); + return ledc_get_freq(group,timer); + } + return 0; +} + + +uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + + if(!freq){ + ledcWrite(pin, 0); + return 0; + } + + uint8_t group=(bus->channel/8), timer=((bus->channel/2)%4); + + ledc_timer_config_t ledc_timer = { + .speed_mode = group, + .timer_num = timer, + .duty_resolution = 10, + .freq_hz = freq, + .clk_cfg = LEDC_DEFAULT_CLK + }; + + if(ledc_timer_config(&ledc_timer) != ESP_OK) + { + log_e("ledcWriteTone configuration failed!"); + return 0; + } + bus->channel_resolution = 10; + + uint32_t res_freq = ledc_get_freq(group,timer); + ledcWrite(pin, 0x1FF); + return res_freq; + } + return 0; +} + +uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave){ + const uint16_t noteFrequencyBase[12] = { + // C C# D Eb E F F# G G# A Bb B + 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902 + }; + + if(octave > 8 || note >= NOTE_MAX){ + return 0; + } + uint32_t noteFreq = (uint32_t)noteFrequencyBase[note] / (uint32_t)(1 << (8-octave)); + return ledcWriteTone(pin, noteFreq); +} + +bool ledcDetach(uint8_t pin) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + // will call ledcDetachBus + return perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL); + } else { + log_e("pin %u is not attached to LEDC", pin); + } + return false; +} + +uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) +{ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + + if(resolution > LEDC_MAX_BIT_WIDTH){ + log_e("LEDC resolution too big (maximum %u)", LEDC_MAX_BIT_WIDTH); + return 0; + } + uint8_t group=(bus->channel/8), timer=((bus->channel/2)%4); + + ledc_timer_config_t ledc_timer = { + .speed_mode = group, + .timer_num = timer, + .duty_resolution = resolution, + .freq_hz = freq, + .clk_cfg = LEDC_DEFAULT_CLK + }; + + if(ledc_timer_config(&ledc_timer) != ESP_OK) + { + log_e("ledcChangeFrequency failed!"); + return 0; + } + bus->channel_resolution = resolution; + return ledc_get_freq(group,timer); + } + return 0; +} + +static IRAM_ATTR bool ledcFnWrapper(const ledc_cb_param_t *param, void *user_arg) +{ + if (param->event == LEDC_FADE_END_EVT) { + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)user_arg; + #ifndef SOC_LEDC_SUPPORT_FADE_STOP + portBASE_TYPE xTaskWoken = 0; + xSemaphoreGiveFromISR(bus->lock, &xTaskWoken); + #endif + if(bus->fn) { + if(bus->arg){ + ((voidFuncPtrArg)bus->fn)(bus->arg); + } else { + bus->fn(); + } + } + } + return true; +} + +static bool ledcFadeConfig(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void*), void * arg){ + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus != NULL){ + + #ifndef SOC_LEDC_SUPPORT_FADE_STOP + #if !CONFIG_DISABLE_HAL_LOCKS + if(bus->lock == NULL){ + bus->lock = xSemaphoreCreateBinary(); + if(bus->lock == NULL){ + log_e("xSemaphoreCreateBinary failed"); + return false; + } + xSemaphoreGive(bus->lock); + } + //acquire lock + if(xSemaphoreTake(bus->lock, 0) != pdTRUE){ + log_e("LEDC Fade is still running on pin %u! SoC does not support stopping fade.", pin); + return false; + } + #endif + #endif + uint8_t group=(bus->channel/8), channel=(bus->channel%8); + + // Initialize fade service. + if(!fade_initialized){ + ledc_fade_func_install(0); + fade_initialized = true; + } + + bus->fn = (voidFuncPtr)userFunc; + bus->arg = arg; + + ledc_cbs_t callbacks = { + .fade_cb = ledcFnWrapper + }; + ledc_cb_register(group, channel, &callbacks, (void *) bus); + + //Fixing if all bits in resolution is set = LEDC FULL ON + uint32_t max_duty = (1 << bus->channel_resolution) - 1; + + if((target_duty == max_duty) && (max_duty != 1)){ + target_duty = max_duty + 1; + } + else if((start_duty == max_duty) && (max_duty != 1)){ + start_duty = max_duty + 1; + } + + #if SOC_LEDC_SUPPORT_FADE_STOP + ledc_fade_stop(group, channel); + #endif + + if(ledc_set_duty_and_update(group, channel, start_duty, 0) != ESP_OK){ + log_e("ledc_set_duty_and_update failed"); + return false; + } + // Wait for LEDCs next PWM cycle to update duty (~ 1-2 ms) + while(ledc_get_duty(group,channel) != start_duty); + + if(ledc_set_fade_time_and_start(group, channel, target_duty, max_fade_time_ms, LEDC_FADE_NO_WAIT) != ESP_OK){ + log_e("ledc_set_fade_time_and_start failed"); + return false; + } + } + else { + log_e("Pin %u is not attached to LEDC. Call ledcAttach first!", pin); + return false; + } + return true; +} + +bool ledcFade(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms){ + return ledcFadeConfig(pin, start_duty, target_duty, max_fade_time_ms, NULL, NULL); +} + +bool ledcFadeWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, voidFuncPtr userFunc){ + return ledcFadeConfig(pin, start_duty, target_duty, max_fade_time_ms, (voidFuncPtrArg)userFunc, NULL); +} + +bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void*), void * arg){ + return ledcFadeConfig(pin, start_duty, target_duty, max_fade_time_ms, userFunc, arg); +} + +static uint8_t analog_resolution = 8; +static int analog_frequency = 1000; +void analogWrite(uint8_t pin, int value) { + // Use ledc hardware for internal pins + if (pin < SOC_GPIO_PIN_COUNT) { + ledc_channel_handle_t *bus = (ledc_channel_handle_t*)perimanGetPinBus(pin, ESP32_BUS_TYPE_LEDC); + if(bus == NULL && perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)){ + if(ledcAttach(pin, analog_frequency, analog_resolution) == 0){ + log_e("analogWrite setup failed (freq = %u, resolution = %u). Try setting different resolution or frequency"); + return; + } + } + ledcWrite(pin, value); + } +} + +void analogWriteFrequency(uint8_t pin, uint32_t freq) { + if (ledcChangeFrequency(pin, freq, analog_resolution) == 0){ + log_e("analogWrite frequency cant be set due to selected resolution! Try to adjust resolution first"); + return; + } + analog_frequency = freq; +} + +void analogWriteResolution(uint8_t pin, uint8_t resolution) { + if (ledcChangeFrequency(pin, analog_frequency, resolution) == 0){ + log_e("analogWrite resolution cant be set due to selected frequency! Try to adjust frequency first"); + return; + } + analog_resolution = resolution; +} + +#endif /* SOC_LEDC_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-ledc.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-ledc.h new file mode 100644 index 0000000..ca17284 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-ledc.h @@ -0,0 +1,66 @@ +// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP32_HAL_LEDC_H_ +#define _ESP32_HAL_LEDC_H_ + +#include "soc/soc_caps.h" +#if SOC_LEDC_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef enum { + NOTE_C, NOTE_Cs, NOTE_D, NOTE_Eb, NOTE_E, NOTE_F, NOTE_Fs, NOTE_G, NOTE_Gs, NOTE_A, NOTE_Bb, NOTE_B, NOTE_MAX +} note_t; + +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); + +typedef struct { + uint8_t pin; // Pin assigned to channel + uint8_t channel; // Channel number + uint8_t channel_resolution; // Resolution of channel + voidFuncPtr fn; + void* arg; +#ifndef SOC_LEDC_SUPPORT_FADE_STOP + SemaphoreHandle_t lock; //xSemaphoreCreateBinary +#endif +} ledc_channel_handle_t; + +//channel 0-15 resolution 1-16bits freq limits depend on resolution +bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution); +bool ledcWrite(uint8_t pin, uint32_t duty); +uint32_t ledcWriteTone(uint8_t pin, uint32_t freq); +uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave); +uint32_t ledcRead(uint8_t pin); +uint32_t ledcReadFreq(uint8_t pin); +bool ledcDetach(uint8_t pin); +uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution); + +//Fade functions +bool ledcFade(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms); +bool ledcFadeWithInterrupt(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void)); +bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_duty, int max_fade_time_ms, void (*userFunc)(void*), void * arg); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_LEDC_SUPPORTED */ +#endif /* _ESP32_HAL_LEDC_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-log.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-log.h new file mode 100644 index 0000000..15f9864 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-log.h @@ -0,0 +1,228 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef __ARDUHAL_LOG_H__ +#define __ARDUHAL_LOG_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sdkconfig.h" +#include "esp_timer.h" + +#define ARDUHAL_LOG_LEVEL_NONE (0) +#define ARDUHAL_LOG_LEVEL_ERROR (1) +#define ARDUHAL_LOG_LEVEL_WARN (2) +#define ARDUHAL_LOG_LEVEL_INFO (3) +#define ARDUHAL_LOG_LEVEL_DEBUG (4) +#define ARDUHAL_LOG_LEVEL_VERBOSE (5) + +#ifndef CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL +#define CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL ARDUHAL_LOG_LEVEL_NONE +#endif + +#ifndef CORE_DEBUG_LEVEL +#define ARDUHAL_LOG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL +#else +#define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL +#ifdef USE_ESP_IDF_LOG +#ifndef LOG_LOCAL_LEVEL +#define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL +#endif +#endif +#endif + +#ifndef CONFIG_ARDUHAL_LOG_COLORS +#define CONFIG_ARDUHAL_LOG_COLORS 0 +#endif + +#if CONFIG_ARDUHAL_LOG_COLORS +#define ARDUHAL_LOG_COLOR_BLACK "30" +#define ARDUHAL_LOG_COLOR_RED "31" //ERROR +#define ARDUHAL_LOG_COLOR_GREEN "32" //INFO +#define ARDUHAL_LOG_COLOR_YELLOW "33" //WARNING +#define ARDUHAL_LOG_COLOR_BLUE "34" +#define ARDUHAL_LOG_COLOR_MAGENTA "35" +#define ARDUHAL_LOG_COLOR_CYAN "36" //DEBUG +#define ARDUHAL_LOG_COLOR_GRAY "37" //VERBOSE +#define ARDUHAL_LOG_COLOR_WHITE "38" + +#define ARDUHAL_LOG_COLOR(COLOR) "\033[0;" COLOR "m" +#define ARDUHAL_LOG_BOLD(COLOR) "\033[1;" COLOR "m" +#define ARDUHAL_LOG_RESET_COLOR "\033[0m" + +#define ARDUHAL_LOG_COLOR_E ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_RED) +#define ARDUHAL_LOG_COLOR_W ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_YELLOW) +#define ARDUHAL_LOG_COLOR_I ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GREEN) +#define ARDUHAL_LOG_COLOR_D ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_CYAN) +#define ARDUHAL_LOG_COLOR_V ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GRAY) +#define ARDUHAL_LOG_COLOR_PRINT(letter) log_printf(ARDUHAL_LOG_COLOR_ ## letter) +#define ARDUHAL_LOG_COLOR_PRINT_END log_printf(ARDUHAL_LOG_RESET_COLOR) +#else +#define ARDUHAL_LOG_COLOR_E +#define ARDUHAL_LOG_COLOR_W +#define ARDUHAL_LOG_COLOR_I +#define ARDUHAL_LOG_COLOR_D +#define ARDUHAL_LOG_COLOR_V +#define ARDUHAL_LOG_RESET_COLOR +#define ARDUHAL_LOG_COLOR_PRINT(letter) +#define ARDUHAL_LOG_COLOR_PRINT_END +#endif + + + +const char * pathToFileName(const char * path); +int log_printf(const char *fmt, ...); +void log_print_buf(const uint8_t *b, size_t len); + +#define ARDUHAL_SHORT_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter format ARDUHAL_LOG_RESET_COLOR "\r\n" +#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__ + +//esp_rom_printf(DRAM_STR("ST:%d\n"), frame_pos); + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE +#ifndef USE_ESP_IDF_LOG +#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__) +#define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__) +#define log_buf_v(b,l) do{ARDUHAL_LOG_COLOR_PRINT(V);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) +#else +#define log_v(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, TAG, format, ##__VA_ARGS__);}while(0) +#define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) +#define log_buf_v(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_VERBOSE);}while(0) +#endif +#else +#define log_v(format, ...) do {} while(0) +#define isr_log_v(format, ...) do {} while(0) +#define log_buf_v(b,l) do {} while(0) +#endif + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG +#ifndef USE_ESP_IDF_LOG +#define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__) +#define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__) +#define log_buf_d(b,l) do{ARDUHAL_LOG_COLOR_PRINT(D);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) +#else +#define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0) +#define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) +#define log_buf_d(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_DEBUG);}while(0) +#endif +#else +#define log_d(format, ...) do {} while(0) +#define isr_log_d(format, ...) do {} while(0) +#define log_buf_d(b,l) do {} while(0) +#endif + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO +#ifndef USE_ESP_IDF_LOG +#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__) +#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__) +#define log_buf_i(b,l) do{ARDUHAL_LOG_COLOR_PRINT(I);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) +#else +#define log_i(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, TAG, format, ##__VA_ARGS__);}while(0) +#define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) +#define log_buf_i(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_INFO);}while(0) +#endif +#else +#define log_i(format, ...) do {} while(0) +#define isr_log_i(format, ...) do {} while(0) +#define log_buf_i(b,l) do {} while(0) +#endif + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN +#ifndef USE_ESP_IDF_LOG +#define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__) +#define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__) +#define log_buf_w(b,l) do{ARDUHAL_LOG_COLOR_PRINT(W);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) +#else +#define log_w(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, TAG, format, ##__VA_ARGS__);}while(0) +#define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) +#define log_buf_w(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_WARN);}while(0) +#endif +#else +#define log_w(format, ...) do {} while(0) +#define isr_log_w(format, ...) do {} while(0) +#define log_buf_w(b,l) do {} while(0) +#endif + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR +#ifndef USE_ESP_IDF_LOG +#define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) +#define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) +#define log_buf_e(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) +#else +#define log_e(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0) +#define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) +#define log_buf_e(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0) +#endif +#else +#define log_e(format, ...) do {} while(0) +#define isr_log_e(format, ...) do {} while(0) +#define log_buf_e(b,l) do {} while(0) +#endif + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE +#ifndef USE_ESP_IDF_LOG +#define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) +#define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__) +#define log_buf_n(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0) +#else +#define log_n(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0) +#define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0) +#define log_buf_n(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0) +#endif +#else +#define log_n(format, ...) do {} while(0) +#define isr_log_n(format, ...) do {} while(0) +#define log_buf_n(b,l) do {} while(0) +#endif + +#include "esp_log.h" + +#ifdef USE_ESP_IDF_LOG +//#ifndef TAG +//#define TAG "ARDUINO" +//#endif +//#define log_n(format, ...) myLog(ESP_LOG_NONE, format, ##__VA_ARGS__) +#else +#ifdef CONFIG_ARDUHAL_ESP_LOG +#undef ESP_LOGE +#undef ESP_LOGW +#undef ESP_LOGI +#undef ESP_LOGD +#undef ESP_LOGV +#undef ESP_EARLY_LOGE +#undef ESP_EARLY_LOGW +#undef ESP_EARLY_LOGI +#undef ESP_EARLY_LOGD +#undef ESP_EARLY_LOGV + +#define ESP_LOGE(tag, format, ...) log_e("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_LOGW(tag, format, ...) log_w("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_LOGI(tag, format, ...) log_i("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_LOGD(tag, format, ...) log_d("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_LOGV(tag, format, ...) log_v("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_EARLY_LOGE(tag, format, ...) isr_log_e("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_EARLY_LOGW(tag, format, ...) isr_log_w("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_EARLY_LOGI(tag, format, ...) isr_log_i("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_EARLY_LOGD(tag, format, ...) isr_log_d("[%s] " format, tag, ##__VA_ARGS__) +#define ESP_EARLY_LOGV(tag, format, ...) isr_log_v("[%s] " format, tag, ##__VA_ARGS__) +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_LOGGING_H__ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-matrix.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-matrix.c new file mode 100644 index 0000000..8f2f7d8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-matrix.c @@ -0,0 +1,67 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-matrix.h" +#include "esp_attr.h" + +#include "esp_system.h" +#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ +#include "soc/gpio_pins.h" +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/gpio.h" +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif +#else // ESP32 Before IDF 4.0 +#include "rom/gpio.h" +#define GPIO_MATRIX_CONST_ZERO_INPUT GPIO_FUNC_IN_LOW +#define GPIO_MATRIX_CONST_ONE_INPUT GPIO_FUNC_IN_HIGH +#endif + + +void ARDUINO_ISR_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable) +{ + gpio_matrix_out(pin, function, invertOut, invertEnable); +} + +void ARDUINO_ISR_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable) +{ + gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, invertOut, invertEnable); +} + +void ARDUINO_ISR_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted) +{ + gpio_matrix_in(pin, signal, inverted); +} + +void ARDUINO_ISR_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted) +{ + gpio_matrix_in(high?GPIO_MATRIX_CONST_ONE_INPUT:GPIO_MATRIX_CONST_ZERO_INPUT, signal, inverted); +} +/* +void ARDUINO_ISR_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){ + intr_matrix_set(PRO_CPU_NUM, source, inum); +} +*/ + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-matrix.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-matrix.h new file mode 100644 index 0000000..3bc9049 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-matrix.h @@ -0,0 +1,35 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP32_HAL_MATRIX_H_ +#define _ESP32_HAL_MATRIX_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp32-hal.h" +#include "soc/gpio_sig_map.h" + +void pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable); +void pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable); +void pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted); +void pinMatrixInDetach(uint8_t signal, bool high, bool inverted); + +#ifdef __cplusplus +} +#endif + +#endif /* COMPONENTS_ARDUHAL_INCLUDE_ESP32_HAL_MATRIX_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-misc.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-misc.c new file mode 100644 index 0000000..ae1083c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-misc.c @@ -0,0 +1,414 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_attr.h" +#include "nvs_flash.h" +#include "nvs.h" +#include "esp_partition.h" +#include "esp_log.h" +#include "esp_timer.h" +#ifdef CONFIG_APP_ROLLBACK_ENABLE +#include "esp_ota_ops.h" +#endif //CONFIG_APP_ROLLBACK_ENABLE +#ifdef CONFIG_BT_ENABLED +#include "esp_bt.h" +#endif //CONFIG_BT_ENABLED +#include +#include "soc/rtc.h" +#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#include "soc/rtc_cntl_reg.h" +#include "soc/apb_ctrl_reg.h" +#endif +#include "esp_task_wdt.h" +#include "esp32-hal.h" + +#include "esp_system.h" +#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ + +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/rtc.h" + +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif + +#if SOC_TEMP_SENSOR_SUPPORTED +#include "driver/temperature_sensor.h" +#endif + +#else // ESP32 Before IDF 4.0 +#include "rom/rtc.h" +#endif + +//Undocumented!!! Get chip temperature in Farenheit +//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino +#ifdef CONFIG_IDF_TARGET_ESP32 +uint8_t temprature_sens_read(); + +float temperatureRead() +{ + return (temprature_sens_read() - 32) / 1.8; +} +#elif SOC_TEMP_SENSOR_SUPPORTED +static temperature_sensor_handle_t temp_sensor = NULL; + +static bool temperatureReadInit() +{ + static volatile bool initialized = false; + if(!initialized){ + initialized = true; + //Install temperature sensor, expected temp ranger range: 10~50 ℃ + temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(10, 50); + if(temperature_sensor_install(&temp_sensor_config, &temp_sensor) != ESP_OK){ + initialized = false; + temp_sensor = NULL; + log_e("temperature_sensor_install failed"); + } + else if(temperature_sensor_enable(temp_sensor) != ESP_OK){ + temperature_sensor_uninstall(temp_sensor); + initialized = false; + temp_sensor = NULL; + log_e("temperature_sensor_enable failed"); + } + } + return initialized; +} + +float temperatureRead() +{ + float result = NAN; + if(temperatureReadInit()){ + if(temperature_sensor_get_celsius(temp_sensor, &result) != ESP_OK){ + log_e("temperature_sensor_get_celsius failed"); + } + } + return result; +} +#endif + +void __yield() +{ + vPortYield(); +} + +void yield() __attribute__ ((weak, alias("__yield"))); + +#if CONFIG_AUTOSTART_ARDUINO + +extern TaskHandle_t loopTaskHandle; +extern bool loopTaskWDTEnabled; + +void enableLoopWDT(){ + if(loopTaskHandle != NULL){ + if(esp_task_wdt_add(loopTaskHandle) != ESP_OK){ + log_e("Failed to add loop task to WDT"); + } else { + loopTaskWDTEnabled = true; + } + } +} + +void disableLoopWDT(){ + if(loopTaskHandle != NULL && loopTaskWDTEnabled){ + loopTaskWDTEnabled = false; + if(esp_task_wdt_delete(loopTaskHandle) != ESP_OK){ + log_e("Failed to remove loop task from WDT"); + } + } +} + +void feedLoopWDT(){ + esp_err_t err = esp_task_wdt_reset(); + if(err != ESP_OK){ + log_e("Failed to feed WDT! Error: %d", err); + } +} +#endif + +void enableCore0WDT(){ + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK){ + log_e("Failed to add Core 0 IDLE task to WDT"); + } +} + +void disableCore0WDT(){ + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK){ + log_e("Failed to remove Core 0 IDLE task from WDT"); + } +} + +#ifndef CONFIG_FREERTOS_UNICORE +void enableCore1WDT(){ + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK){ + log_e("Failed to add Core 1 IDLE task to WDT"); + } +} + +void disableCore1WDT(){ + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK){ + log_e("Failed to remove Core 1 IDLE task from WDT"); + } +} +#endif + +BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + const BaseType_t xCoreID ){ +#ifndef CONFIG_FREERTOS_UNICORE + if(xCoreID >= 0 && xCoreID < 2) { + return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID); + } else { +#endif + return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); +#ifndef CONFIG_FREERTOS_UNICORE + } +#endif +} + +unsigned long ARDUINO_ISR_ATTR micros() +{ + return (unsigned long) (esp_timer_get_time()); +} + +unsigned long ARDUINO_ISR_ATTR millis() +{ + return (unsigned long) (esp_timer_get_time() / 1000ULL); +} + +void delay(uint32_t ms) +{ + vTaskDelay(ms / portTICK_PERIOD_MS); +} + +void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us) +{ + uint64_t m = (uint64_t)esp_timer_get_time(); + if(us){ + uint64_t e = (m + us); + if(m > e){ //overflow + while((uint64_t)esp_timer_get_time() > e){ + NOP(); + } + } + while((uint64_t)esp_timer_get_time() < e){ + NOP(); + } + } +} + +void initVariant() __attribute__((weak)); +void initVariant() {} + +void init() __attribute__((weak)); +void init() {} + +#ifdef CONFIG_APP_ROLLBACK_ENABLE +bool verifyOta() __attribute__((weak)); +bool verifyOta() { return true; } + +bool verifyRollbackLater() __attribute__((weak)); +bool verifyRollbackLater() { return false; } +#endif + +#ifdef CONFIG_BT_ENABLED +#if CONFIG_IDF_TARGET_ESP32 +//overwritten in esp32-hal-bt.c +bool btInUse() __attribute__((weak)); +bool btInUse(){ return false; } +#else +//from esp32-hal-bt.c +extern bool btInUse(); +#endif +#endif + +void initArduino() +{ + //init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz) + //ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1; +#ifdef F_CPU + setCpuFrequencyMhz(F_CPU/1000000); +#endif +#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM + psramInit(); +#endif +#ifdef CONFIG_APP_ROLLBACK_ENABLE + if(!verifyRollbackLater()){ + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_ota_img_states_t ota_state; + if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) { + if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) { + if (verifyOta()) { + esp_ota_mark_app_valid_cancel_rollback(); + } else { + log_e("OTA verification failed! Start rollback to the previous version ..."); + esp_ota_mark_app_invalid_rollback_and_reboot(); + } + } + } + } +#endif + esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL); + esp_err_t err = nvs_flash_init(); + if(err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND){ + const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + if (partition != NULL) { + err = esp_partition_erase_range(partition, 0, partition->size); + if(!err){ + err = nvs_flash_init(); + } else { + log_e("Failed to format the broken NVS partition!"); + } + } else { + log_e("Could not find NVS partition"); + } + } + if(err) { + log_e("Failed to initialize NVS! Error: %u", err); + } +#ifdef CONFIG_BT_ENABLED + if(!btInUse()){ + esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); + } +#endif + init(); + initVariant(); +} + +//used by hal log +const char * ARDUINO_ISR_ATTR pathToFileName(const char * path) +{ + size_t i = 0; + size_t pos = 0; + char * p = (char *)path; + while(*p){ + i++; + if(*p == '/' || *p == '\\'){ + pos = i; + } + p++; + } + return path+pos; +} + +#include "esp_rom_sys.h" +#include "esp_debug_helpers.h" +#if CONFIG_IDF_TARGET_ARCH_XTENSA +#include "esp_cpu_utils.h" +#else +#include "riscv/rvruntime-frames.h" +#endif +#include "esp_memory_utils.h" +#include "esp_private/panic_internal.h" + +static arduino_panic_handler_t _panic_handler = NULL; +static void * _panic_handler_arg = NULL; + +void set_arduino_panic_handler(arduino_panic_handler_t handler, void * arg){ + _panic_handler = handler; + _panic_handler_arg = arg; +} + +arduino_panic_handler_t get_arduino_panic_handler(void){ + return _panic_handler; +} + +void * get_arduino_panic_handler_arg(void){ + return _panic_handler_arg; +} + +static void handle_custom_backtrace(panic_info_t* info){ + arduino_panic_info_t p_info; + p_info.reason = info->reason; + p_info.core = info->core; + p_info.pc = info->addr; + p_info.backtrace_len = 0; + p_info.backtrace_corrupt = false; + p_info.backtrace_continues = false; + +#if CONFIG_IDF_TARGET_ARCH_XTENSA + XtExcFrame *xt_frame = (XtExcFrame *) info->frame; + esp_backtrace_frame_t stk_frame = {.pc = xt_frame->pc, .sp = xt_frame->a1, .next_pc = xt_frame->a0, .exc_frame = xt_frame}; + uint32_t i = 100, pc_ptr = esp_cpu_process_stack_pc(stk_frame.pc); + p_info.backtrace[p_info.backtrace_len++] = pc_ptr; + + bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) && + (esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) || + /* Ignore the first corrupted PC in case of InstrFetchProhibited */ + (stk_frame.exc_frame && ((XtExcFrame *)stk_frame.exc_frame)->exccause == EXCCAUSE_INSTR_PROHIBITED))); + + while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { + if (!esp_backtrace_get_next_frame(&stk_frame)) { + corrupted = true; + } + pc_ptr = esp_cpu_process_stack_pc(stk_frame.pc); + if(esp_ptr_executable((void *)pc_ptr)){ + p_info.backtrace[p_info.backtrace_len++] = pc_ptr; + if(p_info.backtrace_len == 60){ + break; + } + } + } + + if (corrupted) { + p_info.backtrace_corrupt = true; + } else if (stk_frame.next_pc != 0) { + p_info.backtrace_continues = true; + } +#elif CONFIG_IDF_TARGET_ARCH_RISCV + uint32_t sp = (uint32_t)((RvExcFrame *)info->frame)->sp; + p_info.backtrace[p_info.backtrace_len++] = sp; + uint32_t *spptr = (uint32_t *)(sp); + for (int i = 0; i < 256; i++){ + if(esp_ptr_executable((void *)spptr[i])){ + p_info.backtrace[p_info.backtrace_len++] = spptr[i]; + if(p_info.backtrace_len == 60){ + if(i < 255){ + p_info.backtrace_continues = true; + } + break; + } + } + } +#endif + _panic_handler(&p_info, _panic_handler_arg); +} + +void __real_esp_panic_handler(panic_info_t*); +void __wrap_esp_panic_handler(panic_info_t* info) { + if(_panic_handler != NULL){ + handle_custom_backtrace(info); + } + __real_esp_panic_handler(info); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-periman.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-periman.c new file mode 100644 index 0000000..f4c7ca8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-periman.c @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32-hal-log.h" +#include "esp32-hal-periman.h" +#include "esp_bit_defs.h" + +typedef struct { + peripheral_bus_type_t type; + void * bus; +} peripheral_pin_item_t; + +static peripheral_bus_deinit_cb_t deinit_functions[ESP32_BUS_TYPE_MAX]; +static peripheral_pin_item_t pins[SOC_GPIO_PIN_COUNT]; + +#define GPIO_NOT_VALID(p) ((p >= SOC_GPIO_PIN_COUNT) || ((SOC_GPIO_VALID_GPIO_MASK & (1ULL << p)) == 0)) + +bool perimanSetPinBus(uint8_t pin, peripheral_bus_type_t type, void * bus){ + peripheral_bus_type_t otype = ESP32_BUS_TYPE_INIT; + void * obus = NULL; + if(GPIO_NOT_VALID(pin)){ + log_e("Invalid pin: %u", pin); + return false; + } + if(type >= ESP32_BUS_TYPE_MAX){ + log_e("Invalid type: %u", (unsigned int)type); + return false; + } + if(type > ESP32_BUS_TYPE_GPIO && bus == NULL){ + log_e("Bus is NULL"); + return false; + } + if (type == ESP32_BUS_TYPE_INIT && bus != NULL){ + log_e("Can't set a Bus to INIT Type"); + return false; + } + otype = pins[pin].type; + obus = pins[pin].bus; + if(type == otype && bus == obus){ + if (type != ESP32_BUS_TYPE_INIT) { + log_i("Bus already set"); + } + return true; + } + if(obus != NULL){ + if(deinit_functions[otype] == NULL){ + log_e("Bus does not have deinit function set"); + return false; + } + if(!deinit_functions[otype](obus)){ + log_e("Previous bus failed to deinit"); + return false; + } + } + pins[pin].type = type; + pins[pin].bus = bus; + return true; +} + +void * perimanGetPinBus(uint8_t pin, peripheral_bus_type_t type){ + if(GPIO_NOT_VALID(pin)){ + log_e("Invalid pin: %u", pin); + return NULL; + } + if(type >= ESP32_BUS_TYPE_MAX || type == ESP32_BUS_TYPE_INIT){ + log_e("Invalid type: %u", (unsigned int)type); + return NULL; + } + if(pins[pin].type == type){ + return pins[pin].bus; + } + return NULL; +} + +peripheral_bus_type_t perimanGetPinBusType(uint8_t pin){ + if(GPIO_NOT_VALID(pin)){ + log_e("Invalid pin: %u", pin); + return ESP32_BUS_TYPE_MAX; + } + return pins[pin].type; +} + +bool perimanSetBusDeinit(peripheral_bus_type_t type, peripheral_bus_deinit_cb_t cb){ + if(type >= ESP32_BUS_TYPE_MAX || type == ESP32_BUS_TYPE_INIT){ + log_e("Invalid type: %u", (unsigned int)type); + return false; + } + if(cb == NULL){ + log_e("Callback is NULL"); + return false; + } + deinit_functions[type] = cb; + return true; +} + +bool perimanPinIsValid(uint8_t pin){ + return !(GPIO_NOT_VALID(pin)); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-periman.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-periman.h new file mode 100644 index 0000000..94e8098 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-periman.h @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "soc/soc_caps.h" +#include +#include +#include + +typedef enum { + ESP32_BUS_TYPE_INIT, // IO has not been attached to a bus yet + ESP32_BUS_TYPE_GPIO, // IO is used as GPIO + ESP32_BUS_TYPE_UART_RX, // IO is used as UART RX pin + ESP32_BUS_TYPE_UART_TX, // IO is used as UART TX pin + ESP32_BUS_TYPE_UART_CTS, // IO is used as UART CTS pin + ESP32_BUS_TYPE_UART_RTS, // IO is used as UART RTS pin +#if SOC_SDM_SUPPORTED + ESP32_BUS_TYPE_SIGMADELTA, // IO is used as SigmeDelta output +#endif +#if SOC_ADC_SUPPORTED + ESP32_BUS_TYPE_ADC_ONESHOT, // IO is used as ADC OneShot input + ESP32_BUS_TYPE_ADC_CONT, // IO is used as ADC continuous input +#endif +#if SOC_DAC_SUPPORTED + ESP32_BUS_TYPE_DAC_ONESHOT, // IO is used as DAC OneShot output + ESP32_BUS_TYPE_DAC_CONT, // IO is used as DAC continuous output + ESP32_BUS_TYPE_DAC_COSINE, // IO is used as DAC cosine output +#endif +#if SOC_LEDC_SUPPORTED + ESP32_BUS_TYPE_LEDC, // IO is used as LEDC output +#endif +#if SOC_RMT_SUPPORTED + ESP32_BUS_TYPE_RMT_TX, // IO is used as RMT output + ESP32_BUS_TYPE_RMT_RX, // IO is used as RMT input +#endif +#if SOC_I2S_SUPPORTED + ESP32_BUS_TYPE_I2S_STD, // IO is used as I2S STD pin + ESP32_BUS_TYPE_I2S_PDM, // IO is used as I2S PDM pin + ESP32_BUS_TYPE_I2S_TDM, // IO is used as I2S TDM pin +#endif +#if SOC_I2C_SUPPORTED + ESP32_BUS_TYPE_I2C_MASTER, // IO is used as I2C master pin + ESP32_BUS_TYPE_I2C_SLAVE, // IO is used as I2C slave pin +#endif +#if SOC_GPSPI_SUPPORTED + ESP32_BUS_TYPE_SPI_MASTER, // IO is used as SPI master pin +#endif +#if SOC_SDMMC_HOST_SUPPORTED + ESP32_BUS_TYPE_SDMMC, // IO is used as SDMMC pin +#endif +#if SOC_TOUCH_SENSOR_SUPPORTED + ESP32_BUS_TYPE_TOUCH, // IO is used as TOUCH pin +#endif +#if SOC_USB_SERIAL_JTAG_SUPPORTED || SOC_USB_OTG_SUPPORTED + ESP32_BUS_TYPE_USB, // IO is used as USB pin +#endif +#if SOC_GPSPI_SUPPORTED + ESP32_BUS_TYPE_ETHERNET, // IO is used as ETHERNET-RMII pin +#endif + ESP32_BUS_TYPE_MAX +} peripheral_bus_type_t; + +typedef bool (*peripheral_bus_deinit_cb_t)(void * bus); + +// Sets the bus type and bus handle for given pin. +bool perimanSetPinBus(uint8_t pin, peripheral_bus_type_t type, void * bus); + +// Returns handle of the bus for the given pin if type of bus matches. NULL otherwise +void * perimanGetPinBus(uint8_t pin, peripheral_bus_type_t type); + +// Returns the type of the bus for the given pin if attached. ESP32_BUS_TYPE_MAX otherwise +peripheral_bus_type_t perimanGetPinBusType(uint8_t pin); + +// Sets the peripheral destructor callback. Used to destroy bus when pin is assigned another function +bool perimanSetBusDeinit(peripheral_bus_type_t type, peripheral_bus_deinit_cb_t cb); + +// Check if given pin is a valid GPIO number +bool perimanPinIsValid(uint8_t pin); + +#ifdef __cplusplus +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-psram.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-psram.c new file mode 100644 index 0000000..0fda6e0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-psram.c @@ -0,0 +1,144 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal.h" + +#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM +#include "soc/efuse_reg.h" +#include "esp_heap_caps.h" + +#include "esp_system.h" +#include "esp_psram.h" +#include "esp_private/esp_psram_extram.h" +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/cache.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/cache.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/cache.h" +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif + +static volatile bool spiramDetected = false; +static volatile bool spiramFailed = false; + +//allows user to bypass SPI RAM test routine +__attribute__((weak)) bool testSPIRAM(void) +{ + return esp_psram_extram_test(); +} + + +bool psramInit(){ + if (spiramDetected) { + return true; + } +#ifndef CONFIG_SPIRAM_BOOT_INIT + if (spiramFailed) { + return false; + } +#if CONFIG_IDF_TARGET_ESP32 + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_PACKAGE); + uint32_t pkg_ver = chip_ver & 0x7; + if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) { + spiramFailed = true; + log_w("PSRAM not supported!"); + return false; + } +#elif CONFIG_IDF_TARGET_ESP32S2 + extern void esp_config_data_cache_mode(void); + esp_config_data_cache_mode(); + Cache_Enable_DCache(0); +#endif + if (esp_psram_init() != ESP_OK) { + spiramFailed = true; + log_w("PSRAM init failed!"); +#if CONFIG_IDF_TARGET_ESP32 + if (pkg_ver != EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) { + pinMatrixOutDetach(16, false, false); + pinMatrixOutDetach(17, false, false); + } +#endif + return false; + } + + //testSPIRAM() allows user to bypass SPI RAM test routine + if (!testSPIRAM()) { + spiramFailed = true; + log_e("PSRAM test failed!"); + return false; + } + if (esp_psram_extram_add_to_heap_allocator() != ESP_OK) { + spiramFailed = true; + log_e("PSRAM could not be added to the heap!"); + return false; + } +#if CONFIG_SPIRAM_USE_MALLOC && !CONFIG_ARDUINO_ISR_IRAM + heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); +#endif +#endif /* CONFIG_SPIRAM_BOOT_INIT */ + log_i("PSRAM enabled"); + spiramDetected = true; + return true; +} + +bool ARDUINO_ISR_ATTR psramFound(){ + return spiramDetected; +} + +void ARDUINO_ISR_ATTR *ps_malloc(size_t size){ + if(!spiramDetected){ + return NULL; + } + return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); +} + +void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){ + if(!spiramDetected){ + return NULL; + } + return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); +} + +void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){ + if(!spiramDetected){ + return NULL; + } + return heap_caps_realloc(ptr, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); +} + +#else + +bool psramInit(){ + return false; +} + +bool ARDUINO_ISR_ATTR psramFound(){ + return false; +} + +void ARDUINO_ISR_ATTR *ps_malloc(size_t size){ + return NULL; +} + +void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){ + return NULL; +} + +void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){ + return NULL; +} + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-psram.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-psram.h new file mode 100644 index 0000000..0ba6763 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-psram.h @@ -0,0 +1,44 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP32_HAL_PSRAM_H_ +#define _ESP32_HAL_PSRAM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sdkconfig.h" + +#ifndef BOARD_HAS_PSRAM +#ifdef CONFIG_SPIRAM_SUPPORT +#undef CONFIG_SPIRAM_SUPPORT +#endif +#ifdef CONFIG_SPIRAM +#undef CONFIG_SPIRAM +#endif +#endif + +bool psramInit(); +bool psramFound(); + +void *ps_malloc(size_t size); +void *ps_calloc(size_t n, size_t size); +void *ps_realloc(void *ptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP32_HAL_PSRAM_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rgb-led.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rgb-led.c new file mode 100644 index 0000000..c74c812 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rgb-led.c @@ -0,0 +1,44 @@ +#include "esp32-hal-rgb-led.h" + + +void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val){ + rmt_data_t led_data[24]; + static bool initialized = false; + + uint8_t _pin = pin; +#ifdef RGB_BUILTIN + if(pin == RGB_BUILTIN){ + _pin = RGB_BUILTIN - SOC_GPIO_PIN_COUNT; + } +#endif + + if(!initialized){ + if (!rmtInit(_pin, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)){ + log_e("RGB LED driver initialization failed!"); + return; + } + initialized = true; + } + + int color[] = {green_val, red_val, blue_val}; // Color coding is in order GREEN, RED, BLUE + int i = 0; + for(int col=0; col<3; col++ ){ + for(int bit=0; bit<8; bit++){ + if((color[col] & (1<<(7-bit)))){ + // HIGH bit + led_data[i].level0 = 1; // T1H + led_data[i].duration0 = 8; // 0.8us + led_data[i].level1 = 0; // T1L + led_data[i].duration1 = 4; // 0.4us + }else{ + // LOW bit + led_data[i].level0 = 1; // T0H + led_data[i].duration0 = 4; // 0.4us + led_data[i].level1 = 0; // T0L + led_data[i].duration1 = 8; // 0.8us + } + i++; + } + } + rmtWrite(_pin, led_data, RMT_SYMBOLS_OF(led_data), RMT_WAIT_FOR_EVER); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rgb-led.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rgb-led.h new file mode 100644 index 0000000..f3539a2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rgb-led.h @@ -0,0 +1,20 @@ +#ifndef MAIN_ESP32_HAL_RGB_LED_H_ +#define MAIN_ESP32_HAL_RGB_LED_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp32-hal.h" + +#ifndef RGB_BRIGHTNESS + #define RGB_BRIGHTNESS 64 +#endif + +void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val); + +#ifdef __cplusplus +} +#endif + +#endif /* MAIN_ESP32_HAL_RGB_LED_H_ */ \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rmt.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rmt.c new file mode 100644 index 0000000..9131970 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rmt.c @@ -0,0 +1,598 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/soc_caps.h" + +#if SOC_RMT_SUPPORTED +#include "esp32-hal.h" +#include "driver/gpio.h" +#include "driver/rmt_tx.h" +#include "driver/rmt_rx.h" +#include "hal/rmt_ll.h" + +#include "esp32-hal-rmt.h" +#include "esp32-hal-periman.h" + +// Arduino Task Handle indicates if the Arduino Task has been started already +extern TaskHandle_t loopTaskHandle; + +// RMT Events +#define RMT_FLAG_RX_DONE (1) +#define RMT_FLAG_TX_DONE (2) + +/** + Internal macros +*/ + +#if CONFIG_DISABLE_HAL_LOCKS +# define RMT_MUTEX_LOCK(busptr) +# define RMT_MUTEX_UNLOCK(busptr) +#else +# define RMT_MUTEX_LOCK(busptr) do {} while (xSemaphoreTake(busptr->g_rmt_objlocks, portMAX_DELAY) != pdPASS) +# define RMT_MUTEX_UNLOCK(busptr) xSemaphoreGive(busptr->g_rmt_objlocks) +#endif /* CONFIG_DISABLE_HAL_LOCKS */ + + +/** + Typedefs for internal stuctures, enums +*/ + +struct rmt_obj_s { + // general RMT information + rmt_channel_handle_t rmt_channel_h; // IDF RMT channel handler + rmt_encoder_handle_t rmt_copy_encoder_h; // RMT simple copy encoder handle + + uint32_t signal_range_min_ns; // RX Filter data - Low Pass pulse width + uint32_t signal_range_max_ns; // RX idle time that defines end of reading + + EventGroupHandle_t rmt_events; // read/write done event RMT callback handle + bool rmt_ch_is_looping; // Is this RMT TX Channel in LOOPING MODE? + size_t *num_symbols_read; // Pointer to the number of RMT symbol read by IDF RMT RX Done + uint32_t frequency_Hz; // RMT Frequency + +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t g_rmt_objlocks; // Channel Semaphore Lock +#endif /* CONFIG_DISABLE_HAL_LOCKS */ +}; + +typedef struct rmt_obj_s *rmt_bus_handle_t; + +/** + Internal variables used in RMT API +*/ +static SemaphoreHandle_t g_rmt_block_lock = NULL; + +/** + Internal method (private) declarations +*/ + +// This is called from an IDF ISR code, therefore this code is part of an ISR +static bool _rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *data, void *args) +{ + BaseType_t high_task_wakeup = pdFALSE; + rmt_bus_handle_t bus = (rmt_bus_handle_t) args; + // sets the returning number of RMT symbols (32 bits) effectively read + *bus->num_symbols_read = data->num_symbols; + // set RX event group and signal the received RMT symbols of that channel + xEventGroupSetBitsFromISR(bus->rmt_events, RMT_FLAG_RX_DONE, &high_task_wakeup); + // A "need to yield" is returned in order to execute portYIELD_FROM_ISR() in the main IDF RX ISR + return high_task_wakeup == pdTRUE; +} + +// This is called from an IDF ISR code, therefore this code is part of an ISR +static bool _rmt_tx_done_callback(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *data, void *args) +{ + BaseType_t high_task_wakeup = pdFALSE; + rmt_bus_handle_t bus = (rmt_bus_handle_t) args; + // set RX event group and signal the received RMT symbols of that channel + xEventGroupSetBitsFromISR(bus->rmt_events, RMT_FLAG_TX_DONE, &high_task_wakeup); + // A "need to yield" is returned in order to execute portYIELD_FROM_ISR() in the main IDF RX ISR + return high_task_wakeup == pdTRUE; +} + +// This function must be called only after checking the pin and its bus with _rmtGetBus() +static bool _rmtCheckDirection(uint8_t gpio_num, rmt_ch_dir_t rmt_dir, const char* labelFunc) +{ + // gets bus RMT direction from the Peripheral Manager information + rmt_ch_dir_t bus_rmt_dir = perimanGetPinBusType(gpio_num) == ESP32_BUS_TYPE_RMT_TX ? RMT_TX_MODE : RMT_RX_MODE; + + if (bus_rmt_dir == rmt_dir) { // matches expected RX/TX channel + return true; + } + + // print error message + if (rmt_dir == RMT_RX_MODE) { + log_w("==>%s():Channel set as TX instead of RX.", labelFunc); + } else { + log_w("==>%s():Channel set as RX instead of TX.", labelFunc); + } + return false; // mismatched +} + +static rmt_bus_handle_t _rmtGetBus(int pin, const char* labelFunc) +{ + // Is pin RX or TX? Let's find it out + peripheral_bus_type_t rmt_bus_type = perimanGetPinBusType(pin); + if (rmt_bus_type != ESP32_BUS_TYPE_RMT_TX && rmt_bus_type != ESP32_BUS_TYPE_RMT_RX) { + log_e("==>%s():GPIO %u is not attached to an RMT channel.", labelFunc, pin); + return NULL; + } + + return (rmt_bus_handle_t)perimanGetPinBus(pin, rmt_bus_type); +} + +// Peripheral Manager detach callback +static bool _rmtDetachBus(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_rmtDetachBus bus NULL pointer."); + + bool retCode = true; + rmt_bus_handle_t bus = (rmt_bus_handle_t) busptr; + log_v("Detaching RMT GPIO Bus"); + + // lock it + while (xSemaphoreTake(g_rmt_block_lock, portMAX_DELAY) != pdPASS) {} + + // free Event Group + if (bus->rmt_events != NULL) { + vEventGroupDelete(bus->rmt_events); + bus->rmt_events = NULL; + } + // deallocate the channel encoder + if (bus->rmt_copy_encoder_h != NULL) { + if (ESP_OK != rmt_del_encoder(bus->rmt_copy_encoder_h)) { + log_w("RMT Encoder Deletion has failed."); + retCode = false; + } + } + // disable and deallocate RMT channel + if (bus->rmt_channel_h != NULL) { + // force stopping rmt TX/RX processing and unlock Power Management (APB Freq) + rmt_disable(bus->rmt_channel_h); + if (ESP_OK != rmt_del_channel(bus->rmt_channel_h)) { + log_w("RMT Channel Deletion has failed."); + retCode = false; + } + } +#if !CONFIG_DISABLE_HAL_LOCKS + // deallocate channel semaphore + if (bus->g_rmt_objlocks != NULL) { + vSemaphoreDelete(bus->g_rmt_objlocks); + } +#endif + // free the allocated bus data structure + free(bus); + + // release the mutex + xSemaphoreGive(g_rmt_block_lock); + return retCode; +} + +/** + Public method definitions +*/ + +bool rmtSetCarrier(int pin, bool carrier_en, bool carrier_level, uint32_t frequency_Hz, float duty_percent) +{ + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + + if (duty_percent > 1) { + log_w("GPIO %d - RMT Carrier must be a float percentage from 0 to 1. Setting to 50%.", pin); + duty_percent = 0.5; + } + rmt_carrier_config_t carrier_cfg = {0}; + carrier_cfg.duty_cycle = duty_percent; // duty cycle + carrier_cfg.frequency_hz = carrier_en ? frequency_Hz : 0; // carrier frequency in Hz + carrier_cfg.flags.polarity_active_low = carrier_level; // carrier modulation polarity level + + bool retCode = true; + RMT_MUTEX_LOCK(bus); + // modulate carrier to TX channel + if (ESP_OK != rmt_apply_carrier(bus->rmt_channel_h, &carrier_cfg)) { + log_w("GPIO %d - Error applying RMT carrier.", pin); + retCode = false; + } + RMT_MUTEX_UNLOCK(bus); + + return retCode; +} + +bool rmtSetRxMinThreshold(int pin, uint8_t filter_pulse_ticks) +{ + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + + if (!_rmtCheckDirection(pin, RMT_RX_MODE, __FUNCTION__)) { + return false; + } + + uint32_t filter_pulse_ns = (1000000000 / bus->frequency_Hz) * filter_pulse_ticks; + // RMT_LL_MAX_FILTER_VALUE is 255 for ESP32, S2, S3, C3, C6 and H2; + // filter_pulse_ticks is 8 bits, thus it will not exceed 255 +#if 0 // for the future, in case some other SoC has different limit + if (filter_pulse_ticks > RMT_LL_MAX_FILTER_VALUE) { + log_e("filter_pulse_ticks is too big. Max = %d", RMT_LL_MAX_FILTER_VALUE); + return false; + } +#endif + + RMT_MUTEX_LOCK(bus); + bus->signal_range_min_ns = filter_pulse_ns; // set zero to disable it + RMT_MUTEX_UNLOCK(bus); + return true; +} + +bool rmtSetRxMaxThreshold(int pin, uint16_t idle_thres_ticks) +{ + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + + if (!_rmtCheckDirection(pin, RMT_RX_MODE, __FUNCTION__)) { + return false; + } + + uint32_t idle_thres_ns = (1000000000 / bus->frequency_Hz) * idle_thres_ticks; + // RMT_LL_MAX_IDLE_VALUE is 65535 for ESP32,S2 and 32767 for S3, C3, C6 and H2 +#if RMT_LL_MAX_IDLE_VALUE < 65535 // idle_thres_ticks is 16 bits anyway - save some bytes + if (idle_thres_ticks > RMT_LL_MAX_IDLE_VALUE) { + log_e("idle_thres_ticks is too big. Max = %ld", RMT_LL_MAX_IDLE_VALUE); + return false; + } +#endif + + RMT_MUTEX_LOCK(bus); + bus->signal_range_max_ns = idle_thres_ns; + RMT_MUTEX_UNLOCK(bus); + return true; +} + +bool rmtDeinit(int pin) +{ + log_v("Deiniting RMT GPIO %d", pin); + if (_rmtGetBus(pin, __FUNCTION__) != NULL) { + // release all allocated data + return perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL); + } + log_e("GPIO %d - No RMT channel associated.", pin); + return false; +} + +static bool _rmtWrite(int pin, rmt_data_t* data, size_t num_rmt_symbols, bool blocking, bool loop, uint32_t timeout_ms) +{ + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + if (!_rmtCheckDirection(pin, RMT_TX_MODE, __FUNCTION__)) { + return false; + } + bool loopCancel = false; // user wants to cancel the writing loop mode + if (data == NULL || num_rmt_symbols == 0) { + if (!loop) { + log_w("GPIO %d - RMT Write Data NULL pointer or size is zero.", pin); + return false; + } else { + loopCancel = true; + } + } + + log_v("GPIO: %d - Request: %d RMT Symbols - %s - Timeout: %d", pin, num_rmt_symbols, blocking ? "Blocking" : "Non-Blocking", timeout_ms); + log_v("GPIO: %d - Currently in Loop Mode: [%s] | Asked to Loop: %s, LoopCancel: %s", pin, bus->rmt_ch_is_looping ? "YES" : "NO", loop ? "YES" : "NO", loopCancel ? "YES" : "NO"); + + if ((xEventGroupGetBits(bus->rmt_events) & RMT_FLAG_TX_DONE) == 0) { + log_v("GPIO %d - RMT Write still pending to be completed.", pin); + return false; + } + + rmt_transmit_config_t transmit_cfg = {0}; // loop mode disabled + bool retCode = true; + + RMT_MUTEX_LOCK(bus); + // wants to start in writing or looping over a previous looping --> resets the channel + if (bus->rmt_ch_is_looping == true) { + // must force stopping a previous loop transmission first + rmt_disable(bus->rmt_channel_h); + // enable it again for looping or writing + rmt_enable(bus->rmt_channel_h); + bus->rmt_ch_is_looping = false; // not looping anymore + } + if (loopCancel) { + // just resets and releases the channel, maybe, already done above, then exits + bus->rmt_ch_is_looping = false; + } else { // new writing | looping request + // looping | Writing over a previous looping state is valid + if (loop) { + transmit_cfg.loop_count = -1; // enable infinite loop mode + // keeps RMT_FLAG_TX_DONE set - it never changes + } else { + // looping mode never sets this flag (IDF 5.1) in the callback + xEventGroupClearBits(bus->rmt_events, RMT_FLAG_TX_DONE); + } + // transmits just once or looping data + if (ESP_OK != rmt_transmit(bus->rmt_channel_h, bus->rmt_copy_encoder_h, + (const void *) data, num_rmt_symbols * sizeof(rmt_data_t), &transmit_cfg)) { + retCode = false; + log_w("GPIO %d - RMT Transmission failed.", pin); + } else { // transmit OK + if (loop) { + bus->rmt_ch_is_looping = true; // for ever... until a channel canceling or new writing + } else { + if (blocking) { + // wait for transmission confirmation | timeout + retCode = (xEventGroupWaitBits(bus->rmt_events, RMT_FLAG_TX_DONE, pdFALSE /* do not clear on exit */, + pdFALSE /* wait for all bits */, timeout_ms) & RMT_FLAG_TX_DONE) != 0; + } + } + } + } + RMT_MUTEX_UNLOCK(bus); + return retCode; +} + +static bool _rmtRead(int pin, rmt_data_t* data, size_t *num_rmt_symbols, bool waitForData, uint32_t timeout_ms) +{ + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + if (!_rmtCheckDirection(pin, RMT_RX_MODE, __FUNCTION__)) { + return false; + } + if (data == NULL || num_rmt_symbols == NULL) { + log_w("GPIO %d - RMT Read Data and/or Size NULL pointer.", pin); + return false; + } + log_v("GPIO: %d - Request: %d RMT Symbols - %s - Timeout: %d", pin, *num_rmt_symbols, waitForData ? "Blocking" : "Non-Blocking", timeout_ms); + bool retCode = true; + RMT_MUTEX_LOCK(bus); + + // request reading RMT Channel Data + rmt_receive_config_t receive_config; + receive_config.signal_range_min_ns = bus->signal_range_min_ns; + receive_config.signal_range_max_ns = bus->signal_range_max_ns; + + xEventGroupClearBits(bus->rmt_events, RMT_FLAG_RX_DONE); + bus->num_symbols_read = num_rmt_symbols; + + rmt_receive(bus->rmt_channel_h, data, *num_rmt_symbols * sizeof(rmt_data_t), &receive_config); + // wait for data if requested + if (waitForData) { + retCode = (xEventGroupWaitBits(bus->rmt_events, RMT_FLAG_RX_DONE, pdFALSE /* do not clear on exit */, + pdFALSE /* wait for all bits */, timeout_ms) & RMT_FLAG_RX_DONE) != 0; + } + + RMT_MUTEX_UNLOCK(bus); + return retCode; +} + + +bool rmtWrite(int pin, rmt_data_t *data, size_t num_rmt_symbols, uint32_t timeout_ms) { + return _rmtWrite(pin, data, num_rmt_symbols, true /*blocks*/, false /*looping*/, timeout_ms); +} + +bool rmtWriteAsync(int pin, rmt_data_t *data, size_t num_rmt_symbols) { + return _rmtWrite(pin, data, num_rmt_symbols, false /*blocks*/, false /*looping*/, 0 /*N/A*/); +} + +bool rmtWriteLooping(int pin, rmt_data_t* data, size_t num_rmt_symbols) { + return _rmtWrite(pin, data, num_rmt_symbols, false /*blocks*/, true /*looping*/, 0 /*N/A*/); +} + +bool rmtTransmitCompleted(int pin) { + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + if (!_rmtCheckDirection(pin, RMT_TX_MODE, __FUNCTION__)) { + return false; + } + + bool retCode = true; + RMT_MUTEX_LOCK(bus); + retCode = (xEventGroupGetBits(bus->rmt_events) & RMT_FLAG_TX_DONE) != 0; + RMT_MUTEX_UNLOCK(bus); + return retCode; +} + +bool rmtRead(int pin, rmt_data_t* data, size_t *num_rmt_symbols, uint32_t timeout_ms) { + return _rmtRead(pin, data, num_rmt_symbols, true /* blocking */, timeout_ms); +} + +bool rmtReadAsync(int pin, rmt_data_t* data, size_t *num_rmt_symbols) { + return _rmtRead(pin, data, num_rmt_symbols, false /* non-blocking */, 0 /* N/A */); +} + +bool rmtReceiveCompleted(int pin) { + rmt_bus_handle_t bus = _rmtGetBus(pin, __FUNCTION__); + if (bus == NULL) { + return false; + } + if (!_rmtCheckDirection(pin, RMT_RX_MODE, __FUNCTION__)) { + return false; + } + + bool retCode = true; + RMT_MUTEX_LOCK(bus); + retCode = (xEventGroupGetBits(bus->rmt_events) & RMT_FLAG_RX_DONE) != 0; + RMT_MUTEX_UNLOCK(bus); + return retCode; +} + +bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_size, uint32_t frequency_Hz) +{ + log_v("GPIO %d - %s - MemSize[%d] - Freq=%dHz", pin, channel_direction == RMT_RX_MODE ? "RX MODE" : "TX MODE", mem_size * RMT_SYMBOLS_PER_CHANNEL_BLOCK, frequency_Hz); + + // create common block mutex for protecting allocs from multiple threads allocating RMT channels + if (!g_rmt_block_lock) { + g_rmt_block_lock = xSemaphoreCreateMutex(); + if (g_rmt_block_lock == NULL) { + log_e("GPIO %d - Failed creating RMT Mutex.", pin); + return false; + } + } + + // set Peripheral Manager deInit Callback + perimanSetBusDeinit(ESP32_BUS_TYPE_RMT_TX, _rmtDetachBus); + perimanSetBusDeinit(ESP32_BUS_TYPE_RMT_RX, _rmtDetachBus); + + // check is pin is valid and in the right direction + if ((channel_direction == RMT_TX_MODE && !GPIO_IS_VALID_OUTPUT_GPIO(pin)) || (!GPIO_IS_VALID_GPIO(pin))) { + log_e("GPIO %d is not valid or can't be used for output in TX mode.", pin); + return false; + } + + // validate the RMT ticks by the requested frequency + // Based on 80Mhz using a divider of 8 bits (calculated as 1..256) + if (frequency_Hz > 80000000 || frequency_Hz < 312500) { + log_e("GPIO %d - Bad RMT frequency resolution. Must be between 312.5KHz to 80MHz.", pin); + return false; + } + + // Try to dettach any (Tx|Rx|Whatever) previous bus or just keep it as not attached + if (!perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)) { + log_w("GPIO %d - Can't detach previous peripheral.", pin); + return false; + } + + // lock it + while (xSemaphoreTake(g_rmt_block_lock, portMAX_DELAY) != pdPASS) {} + + // allocate the rmt bus object and sets all fields to NULL + rmt_bus_handle_t bus = (rmt_bus_handle_t)heap_caps_calloc(1, sizeof(struct rmt_obj_s), MALLOC_CAP_DEFAULT); + if (bus == NULL) { + log_e("GPIO %d - Bus Memory allocation fault.", pin); + goto Err; + } + + // store the RMT Freq to check Filter and Idle valid values in the RMT API + bus->frequency_Hz = frequency_Hz; + // pulses with width smaller than min_ns will be ignored (as a glitch) + bus->signal_range_min_ns = 0; // disabled + // RMT stops reading if the input stays idle for longer than max_ns + bus->signal_range_max_ns = (1000000000 / frequency_Hz) * RMT_LL_MAX_IDLE_VALUE; // maximum possible + // creates the event group to control read_done and write_done + bus->rmt_events = xEventGroupCreate(); + if (bus->rmt_events == NULL) { + log_e("GPIO %d - RMT Group Event allocation fault.", pin); + goto Err; + } + + // Starting with Receive|Transmit DONE bits set, for allowing a new request from user + xEventGroupSetBits(bus->rmt_events, RMT_FLAG_RX_DONE | RMT_FLAG_TX_DONE); + + // channel particular configuration + if (channel_direction == RMT_TX_MODE) { + // TX Channel + rmt_tx_channel_config_t tx_cfg; + tx_cfg.gpio_num = pin; + // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2 + tx_cfg.clk_src = RMT_CLK_SRC_DEFAULT; + tx_cfg.resolution_hz = frequency_Hz; + tx_cfg.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * mem_size; + tx_cfg.trans_queue_depth = 10; // maximum allowed + tx_cfg.flags.invert_out = 0; + tx_cfg.flags.with_dma = 0; + tx_cfg.flags.io_loop_back = 0; + tx_cfg.flags.io_od_mode = 0; + + if (rmt_new_tx_channel(&tx_cfg, &bus->rmt_channel_h) != ESP_OK) { + log_e("GPIO %d - RMT TX Initialization error.", pin); + goto Err; + } + + // set TX Callback + rmt_tx_event_callbacks_t cbs = { .on_trans_done = _rmt_tx_done_callback }; + if (ESP_OK != rmt_tx_register_event_callbacks(bus->rmt_channel_h, &cbs, bus)) { + log_e("GPIO %d RMT - Error registering TX Callback.", pin); + goto Err; + } + + } else { + // RX Channel + rmt_rx_channel_config_t rx_cfg; + rx_cfg.gpio_num = pin; + // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2 + rx_cfg.clk_src = RMT_CLK_SRC_DEFAULT; + rx_cfg.resolution_hz = frequency_Hz; + rx_cfg.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * mem_size; + rx_cfg.flags.invert_in = 0; + rx_cfg.flags.with_dma = 0; + rx_cfg.flags.io_loop_back = 0; + // try to allocate the RMT Channel + if (ESP_OK != rmt_new_rx_channel(&rx_cfg, &bus->rmt_channel_h)) { + log_e("GPIO %d RMT - RX Initialization error.", pin); + goto Err; + } + + // set RX Callback + rmt_rx_event_callbacks_t cbs = { .on_recv_done = _rmt_rx_done_callback }; + if (ESP_OK != rmt_rx_register_event_callbacks(bus->rmt_channel_h, &cbs, bus)) { + log_e("GPIO %d RMT - Error registering RX Callback.", pin); + goto Err; + } + } + + // allocate memory for the RMT Copy encoder + rmt_copy_encoder_config_t copy_encoder_config = {}; + if (rmt_new_copy_encoder(©_encoder_config, &bus->rmt_copy_encoder_h) != ESP_OK) { + log_e("GPIO %d - RMT Encoder Memory Allocation error.", pin); + goto Err; + } + + // create each channel Mutex for multi thread operations +#if !CONFIG_DISABLE_HAL_LOCKS + bus->g_rmt_objlocks = xSemaphoreCreateMutex(); + if (bus->g_rmt_objlocks == NULL) { + log_e("GPIO %d - Failed creating RMT Channel Mutex.", pin); + goto Err; + } +#endif + + rmt_enable(bus->rmt_channel_h); // starts/enables the channel + + // Finally, allocate Peripheral Manager RMT bus and associate it to its GPIO + peripheral_bus_type_t pinBusType = + channel_direction == RMT_TX_MODE ? ESP32_BUS_TYPE_RMT_TX : ESP32_BUS_TYPE_RMT_RX; + if (!perimanSetPinBus(pin, pinBusType, (void *) bus)) { + log_e("Can't allocate the GPIO %d in the Peripheral Manager.", pin); + goto Err; + } + + // this delay is necessary when CPU frequency changes, but internal RMT setup is "old/wrong" + // The use case is related to the RMT_CPUFreq_Test example. The very first RMT Write + // goes in the wrong pace (frequency). The delay allows other IDF tasks to run to fix it. + if (loopTaskHandle != NULL) { + // it can only run when Arduino task has been already started. + delay(1); + } // prevent panic when rmtInit() is executed within an C++ object constructor + // release the mutex + xSemaphoreGive(g_rmt_block_lock); + return true; + +Err: + // release LOCK and the RMT object + xSemaphoreGive(g_rmt_block_lock); + _rmtDetachBus((void *)bus); + return false; +} + +#endif /* SOC_RMT_SUPPORTED */ \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rmt.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rmt.h new file mode 100644 index 0000000..fedc75d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-rmt.h @@ -0,0 +1,222 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MAIN_ESP32_HAL_RMT_H_ +#define MAIN_ESP32_HAL_RMT_H_ + +#include "soc/soc_caps.h" +#if SOC_RMT_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + RMT_RX_MODE = 0, // false + RMT_TX_MODE = 1, // true +} rmt_ch_dir_t; + +typedef enum { + RMT_MEM_NUM_BLOCKS_1 = 1, + RMT_MEM_NUM_BLOCKS_2 = 2, +#if SOC_RMT_TX_CANDIDATES_PER_GROUP > 2 + RMT_MEM_NUM_BLOCKS_3 = 3, + RMT_MEM_NUM_BLOCKS_4 = 4, +#if SOC_RMT_TX_CANDIDATES_PER_GROUP > 4 + RMT_MEM_NUM_BLOCKS_5 = 5, + RMT_MEM_NUM_BLOCKS_6 = 6, + RMT_MEM_NUM_BLOCKS_7 = 7, + RMT_MEM_NUM_BLOCKS_8 = 8, +#endif +#endif +} rmt_reserve_memsize_t; + +// Each RMT Symbols has 4 bytes +// Total number of bytes per RMT_MEM_BLOCK is RMT_SYMBOLS_PER_CHANNEL_BLOCK * 4 bytes +typedef union { + struct { + uint32_t duration0 : 15; + uint32_t level0 : 1; + uint32_t duration1 : 15; + uint32_t level1 : 1; + }; + uint32_t val; +} rmt_data_t; + +// Reading and Writing shall use as rmt_symbols_size this unit +// ESP32 has 8 MEM BLOCKS in total shared with Reading and/or Writing +// ESP32-S2 has 4 MEM BLOCKS in total shared with Reading and/or Writing +// ESP32-S3 has 4 MEM BLOCKS for Reading and another 4 MEM BLOCKS for Writing +// ESP32-C3 has 2 MEM BLOCKS for Reading and another 2 MEM BLOCKS for Writing +#define RMT_SYMBOLS_PER_CHANNEL_BLOCK SOC_RMT_MEM_WORDS_PER_CHANNEL + +// Used to tell rmtRead() to wait for ever until reading data from the RMT channel +#define RMT_WAIT_FOR_EVER ((uint32_t)portMAX_DELAY) + +// Helper macro to calculate the number of RTM symbols in a array or type +#define RMT_SYMBOLS_OF(x) (sizeof(x) / sizeof(rmt_data_t)) + +/** + Initialize the object + + New Parameters in Arduino Core 3: RMT tick is set in the rmtInit() function by the + frequency of the RMT channel. Example: 100ns tick => 10MHz, thus frequency will be 10,000,000 Hz + Returns on execution success, otherwise +*/ +bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t memsize, uint32_t frequency_Hz); + +/** + Sending data in Blocking Mode. + is a 32 bits structure as defined by rmt_data_t type. + It is possible to use the macro RMT_SYMBOLS_OF(data), if data is an array of . + + Blocking mode - only returns after sending all data or by timeout. + If the writing operation takes longer than in milliseconds, it will end its + execution returning . + Timeout can be set as undefined time by passing as parameter. + When the operation is timed out, rmtTransmitCompleted() will return until the transmission + is finished, when rmtTransmitCompleted() will return . + + Returns when there is no error in the write operation, otherwise, including when it + exits by timeout. +*/ +bool rmtWrite(int pin, rmt_data_t *data, size_t num_rmt_symbols, uint32_t timeout_ms); + +/** + Sending data in Async Mode. + is a 32 bits structure as defined by rmt_data_t type. + It is possible to use the macro RMT_SYMBOLS_OF(data), if is an array of + + If more than one rmtWriteAsync() is executed in sequence, it will wait for the first transmission + to finish, resulting in a return that indicates that the rmtWriteAsync() call has failed. + In such case, this channel will have to finish the previous transmission before starting a new one. + + Non-Blocking mode - returns right after execution. + Returns on execution success, otherwise. + + will return when all data is sent. +*/ +bool rmtWriteAsync(int pin, rmt_data_t *data, size_t num_rmt_symbols); + +/** + Writing data up to the reserved memsize, looping continuously + is a 32 bits structure as defined by rmt_data_t type. + It is possible to use the macro RMT_SYMBOLS_OF(data), if data is an array of rmt_data_t + + If *data or size_byte are NULL | Zero, it will disable the writing loop and stop transmission + + Non-Blocking mode - returns right after execution + Returns on execution success, otherwise + + will return always while it is looping. +*/ +bool rmtWriteLooping(int pin, rmt_data_t* data, size_t num_rmt_symbols); + +/** + Checks if transmission is completed and the rmtChannel ready for transmiting new data. + To be ready for a new transmission, means that the previous transmission is completed. + Returns when all data has been sent, otherwise. + The data transmition information is reset when a new rmtWrite/Async function is called. + If rmtWrite() times out or rmtWriteAsync() is called, this function will return until + all data is sent out. + rmtTranmitCompleted() will always return when rmtWriteLooping() is called, + beacuse it has no effect in such case. +*/ +bool rmtTransmitCompleted(int pin); + +/** + Initiates blocking receive. Read data will be stored in a user provided buffer <*data> + It will read up to RMT Symbols and the value of this variable will + change to the effective number of symbols read. + is a 32 bits structure as defined by rmt_data_t type. + + If the reading operation takes longer than in milliseconds, it will end its + execution and the function will return . In a time out scenario, won't + change and rmtReceiveCompleted() can be used latter to check if there is data available. + Timeout can be set as undefined time by passing RMT_WAIT_FOR_EVER as parameter + + Returns when there is no error in the read operation, otherwise, including when it + exits by timeout. + Returns, by value, the number of RMT Symbols read in and the user buffer + when the read operation has success within the defined . If the function times out, it + will read RMT data latter asynchronously, affecting <*data> and <*num_rmt_symbols>. After timeout, + the application can check if data is already available using +*/ +bool rmtRead(int pin, rmt_data_t* data, size_t *num_rmt_symbols, uint32_t timeout_ms); + +/** + Initiates async (non-blocking) receive. It will return immediately after execution. + Read data will be stored in a user provided buffer <*data>. + It will read up to RMT Symbols and the value of this variable will + change to the effective number of symbols read, whenever the read is completed. + is a 32 bits structure as defined by type. + + Returns when there is no error in the read operation, otherwise. + Returns asynchronously, by value, the number of RMT Symbols read, and also, it will copy + the RMT received data to the user buffer when the read operation happens. + The application can check if data is already available using +*/ +bool rmtReadAsync(int pin, rmt_data_t* data, size_t *num_rmt_symbols); + +/** + Checks if a data reception is completed and the rmtChannel has new data for processing. + Returns when data has been received, otherwise. + The data reception information is reset when a new rmtRead/Async function is called. +*/ +bool rmtReceiveCompleted(int pin); + +/** + Function used to set a threshold (in ticks) used to consider that a data reception has ended. + In receive mode, when no edge is detected on the input signal for longer than idle_thres_ticks + time, the receiving process is finished and the Data is made available by + the rmtRead/Async functions. Note that this time (in RMT channel frequency cycles) will also + define how many low/high bits are read at the end of the received data. + The function returns if it is correctly executed, otherwise. +*/ +bool rmtSetRxMaxThreshold(int pin, uint16_t idle_thres_ticks); + +/** + Parameters changed in Arduino Core 3: low and high (ticks) are now expressed in Carrier Freq in Hz and + duty cycle in percentage float 0.0 to 1.0 - example: 38.5KHz 33% High => 38500, 0.33 + + Function to set a RX demodulation carrier or TX modulation carrier + is used to enable/disable the use of demodulation/modulation for RX/TX + true means that the polarity level for the (de)modulation is positive + is the carrier frequency used + is a float deom 0 to 1 (0.5 means a square wave) of the carrier frequency + The function returns if it is correctly executed, otherwise. +*/ +bool rmtSetCarrier(int pin, bool carrier_en, bool carrier_level, uint32_t frequency_Hz, float duty_percent); + +/** + Function used to filter input noise in the RX channel. + In receiving mode, channel will ignore any input pulse which width (high or low) + is smaller than + If is Zero, it will to disable the filter. + The function returns if it is correctly executed, otherwise. +*/ +bool rmtSetRxMinThreshold(int pin, uint8_t filter_pulse_ticks); + +/** + Deinitializes the driver and releases all allocated memory + It also disables RMT for this gpio +*/ +bool rmtDeinit(int pin); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_RMT_SUPPORTED */ +#endif /* MAIN_ESP32_HAL_RMT_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-sigmadelta.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-sigmadelta.c new file mode 100644 index 0000000..7b8e3bb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-sigmadelta.c @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32-hal-sigmadelta.h" + +#if SOC_SDM_SUPPORTED +#include "esp32-hal.h" +#include "esp32-hal-periman.h" +#include "driver/sdm.h" + +static bool sigmaDeltaDetachBus(void * bus){ + esp_err_t err = sdm_channel_disable((sdm_channel_handle_t)bus); + if(err != ESP_OK){ + log_w("sdm_channel_disable failed with error: %d", err); + } + err = sdm_del_channel((sdm_channel_handle_t)bus); + if(err != ESP_OK){ + log_e("sdm_del_channel failed with error: %d", err); + return false; + } + return true; +} + +bool sigmaDeltaAttach(uint8_t pin, uint32_t freq) //freq 1220-312500 +{ + perimanSetBusDeinit(ESP32_BUS_TYPE_SIGMADELTA, sigmaDeltaDetachBus); + sdm_channel_handle_t bus = (sdm_channel_handle_t)perimanGetPinBus(pin, ESP32_BUS_TYPE_SIGMADELTA); + if(bus != NULL && !perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + bus = NULL; + sdm_config_t config = { + .gpio_num = (int)pin, + .clk_src = SDM_CLK_SRC_DEFAULT, + .sample_rate_hz = freq, + .flags = { + .invert_out = 0, + .io_loop_back = 0 + } + }; + esp_err_t err = sdm_new_channel(&config, &bus); + if(err != ESP_OK){ + log_e("sdm_new_channel failed with error: %d", err); + return false; + } + err = sdm_channel_enable(bus); + if(err != ESP_OK){ + sigmaDeltaDetachBus((void *)bus); + log_e("sdm_channel_enable failed with error: %d", err); + return false; + } + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_SIGMADELTA, (void *)bus)){ + sigmaDeltaDetachBus((void *)bus); + return false; + } + return true; +} + +bool sigmaDeltaWrite(uint8_t pin, uint8_t duty) //chan 0-x according to SOC duty 8 bit +{ + sdm_channel_handle_t bus = (sdm_channel_handle_t)perimanGetPinBus(pin, ESP32_BUS_TYPE_SIGMADELTA); + if(bus != NULL){ + int8_t d = duty - 128; + esp_err_t err = sdm_channel_set_duty(bus, d); + if(err != ESP_OK){ + log_e("sdm_channel_set_duty failed with error: %d", err); + return false; + } + return true; + } else { + log_e("pin %u is not attached to SigmaDelta", pin); + } + return false; +} + +bool sigmaDeltaDetach(uint8_t pin) +{ + void * bus = perimanGetPinBus(pin, ESP32_BUS_TYPE_SIGMADELTA); + if(bus != NULL){ + // will call sigmaDeltaDetachBus + return perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL); + } else { + log_e("pin %u is not attached to SigmaDelta", pin); + } + return false; +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-sigmadelta.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-sigmadelta.h new file mode 100644 index 0000000..41d2b3a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-sigmadelta.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_SDM_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +//freq 1220-312500 duty 0-255 +bool sigmaDeltaAttach(uint8_t pin, uint32_t freq); +bool sigmaDeltaWrite(uint8_t pin, uint8_t duty); +bool sigmaDeltaDetach(uint8_t pin); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_SDM_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-spi.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-spi.c new file mode 100644 index 0000000..a850e5e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-spi.c @@ -0,0 +1,1576 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-spi.h" + +#if SOC_GPSPI_SUPPORTED +#include "esp32-hal.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_attr.h" +#include "soc/spi_reg.h" +#include "soc/spi_struct.h" +#include "soc/io_mux_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/rtc.h" +#include "hal/clk_gate_ll.h" +#include "esp32-hal-periman.h" + +#include "esp_system.h" +#include "esp_intr_alloc.h" + +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "soc/dport_reg.h" +#include "esp32/rom/ets_sys.h" +#include "esp32/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "soc/dport_reg.h" +#include "esp32s2/rom/ets_sys.h" +#include "esp32s2/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "soc/dport_reg.h" +#include "esp32s3/rom/ets_sys.h" +#include "esp32s3/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/ets_sys.h" +#include "esp32c3/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/ets_sys.h" +#include "esp32c6/rom/gpio.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/ets_sys.h" +#include "esp32h2/rom/gpio.h" +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif + +struct spi_struct_t { + spi_dev_t * dev; +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t lock; +#endif + uint8_t num; + int8_t sck; + int8_t miso; + int8_t mosi; + int8_t ss; +}; + +#if CONFIG_IDF_TARGET_ESP32S2 +// ESP32S2 +#define SPI_COUNT (3) + +#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_MUX_IDX:((p==1)?FSPICLK_OUT_MUX_IDX:((p==2)?SPI3_CLK_OUT_MUX_IDX:0))) +#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?FSPIQ_OUT_IDX:((p==2)?SPI3_Q_OUT_IDX:0))) +#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?FSPID_IN_IDX:((p==2)?SPI3_D_IN_IDX:0))) + +#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:0)) +#define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:((n==2)?SPI3_CS2_OUT_IDX:SPI3_CS0_OUT_IDX))) +#define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX))) +#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):0))) + +#elif CONFIG_IDF_TARGET_ESP32S3 +// ESP32S3 +#define SPI_COUNT (2) + +#define SPI_CLK_IDX(p) ((p==0)?FSPICLK_OUT_IDX:((p==1)?SPI3_CLK_OUT_IDX:0)) +#define SPI_MISO_IDX(p) ((p==0)?FSPIQ_OUT_IDX:((p==1)?SPI3_Q_OUT_IDX:0)) +#define SPI_MOSI_IDX(p) ((p==0)?FSPID_IN_IDX:((p==1)?SPI3_D_IN_IDX:0)) + +#define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:0)) +#define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:0)) +#define SPI_SS_IDX(p, n) ((p==0)?SPI_FSPI_SS_IDX(n):((p==1)?SPI_HSPI_SS_IDX(n):0)) + +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +// ESP32C3 +#define SPI_COUNT (1) + +#define SPI_CLK_IDX(p) FSPICLK_OUT_IDX +#define SPI_MISO_IDX(p) FSPIQ_OUT_IDX +#define SPI_MOSI_IDX(p) FSPID_IN_IDX + +#define SPI_SPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX))) +#define SPI_SS_IDX(p, n) SPI_SPI_SS_IDX(n) + +#else +// ESP32 +#define SPI_COUNT (4) + +#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0)))) +#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0)))) +#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0)))) + +#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX))) +#define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX))) +#define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX))) +#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0)))) + +#endif + +#if CONFIG_DISABLE_HAL_LOCKS +#define SPI_MUTEX_LOCK() +#define SPI_MUTEX_UNLOCK() + +static spi_t _spi_bus_array[] = { +#if CONFIG_IDF_TARGET_ESP32S2 + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2, -1, -1, -1, -1} +#elif CONFIG_IDF_TARGET_ESP32S3 + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 1, -1, -1, -1, -1} +#elif CONFIG_IDF_TARGET_ESP32C3 + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} +#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + {(spi_dev_t *)(DR_REG_SPI2_BASE), 0, -1, -1, -1, -1} +#else + {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3, -1, -1, -1, -1} +#endif +}; +#else +#define SPI_MUTEX_LOCK() do {} while (xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS) +#define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock) + +static spi_t _spi_bus_array[] = { +#if CONFIG_IDF_TARGET_ESP32S2 + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2, -1, -1, -1, -1} +#elif CONFIG_IDF_TARGET_ESP32S3 + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 1, -1, -1, -1, -1} +#elif CONFIG_IDF_TARGET_ESP32C3 + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} +#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + {(spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 0, -1, -1, -1, -1} +#else + {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2, -1, -1, -1, -1}, + {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3, -1, -1, -1, -1} +#endif +}; +#endif + +static bool spiDetachBus(void * bus){ + uint8_t spi_num = (int)bus - 1; + spi_t * spi = &_spi_bus_array[spi_num]; + if(spi->dev->clock.val != 0){ + log_d("Stopping SPI BUS"); + spiStopBus(spi); + } + if(spi->sck != -1){ + log_d("SPI detach SCK pin %d",spi->sck); + spiDetachSCK(spi,spi->sck); + } + if(spi->miso != -1){ + log_d("SPI detach MISO pin %d",spi->miso); + spiDetachMISO(spi,spi->miso); + } + if(spi->mosi != -1){ + log_d("SPI detach MOSI pin %d",spi->mosi); + spiDetachMOSI(spi,spi->mosi); + } + if(spi->ss != -1){ + log_d("SPI detach SS pin %d",spi->ss); + spiDetachSS(spi,spi->ss); + } + //set SPI to NULL, as all pins are already detached + if(spi->sck == -1 && spi->miso == -1 && spi->mosi == -1 && spi->ss == -1){ + log_d("Set spi handle to NULL"); + spi = NULL; + return true; + } + return false; +} + + +bool spiAttachSCK(spi_t * spi, int8_t sck) +{ + if(!spi || sck < 0) { + return false; + } + void * bus = perimanGetPinBus(sck, ESP32_BUS_TYPE_SPI_MASTER); + if(bus != NULL && !perimanSetPinBus(sck, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + pinMode(sck, OUTPUT); + pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false); + spi->sck = sck; + if(!perimanSetPinBus(sck, ESP32_BUS_TYPE_SPI_MASTER, (void *)(spi->num+1))){ + spiDetachBus((void *)(spi->num+1)); + log_e("Failed to set pin bus to SPI for pin %d", sck); + return false; + } + return true; +} + +bool spiAttachMISO(spi_t * spi, int8_t miso) +{ + if(!spi || miso < 0) { + return false; + } + void * bus = perimanGetPinBus(miso, ESP32_BUS_TYPE_SPI_MASTER); + if(bus != NULL && !perimanSetPinBus(miso, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + SPI_MUTEX_LOCK(); + pinMode(miso, INPUT); + pinMatrixInAttach(miso, SPI_MISO_IDX(spi->num), false); + spi->miso = miso; + SPI_MUTEX_UNLOCK(); + if(!perimanSetPinBus(miso, ESP32_BUS_TYPE_SPI_MASTER, (void *)(spi->num+1))){ + spiDetachBus((void *)(spi->num+1)); + log_e("Failed to set pin bus to SPI for pin %d", miso); + return false; + } + return true; +} + +bool spiAttachMOSI(spi_t * spi, int8_t mosi) +{ + if(!spi || mosi < 0) { + return false; + } + void * bus = perimanGetPinBus(mosi, ESP32_BUS_TYPE_SPI_MASTER); + if(bus != NULL && !perimanSetPinBus(mosi, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + pinMode(mosi, OUTPUT); + pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false); + spi->mosi = mosi; + if(!perimanSetPinBus(mosi, ESP32_BUS_TYPE_SPI_MASTER, (void *)(spi->num+1))){ + spiDetachBus((void *)(spi->num+1)); + log_e("Failed to set pin bus to SPI for pin %d", mosi); + return false; + } + return true; +} + +bool spiDetachSCK(spi_t * spi, int8_t sck) +{ + if(!spi || sck < 0) { + return false; + } + pinMatrixOutDetach(sck, false, false); + spi->sck = -1; + perimanSetPinBus(sck, ESP32_BUS_TYPE_INIT, NULL); + return true; +} + +bool spiDetachMISO(spi_t * spi, int8_t miso) +{ + if(!spi || miso < 0) { + return false; + } + pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false); + spi->miso = -1; + perimanSetPinBus(miso, ESP32_BUS_TYPE_INIT, NULL); + return true; +} + +bool spiDetachMOSI(spi_t * spi, int8_t mosi) +{ + if(!spi || mosi < 0) { + return false; + } + pinMatrixOutDetach(mosi, false, false); + spi->mosi = -1; + perimanSetPinBus(mosi, ESP32_BUS_TYPE_INIT, NULL); + return true; +} + +bool spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss) +{ + if(!spi || ss < 0 || cs_num > 2) { + return false; + } + void * bus = perimanGetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER); + if(bus != NULL && !perimanSetPinBus(ss, ESP32_BUS_TYPE_INIT, NULL)){ + return false; + } + pinMode(ss, OUTPUT); + pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false); + spiEnableSSPins(spi, (1 << cs_num)); + spi->ss = ss; + if(!perimanSetPinBus(ss, ESP32_BUS_TYPE_SPI_MASTER, (void *)(spi->num+1))){ + spiDetachBus((void *)(spi->num+1)); + log_e("Failed to set pin bus to SPI for pin %d", ss); + return false; + } + return true; +} + +bool spiDetachSS(spi_t * spi, int8_t ss) +{ + if(!spi || ss < 0) { + return false; + } + pinMatrixOutDetach(ss, false, false); + spi->ss = -1; + perimanSetPinBus(ss, ESP32_BUS_TYPE_INIT, NULL); + return true; +} + +void spiEnableSSPins(spi_t * spi, uint8_t cs_mask) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL); +#else + spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL); +#endif + SPI_MUTEX_UNLOCK(); +} + +void spiDisableSSPins(spi_t * spi, uint8_t cs_mask) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL); +#else + spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL); +#endif + SPI_MUTEX_UNLOCK(); +} + +void spiSSEnable(spi_t * spi) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + spi->dev->user.cs_setup = 1; + spi->dev->user.cs_hold = 1; + SPI_MUTEX_UNLOCK(); +} + +void spiSSDisable(spi_t * spi) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + spi->dev->user.cs_setup = 0; + spi->dev->user.cs_hold = 0; + SPI_MUTEX_UNLOCK(); +} + +void spiSSSet(spi_t * spi) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.cs_keep_active = 1; +#else + spi->dev->pin.cs_keep_active = 1; +#endif + SPI_MUTEX_UNLOCK(); +} + +void spiSSClear(spi_t * spi) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.cs_keep_active = 0; +#else + spi->dev->pin.cs_keep_active = 0; +#endif + SPI_MUTEX_UNLOCK(); +} + +uint32_t spiGetClockDiv(spi_t * spi) +{ + if(!spi) { + return 0; + } + return spi->dev->clock.val; +} + +void spiSetClockDiv(spi_t * spi, uint32_t clockDiv) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + spi->dev->clock.val = clockDiv; + SPI_MUTEX_UNLOCK(); +} + +uint8_t spiGetDataMode(spi_t * spi) +{ + if(!spi) { + return 0; + } +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + bool idleEdge = spi->dev->misc.ck_idle_edge; +#else + bool idleEdge = spi->dev->pin.ck_idle_edge; +#endif + bool outEdge = spi->dev->user.ck_out_edge; + if(idleEdge) { + if(outEdge) { + return SPI_MODE2; + } + return SPI_MODE3; + } + if(outEdge) { + return SPI_MODE1; + } + return SPI_MODE0; +} + +void spiSetDataMode(spi_t * spi, uint8_t dataMode) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + switch (dataMode) { + case SPI_MODE1: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 0; +#else + spi->dev->pin.ck_idle_edge = 0; +#endif + spi->dev->user.ck_out_edge = 1; + break; + case SPI_MODE2: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 1; +#else + spi->dev->pin.ck_idle_edge = 1; +#endif + spi->dev->user.ck_out_edge = 1; + break; + case SPI_MODE3: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 1; +#else + spi->dev->pin.ck_idle_edge = 1; +#endif + spi->dev->user.ck_out_edge = 0; + break; + case SPI_MODE0: + default: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 0; +#else + spi->dev->pin.ck_idle_edge = 0; +#endif + spi->dev->user.ck_out_edge = 0; + break; + } + SPI_MUTEX_UNLOCK(); +} + +uint8_t spiGetBitOrder(spi_t * spi) +{ + if(!spi) { + return 0; + } + return (spi->dev->ctrl.wr_bit_order | spi->dev->ctrl.rd_bit_order) == 0; +} + +void spiSetBitOrder(spi_t * spi, uint8_t bitOrder) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + if (SPI_MSBFIRST == bitOrder) { + spi->dev->ctrl.wr_bit_order = 0; + spi->dev->ctrl.rd_bit_order = 0; + } else if (SPI_LSBFIRST == bitOrder) { + spi->dev->ctrl.wr_bit_order = 1; + spi->dev->ctrl.rd_bit_order = 1; + } + SPI_MUTEX_UNLOCK(); +} + +static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb) +{ + spi_t * spi = (spi_t *)arg; + if(ev_type == APB_BEFORE_CHANGE){ + SPI_MUTEX_LOCK(); + while(spi->dev->cmd.usr); + } else { + spi->dev->clock.val = spiFrequencyToClockDiv(old_apb / ((spi->dev->clock.clkdiv_pre + 1) * (spi->dev->clock.clkcnt_n + 1))); + SPI_MUTEX_UNLOCK(); + } +} + +static void spiInitBus(spi_t * spi) +{ +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->slave.trans_done = 0; +#endif + spi->dev->slave.val = 0; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.val = 0; +#else + spi->dev->pin.val = 0; +#endif + spi->dev->user.val = 0; + spi->dev->user1.val = 0; + spi->dev->ctrl.val = 0; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->ctrl1.val = 0; + spi->dev->ctrl2.val = 0; +#else + spi->dev->clk_gate.val = 0; + spi->dev->dma_conf.val = 0; + spi->dev->dma_conf.rx_afifo_rst = 1; + spi->dev->dma_conf.buf_afifo_rst = 1; +#endif + spi->dev->clock.val = 0; +} + +void spiStopBus(spi_t * spi) +{ + if(!spi) { + return; + } + + removeApbChangeCallback(spi, _on_apb_change); + + SPI_MUTEX_LOCK(); + spiInitBus(spi); + SPI_MUTEX_UNLOCK(); +} + +spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) +{ + if(spi_num >= SPI_COUNT){ + return NULL; + } + + perimanSetBusDeinit(ESP32_BUS_TYPE_SPI_MASTER, spiDetachBus); + spi_t * spi = &_spi_bus_array[spi_num]; + +#if !CONFIG_DISABLE_HAL_LOCKS + if(spi->lock == NULL){ + spi->lock = xSemaphoreCreateMutex(); + if(spi->lock == NULL) { + return NULL; + } + } +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 + if(spi_num == FSPI) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); + } else if(spi_num == HSPI) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); + } +#elif CONFIG_IDF_TARGET_ESP32S3 + if(spi_num == FSPI) { + periph_ll_reset( PERIPH_SPI2_MODULE ); + periph_ll_enable_clk_clear_rst( PERIPH_SPI2_MODULE ); + } else if(spi_num == HSPI) { + periph_ll_reset( PERIPH_SPI3_MODULE ); + periph_ll_enable_clk_clear_rst( PERIPH_SPI3_MODULE ); + } +#elif CONFIG_IDF_TARGET_ESP32 + if(spi_num == HSPI) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); + } else if(spi_num == VSPI) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); + } +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + periph_ll_reset( PERIPH_SPI2_MODULE ); + periph_ll_enable_clk_clear_rst( PERIPH_SPI2_MODULE ); +#endif + + SPI_MUTEX_LOCK(); + spiInitBus(spi); +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->clk_gate.clk_en = 1; + spi->dev->clk_gate.mst_clk_sel = 1; + spi->dev->clk_gate.mst_clk_active = 1; +#if !CONFIG_IDF_TARGET_ESP32C6 && !CONFIG_IDF_TARGET_ESP32H2 + spi->dev->dma_conf.tx_seg_trans_clr_en = 1; + spi->dev->dma_conf.rx_seg_trans_clr_en = 1; + spi->dev->dma_conf.dma_seg_trans_en = 0; +#endif +#endif + spi->dev->user.usr_mosi = 1; + spi->dev->user.usr_miso = 1; + spi->dev->user.doutdin = 1; + int i; + for(i=0; i<16; i++) { + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[i].val = 0x00000000; + #else + spi->dev->data_buf[i] = 0x00000000; + #endif + } + SPI_MUTEX_UNLOCK(); + + spiSetDataMode(spi, dataMode); + spiSetBitOrder(spi, bitOrder); + spiSetClockDiv(spi, clockDiv); + + addApbChangeCallback(spi, _on_apb_change); + + return spi; +} + +void spiWaitReady(spi_t * spi) +{ + if(!spi) { + return; + } + while(spi->dev->cmd.usr); +} + +#if CONFIG_IDF_TARGET_ESP32S2 +#define usr_mosi_dbitlen usr_mosi_bit_len +#define usr_miso_dbitlen usr_miso_bit_len +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#define usr_mosi_dbitlen ms_data_bitlen +#define usr_miso_dbitlen ms_data_bitlen +#define mosi_dlen ms_dlen +#define miso_dlen ms_dlen +#endif + +void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len) +{ + if(!spi) { + return; + } + int i; + if(len > 16) { + len = 16; + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif + for(i=0; idev->data_buf[i].val = data[i]; +#else + spi->dev->data_buf[i] = data[i]; +#endif + } +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + SPI_MUTEX_UNLOCK(); +} + +void spiTransfer(spi_t * spi, uint32_t *data, uint8_t len) +{ + if(!spi) { + return; + } + int i; + if(len > 16) { + len = 16; + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; + spi->dev->miso_dlen.usr_miso_dbitlen = (len * 32) - 1; + for(i=0; idev->data_buf[i].val = data[i]; +#else + spi->dev->data_buf[i] = data[i]; +#endif + } +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + for(i=0; idev->data_buf[i].val; +#else + data[i] = spi->dev->data_buf[i]; +#endif + } + SPI_MUTEX_UNLOCK(); +} + +void spiWriteByte(spi_t * spi, uint8_t data) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + SPI_MUTEX_UNLOCK(); +} + +uint8_t spiTransferByte(spi_t * spi, uint8_t data) +{ + if(!spi) { + return 0; + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; + spi->dev->miso_dlen.usr_miso_dbitlen = 7; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val & 0xFF; +#else + data = spi->dev->data_buf[0] & 0xFF; +#endif + SPI_MUTEX_UNLOCK(); + return data; +} + +static uint32_t __spiTranslate32(uint32_t data) +{ + union { + uint32_t l; + uint8_t b[4]; + } out; + out.l = data; + return out.b[3] | (out.b[2] << 8) | (out.b[1] << 16) | (out.b[0] << 24); +} + +void spiWriteWord(spi_t * spi, uint16_t data) +{ + if(!spi) { + return; + } + if(!spi->dev->ctrl.wr_bit_order){ + data = (data >> 8) | (data << 8); + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + SPI_MUTEX_UNLOCK(); +} + +uint16_t spiTransferWord(spi_t * spi, uint16_t data) +{ + if(!spi) { + return 0; + } + if(!spi->dev->ctrl.wr_bit_order){ + data = (data >> 8) | (data << 8); + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; + spi->dev->miso_dlen.usr_miso_dbitlen = 15; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val; +#else + data = spi->dev->data_buf[0]; +#endif + SPI_MUTEX_UNLOCK(); + if(!spi->dev->ctrl.rd_bit_order){ + data = (data >> 8) | (data << 8); + } + return data; +} + +void spiWriteLong(spi_t * spi, uint32_t data) +{ + if(!spi) { + return; + } + if(!spi->dev->ctrl.wr_bit_order){ + data = __spiTranslate32(data); + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + SPI_MUTEX_UNLOCK(); +} + +uint32_t spiTransferLong(spi_t * spi, uint32_t data) +{ + if(!spi) { + return 0; + } + if(!spi->dev->ctrl.wr_bit_order){ + data = __spiTranslate32(data); + } + SPI_MUTEX_LOCK(); + spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; + spi->dev->miso_dlen.usr_miso_dbitlen = 31; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val; +#else + data = spi->dev->data_buf[0]; +#endif + SPI_MUTEX_UNLOCK(); + if(!spi->dev->ctrl.rd_bit_order){ + data = __spiTranslate32(data); + } + return data; +} + +static void __spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t bytes) +{ + if(!spi) { + return; + } + uint32_t i; + + if(bytes > 64) { + bytes = 64; + } + + uint32_t words = (bytes + 3) / 4;//16 max + + uint32_t wordsBuf[16] = {0,}; + uint8_t * bytesBuf = (uint8_t *) wordsBuf; + + if(data) { + memcpy(bytesBuf, data, bytes);//copy data to buffer + } else { + memset(bytesBuf, 0xFF, bytes); + } + + spi->dev->mosi_dlen.usr_mosi_dbitlen = ((bytes * 8) - 1); + spi->dev->miso_dlen.usr_miso_dbitlen = ((bytes * 8) - 1); + + for(i=0; idev->data_buf[i].val = wordsBuf[i]; //copy buffer to spi fifo + #else + spi->dev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo + #endif + } + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + + while(spi->dev->cmd.usr); + + if(out) { + for(i=0; idev->data_buf[i].val;//copy spi fifo to buffer + #else + wordsBuf[i] = spi->dev->data_buf[i];//copy spi fifo to buffer + #endif + } + memcpy(out, bytesBuf, bytes);//copy buffer to output + } +} + +void spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t size) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + while(size) { + if(size > 64) { + __spiTransferBytes(spi, data, out, 64); + size -= 64; + if(data) { + data += 64; + } + if(out) { + out += 64; + } + } else { + __spiTransferBytes(spi, data, out, size); + size = 0; + } + } + SPI_MUTEX_UNLOCK(); +} + +void spiTransferBits(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + spiTransferBitsNL(spi, data, out, bits); + SPI_MUTEX_UNLOCK(); +} + +/* + * Manual Lock Management + * */ + +#define MSB_32_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[3] | (d[2] << 8) | (d[1] << 16) | (d[0] << 24); } +#define MSB_24_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[2] | (d[1] << 8) | (d[0] << 16); } +#define MSB_16_SET(var, val) { (var) = (((val) & 0xFF00) >> 8) | (((val) & 0xFF) << 8); } +#define MSB_PIX_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[1] | (d[0] << 8) | (d[3] << 16) | (d[2] << 24); } + +void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); + spi->dev->clock.val = clockDiv; + switch (dataMode) { + case SPI_MODE1: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 0; +#else + spi->dev->pin.ck_idle_edge = 0; +#endif + spi->dev->user.ck_out_edge = 1; + break; + case SPI_MODE2: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 1; +#else + spi->dev->pin.ck_idle_edge = 1; +#endif + spi->dev->user.ck_out_edge = 1; + break; + case SPI_MODE3: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 1; +#else + spi->dev->pin.ck_idle_edge = 1; +#endif + spi->dev->user.ck_out_edge = 0; + break; + case SPI_MODE0: + default: +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->misc.ck_idle_edge = 0; +#else + spi->dev->pin.ck_idle_edge = 0; +#endif + spi->dev->user.ck_out_edge = 0; + break; + } + if (SPI_MSBFIRST == bitOrder) { + spi->dev->ctrl.wr_bit_order = 0; + spi->dev->ctrl.rd_bit_order = 0; + } else if (SPI_LSBFIRST == bitOrder) { + spi->dev->ctrl.wr_bit_order = 1; + spi->dev->ctrl.rd_bit_order = 1; + } +} + +void spiSimpleTransaction(spi_t * spi) +{ + if(!spi) { + return; + } + SPI_MUTEX_LOCK(); +} + +void spiEndTransaction(spi_t * spi) +{ + if(!spi) { + return; + } + SPI_MUTEX_UNLOCK(); +} + +void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t * spi, uint8_t data) +{ + if(!spi) { + return; + } + spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +} + +uint8_t spiTransferByteNL(spi_t * spi, uint8_t data) +{ + if(!spi) { + return 0; + } + spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; + spi->dev->miso_dlen.usr_miso_dbitlen = 7; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val & 0xFF; +#else + data = spi->dev->data_buf[0] & 0xFF; +#endif + return data; +} + +void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data) +{ + if(!spi) { + return; + } + if(!spi->dev->ctrl.wr_bit_order){ + MSB_16_SET(data, data); + } + spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +} + +uint16_t spiTransferShortNL(spi_t * spi, uint16_t data) +{ + if(!spi) { + return 0; + } + if(!spi->dev->ctrl.wr_bit_order){ + MSB_16_SET(data, data); + } + spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; + spi->dev->miso_dlen.usr_miso_dbitlen = 15; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val & 0xFFFF; +#else + data = spi->dev->data_buf[0] & 0xFFFF; +#endif + if(!spi->dev->ctrl.rd_bit_order){ + MSB_16_SET(data, data); + } + return data; +} + +void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data) +{ + if(!spi) { + return; + } + if(!spi->dev->ctrl.wr_bit_order){ + MSB_32_SET(data, data); + } + spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); +} + +uint32_t spiTransferLongNL(spi_t * spi, uint32_t data) +{ + if(!spi) { + return 0; + } + if(!spi->dev->ctrl.wr_bit_order){ + MSB_32_SET(data, data); + } + spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; + spi->dev->miso_dlen.usr_miso_dbitlen = 31; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val; +#else + data = spi->dev->data_buf[0]; +#endif + if(!spi->dev->ctrl.rd_bit_order){ + MSB_32_SET(data, data); + } + return data; +} + +void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){ + if(!spi) { + return; + } + size_t longs = len >> 2; + if(len & 3){ + longs++; + } + uint32_t * data = (uint32_t*)data_in; + size_t c_len = 0, c_longs = 0; + + while(len){ + c_len = (len>64)?64:len; + c_longs = (longs > 16)?16:longs; + + spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif + for (size_t i=0; idev->data_buf[i].val = data[i]; + #else + spi->dev->data_buf[i] = data[i]; + #endif + } +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + + data += c_longs; + longs -= c_longs; + len -= c_len; + } +} + +void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, uint32_t len){ + if(!spi) { + return; + } + size_t longs = len >> 2; + if(len & 3){ + longs++; + } + uint32_t * data = (uint32_t*)data_in; + uint32_t * result = (uint32_t*)data_out; + size_t c_len = 0, c_longs = 0; + + while(len){ + c_len = (len>64)?64:len; + c_longs = (longs > 16)?16:longs; + + spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; + spi->dev->miso_dlen.usr_miso_dbitlen = (c_len*8)-1; + if(data){ + for (size_t i=0; idev->data_buf[i].val = data[i]; + #else + spi->dev->data_buf[i] = data[i]; + #endif + } + } else { + for (size_t i=0; idev->data_buf[i].val = 0xFFFFFFFF; + #else + spi->dev->data_buf[i] = 0xFFFFFFFF; + #endif + } + } +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + if(result){ + if(c_len & 3){ + for (size_t i=0; i<(c_longs-1); i++) { + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + result[i] = spi->dev->data_buf[i].val; + #else + result[i] = spi->dev->data_buf[i]; + #endif + } + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + uint32_t last_data = spi->dev->data_buf[c_longs-1].val; + #else + uint32_t last_data = spi->dev->data_buf[c_longs-1]; + #endif + uint8_t * last_out8 = (uint8_t *)&result[c_longs-1]; + uint8_t * last_data8 = (uint8_t *)&last_data; + for (size_t i=0; i<(c_len & 3); i++) { + last_out8[i] = last_data8[i]; + } + } else { + for (size_t i=0; idev->data_buf[i].val; + #else + result[i] = spi->dev->data_buf[i]; + #endif + } + } + } + if(data){ + data += c_longs; + } + if(result){ + result += c_longs; + } + longs -= c_longs; + len -= c_len; + } +} + +void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits) +{ + if(!spi) { + return; + } + + if(bits > 32) { + bits = 32; + } + uint32_t bytes = (bits + 7) / 8;//64 max + uint32_t mask = (((uint64_t)1 << bits) - 1) & 0xFFFFFFFF; + data = data & mask; + if(!spi->dev->ctrl.wr_bit_order){ + if(bytes == 2) { + MSB_16_SET(data, data); + } else if(bytes == 3) { + MSB_24_SET(data, data); + } else { + MSB_32_SET(data, data); + } + } + + spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1); + spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1); +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[0].val = data; +#else + spi->dev->data_buf[0] = data; +#endif +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + data = spi->dev->data_buf[0].val; +#else + data = spi->dev->data_buf[0]; +#endif + if(out) { + *out = data; + if(!spi->dev->ctrl.rd_bit_order){ + if(bytes == 2) { + MSB_16_SET(*out, data); + } else if(bytes == 3) { + MSB_24_SET(*out, data); + } else { + MSB_32_SET(*out, data); + } + } + } +} + +void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){ + size_t longs = len >> 2; + if(len & 3){ + longs++; + } + bool msb = !spi->dev->ctrl.wr_bit_order; + uint32_t * data = (uint32_t*)data_in; + size_t c_len = 0, c_longs = 0, l_bytes = 0; + + while(len){ + c_len = (len>64)?64:len; + c_longs = (longs > 16)?16:longs; + l_bytes = (c_len & 3); + + spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32 + spi->dev->miso_dlen.usr_miso_dbitlen = 0; +#endif + for (size_t i=0; idev->data_buf[i].val, data[i]); + #else + MSB_16_SET(spi->dev->data_buf[i], data[i]); + #endif + } else { + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[i].val = data[i] & 0xFF; + #else + spi->dev->data_buf[i] = data[i] & 0xFF; + #endif + } + } else { + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + MSB_PIX_SET(spi->dev->data_buf[i].val, data[i]); + #else + MSB_PIX_SET(spi->dev->data_buf[i], data[i]); + #endif + } + } else { + #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->data_buf[i].val = data[i]; + #else + spi->dev->data_buf[i] = data[i]; + #endif + } + } +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + spi->dev->cmd.update = 1; + while (spi->dev->cmd.update); +#endif + spi->dev->cmd.usr = 1; + while(spi->dev->cmd.usr); + + data += c_longs; + longs -= c_longs; + len -= c_len; + } +} + + + +/* + * Clock Calculators + * + * */ + +typedef union { + uint32_t value; + struct { + uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/ + uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/ + uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + uint32_t clkdiv_pre: 4; /*it is pre-divider of spi_clk.*/ + uint32_t reserved: 9; /*reserved*/ +#else + uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/ +#endif + uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/ + }; +} spiClk_t; + +#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1))) + +uint32_t spiClockDivToFrequency(uint32_t clockDiv) +{ + uint32_t apb_freq = getApbFrequency(); + spiClk_t reg = { clockDiv }; + return ClkRegToFreq(®); +} + +uint32_t spiFrequencyToClockDiv(uint32_t freq) +{ + uint32_t apb_freq = getApbFrequency(); + + if(freq >= apb_freq) { + return SPI_CLK_EQU_SYSCLK; + } + + const spiClk_t minFreqReg = { 0x7FFFF000 }; + uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); + if(freq < minFreq) { + return minFreqReg.value; + } + + uint8_t calN = 1; + spiClk_t bestReg = { 0 }; + uint32_t bestFreq = 0; + + while(calN <= 0x3F) { + spiClk_t reg = { 0 }; + uint32_t calFreq; + int32_t calPre; + int8_t calPreVari = -2; + + reg.clkcnt_n = calN; + + while(calPreVari++ <= 1) { + calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + if(calPre > 0xF) { + reg.clkdiv_pre = 0xF; +#else + if(calPre > 0x1FFF) { + reg.clkdiv_pre = 0x1FFF; +#endif + } else if(calPre <= 0) { + reg.clkdiv_pre = 0; + } else { + reg.clkdiv_pre = calPre; + } + reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2); + calFreq = ClkRegToFreq(®); + if(calFreq == freq) { + memcpy(&bestReg, ®, sizeof(bestReg)); + break; + } else if(calFreq < freq) { + if((freq - calFreq) < (freq - bestFreq)) { + bestFreq = calFreq; + memcpy(&bestReg, ®, sizeof(bestReg)); + } + } + } + if(calFreq == (int32_t) freq) { + break; + } + calN++; + } + return bestReg.value; +} + +#endif /* SOC_GPSPI_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-spi.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-spi.h new file mode 100644 index 0000000..640501d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-spi.h @@ -0,0 +1,153 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MAIN_ESP32_HAL_SPI_H_ +#define MAIN_ESP32_HAL_SPI_H_ + +#include "soc/soc_caps.h" +#if SOC_GPSPI_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sdkconfig.h" +#include +#include + +#define SPI_HAS_TRANSACTION + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32S3 +#define FSPI 0 +#define HSPI 1 +#else +#define FSPI 1 //SPI bus attached to the flash (can use the same data lines but different SS) +#define HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins +#if CONFIG_IDF_TARGET_ESP32 +#define VSPI 3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins +#endif +#endif + +// This defines are not representing the real Divider of the ESP32 +// the Defines match to an AVR Arduino on 16MHz for better compatibility +#define SPI_CLOCK_DIV2 0x00101001 //8 MHz +#define SPI_CLOCK_DIV4 0x00241001 //4 MHz +#define SPI_CLOCK_DIV8 0x004c1001 //2 MHz +#define SPI_CLOCK_DIV16 0x009c1001 //1 MHz +#define SPI_CLOCK_DIV32 0x013c1001 //500 KHz +#define SPI_CLOCK_DIV64 0x027c1001 //250 KHz +#define SPI_CLOCK_DIV128 0x04fc1001 //125 KHz + +#define SPI_MODE0 0 +#define SPI_MODE1 1 +#define SPI_MODE2 2 +#define SPI_MODE3 3 + +#define SPI_CS0 0 +#define SPI_CS1 1 +#define SPI_CS2 2 +#define SPI_CS_MASK_ALL 0x7 + +#define SPI_LSBFIRST 0 +#define SPI_MSBFIRST 1 + +struct spi_struct_t; +typedef struct spi_struct_t spi_t; + +spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder); +void spiStopBus(spi_t * spi); + +//Attach/Detach Signal Pins +bool spiAttachSCK(spi_t * spi, int8_t sck); +bool spiAttachMISO(spi_t * spi, int8_t miso); +bool spiAttachMOSI(spi_t * spi, int8_t mosi); +bool spiDetachSCK(spi_t * spi, int8_t sck); +bool spiDetachMISO(spi_t * spi, int8_t miso); +bool spiDetachMOSI(spi_t * spi, int8_t mosi); + +//Attach/Detach SS pin to SPI_CSx signal +bool spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss); +bool spiDetachSS(spi_t * spi, int8_t ss); + +//Enable/Disable SPI_CSx pins +void spiEnableSSPins(spi_t * spi, uint8_t cs_mask); +void spiDisableSSPins(spi_t * spi, uint8_t cs_mask); + +//Enable/Disable hardware control of SPI_CSx pins +void spiSSEnable(spi_t * spi); +void spiSSDisable(spi_t * spi); + +//Activate enabled SPI_CSx pins +void spiSSSet(spi_t * spi); +//Deactivate enabled SPI_CSx pins +void spiSSClear(spi_t * spi); + +void spiWaitReady(spi_t * spi); + +uint32_t spiGetClockDiv(spi_t * spi); +uint8_t spiGetDataMode(spi_t * spi); +uint8_t spiGetBitOrder(spi_t * spi); + + +/* + * Non transaction based lock methods (each locks and unlocks when called) + * */ +void spiSetClockDiv(spi_t * spi, uint32_t clockDiv); +void spiSetDataMode(spi_t * spi, uint8_t dataMode); +void spiSetBitOrder(spi_t * spi, uint8_t bitOrder); + +void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len); +void spiWriteByte(spi_t * spi, uint8_t data); +void spiWriteWord(spi_t * spi, uint16_t data); +void spiWriteLong(spi_t * spi, uint32_t data); + +void spiTransfer(spi_t * spi, uint32_t *out, uint8_t len); +uint8_t spiTransferByte(spi_t * spi, uint8_t data); +uint16_t spiTransferWord(spi_t * spi, uint16_t data); +uint32_t spiTransferLong(spi_t * spi, uint32_t data); +void spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t size); +void spiTransferBits(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits); + +/* + * New (EXPERIMENTAL) Transaction lock based API (lock once until endTransaction) + * */ +void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder); +void spiSimpleTransaction(spi_t * spi); +void spiEndTransaction(spi_t * spi); + +void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len); +void spiWriteByteNL(spi_t * spi, uint8_t data); +void spiWriteShortNL(spi_t * spi, uint16_t data); +void spiWriteLongNL(spi_t * spi, uint32_t data); +void spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len); + +#define spiTransferNL(spi, data, len) spiTransferBytesNL(spi, data, data, len) +uint8_t spiTransferByteNL(spi_t * spi, uint8_t data); +uint16_t spiTransferShortNL(spi_t * spi, uint16_t data); +uint32_t spiTransferLongNL(spi_t * spi, uint32_t data); +void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, uint32_t len); +void spiTransferBitsNL(spi_t * spi, uint32_t data_in, uint32_t * data_out, uint8_t bits); + +/* + * Helper functions to translate frequency to clock divider and back + * */ +uint32_t spiFrequencyToClockDiv(uint32_t freq); +uint32_t spiClockDivToFrequency(uint32_t freq); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_GPSPI_SUPPORTED */ +#endif /* MAIN_ESP32_HAL_SPI_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-time.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-time.c new file mode 100644 index 0000000..e704830 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-time.c @@ -0,0 +1,97 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal.h" +#include "lwip/apps/sntp.h" +//#include "tcpip_adapter.h" +#include "esp_netif.h" + +static void setTimeZone(long offset, int daylight) +{ + char cst[17] = {0}; + char cdt[17] = "DST"; + char tz[33] = {0}; + + if(offset % 3600){ + sprintf(cst, "UTC%ld:%02u:%02u", offset / 3600, abs((offset % 3600) / 60), abs(offset % 60)); + } else { + sprintf(cst, "UTC%ld", offset / 3600); + } + if(daylight != 3600){ + long tz_dst = offset - daylight; + if(tz_dst % 3600){ + sprintf(cdt, "DST%ld:%02u:%02u", tz_dst / 3600, abs((tz_dst % 3600) / 60), abs(tz_dst % 60)); + } else { + sprintf(cdt, "DST%ld", tz_dst / 3600); + } + } + sprintf(tz, "%s%s", cst, cdt); + setenv("TZ", tz, 1); + tzset(); +} + +/* + * configTime + * Source: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/time.c + * */ +void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3) +{ + //tcpip_adapter_init(); // Should not hurt anything if already inited + esp_netif_init(); + if(sntp_enabled()){ + sntp_stop(); + } + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, (char*)server1); + sntp_setservername(1, (char*)server2); + sntp_setservername(2, (char*)server3); + sntp_init(); + setTimeZone(-gmtOffset_sec, daylightOffset_sec); +} + +/* + * configTzTime + * sntp setup using TZ environment variable + * */ +void configTzTime(const char* tz, const char* server1, const char* server2, const char* server3) +{ + //tcpip_adapter_init(); // Should not hurt anything if already inited + esp_netif_init(); + if(sntp_enabled()){ + sntp_stop(); + } + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, (char*)server1); + sntp_setservername(1, (char*)server2); + sntp_setservername(2, (char*)server3); + sntp_init(); + setenv("TZ", tz, 1); + tzset(); +} + +bool getLocalTime(struct tm * info, uint32_t ms) +{ + uint32_t start = millis(); + time_t now; + while((millis()-start) <= ms) { + time(&now); + localtime_r(&now, info); + if(info->tm_year > (2016 - 1900)){ + return true; + } + delay(10); + } + return false; +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-timer.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-timer.c new file mode 100644 index 0000000..b8ab854 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-timer.c @@ -0,0 +1,217 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-timer.h" + +#if SOC_GPTIMER_SUPPORTED +#include "driver/gptimer.h" +#if defined __has_include && __has_include ("clk_tree.h") +#include "clk_tree.h" +#else +#include "esp_clk_tree.h" +#endif + +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); + +typedef struct { + voidFuncPtr fn; + void* arg; +} interrupt_config_t; + +struct timer_struct_t { + gptimer_handle_t timer_handle; + interrupt_config_t interrupt_handle; + bool timer_started; +}; + +inline uint64_t timerRead(hw_timer_t * timer){ + + uint64_t value; + gptimer_get_raw_count(timer->timer_handle, &value); + return value; +} + +void timerWrite(hw_timer_t * timer, uint64_t val){ + gptimer_set_raw_count(timer->timer_handle, val); +} + +void timerAlarm(hw_timer_t * timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count){ + esp_err_t err = ESP_OK; + gptimer_alarm_config_t alarm_cfg = { + .alarm_count = alarm_value, + .reload_count = reload_count, + .flags.auto_reload_on_alarm = autoreload, + }; + err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg); + if (err != ESP_OK){ + log_e("Timer Alarm Write failed, error num=%d", err); + } +} + +uint32_t timerGetFrequency(hw_timer_t * timer){ + uint32_t frequency; + gptimer_get_resolution(timer->timer_handle, &frequency); + return frequency; +} + +void timerStart(hw_timer_t * timer){ + gptimer_start(timer->timer_handle); + timer->timer_started = true; +} + +void timerStop(hw_timer_t * timer){ + gptimer_stop(timer->timer_handle); + timer->timer_started = false; +} + +void timerRestart(hw_timer_t * timer){ + gptimer_set_raw_count(timer->timer_handle,0); +} + +hw_timer_t * timerBegin(uint32_t frequency){ + esp_err_t err = ESP_OK; + uint32_t counter_src_hz = 0; + uint32_t divider = 0; + soc_periph_gptimer_clk_src_t clk; + + soc_periph_gptimer_clk_src_t gptimer_clks[] = SOC_GPTIMER_CLKS; + for (size_t i = 0; i < sizeof(gptimer_clks) / sizeof(gptimer_clks[0]); i++){ + clk = gptimer_clks[i]; +#if defined __has_include && __has_include ("clk_tree.h") + clk_tree_src_get_freq_hz(clk, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz); +#else + esp_clk_tree_src_get_freq_hz(clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz); +#endif + divider = counter_src_hz / frequency; + if((divider >= 2) && (divider <= 65536)){ + break; + } + else divider = 0; + } + + if(divider == 0){ + log_e("Resolution cannot be reached with any clock source, aborting!"); + return NULL; + } + + gptimer_config_t config = { + .clk_src = clk, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = frequency, + .flags.intr_shared = true, + }; + + hw_timer_t *timer = malloc(sizeof(hw_timer_t)); + + err = gptimer_new_timer(&config, &timer->timer_handle); + if (err != ESP_OK){ + log_e("Failed to create a new GPTimer, error num=%d", err); + free(timer); + return NULL; + } + gptimer_enable(timer->timer_handle); + gptimer_start(timer->timer_handle); + timer->timer_started = true; + return timer; +} + +void timerEnd(hw_timer_t * timer){ + esp_err_t err = ESP_OK; + if(timer->timer_started == true){ + gptimer_stop(timer->timer_handle); + } + gptimer_disable(timer->timer_handle); + err = gptimer_del_timer(timer->timer_handle); + if (err != ESP_OK){ + log_e("Failed to destroy GPTimer, error num=%d", err); + return; + } + free(timer); +} + +bool IRAM_ATTR timerFnWrapper(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void * args){ + interrupt_config_t * isr = (interrupt_config_t*)args; + if(isr->fn) { + if(isr->arg){ + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } + } + // some additional logic or handling may be required here to approriately yield or not + return false; +} + +void timerAttachInterruptFunctionalArg(hw_timer_t * timer, void (*userFunc)(void*), void * arg){ + esp_err_t err = ESP_OK; + gptimer_event_callbacks_t cbs = { + .on_alarm = timerFnWrapper, + }; + + timer->interrupt_handle.fn = (voidFuncPtr)userFunc; + timer->interrupt_handle.arg = arg; + + if(timer->timer_started == true){ + gptimer_stop(timer->timer_handle); + } + gptimer_disable(timer->timer_handle); + err = gptimer_register_event_callbacks(timer->timer_handle, &cbs, &timer->interrupt_handle); + if (err != ESP_OK){ + log_e("Timer Attach Interrupt failed, error num=%d", err); + } + gptimer_enable(timer->timer_handle); + if(timer->timer_started == true){ + gptimer_start(timer->timer_handle); + } + +} + +void timerAttachInterruptArg(hw_timer_t * timer, void (*userFunc)(void*), void * arg){ + timerAttachInterruptFunctionalArg(timer, userFunc, arg); +} + +void timerAttachInterrupt(hw_timer_t * timer, voidFuncPtr userFunc){ + timerAttachInterruptFunctionalArg(timer, (voidFuncPtrArg)userFunc, NULL); +} + +void timerDetachInterrupt(hw_timer_t * timer){ + esp_err_t err = ESP_OK; + err = gptimer_set_alarm_action(timer->timer_handle, NULL); + timer->interrupt_handle.fn = NULL; + timer->interrupt_handle.arg = NULL; + if (err != ESP_OK){ + log_e("Timer Detach Interrupt failed, error num=%d", err); + } +} + +uint64_t timerReadMicros(hw_timer_t * timer){ + uint64_t timer_val = timerRead(timer); + uint32_t frequency = timerGetFrequency(timer); + return timer_val * 1000000 / frequency; +} + +uint64_t timerReadMilis(hw_timer_t * timer){ + uint64_t timer_val = timerRead(timer); + uint32_t frequency = timerGetFrequency(timer); + return timer_val * 1000 / frequency; +} + +double timerReadSeconds(hw_timer_t * timer){ + uint64_t timer_val = timerRead(timer); + uint32_t frequency = timerGetFrequency(timer); + return (double)timer_val / frequency; +} + +#endif /* SOC_GPTIMER_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-timer.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-timer.h new file mode 100644 index 0000000..9b71e18 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-timer.h @@ -0,0 +1,60 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "soc/soc_caps.h" +#if SOC_GPTIMER_SUPPORTED + +#include "esp32-hal.h" +#include "driver/gptimer_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct timer_struct_t; +typedef struct timer_struct_t hw_timer_t; + +hw_timer_t * timerBegin(uint32_t frequency); +void timerEnd(hw_timer_t * timer); + +void timerStart(hw_timer_t * timer); +void timerStop(hw_timer_t * timer); +void timerRestart(hw_timer_t * timer); +void timerWrite(hw_timer_t * timer, uint64_t val); + +uint64_t timerRead(hw_timer_t * timer); +uint64_t timerReadMicros(hw_timer_t * timer); +uint64_t timerReadMilis(hw_timer_t * timer); +double timerReadSeconds(hw_timer_t * timer); + +uint32_t timerGetFrequency(hw_timer_t * timer); + +void timerAttachInterrupt(hw_timer_t * timer, void (*userFunc)(void)); +void timerAttachInterruptArg(hw_timer_t * timer, void (*userFunc)(void*), void * arg); +void timerDetachInterrupt(hw_timer_t * timer); + +void timerAlarm(hw_timer_t * timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_GPTIMER_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-tinyusb.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-tinyusb.c new file mode 100644 index 0000000..fa97fb8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-tinyusb.c @@ -0,0 +1,799 @@ +#include "soc/soc_caps.h" + +#if SOC_USB_OTG_SUPPORTED +#include "sdkconfig.h" +#if CONFIG_TINYUSB_ENABLED +#include +#include + +#include "esp_log.h" + +#include "soc/soc.h" +#include "soc/efuse_reg.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/usb_struct.h" +#include "soc/usb_reg.h" +#include "soc/usb_wrap_reg.h" +#include "soc/usb_wrap_struct.h" +#include "soc/usb_periph.h" +#include "soc/periph_defs.h" +#include "soc/timer_group_struct.h" +#include "soc/system_reg.h" + +#include "rom/gpio.h" + +#include "hal/usb_hal.h" +#include "hal/gpio_ll.h" +#include "hal/clk_gate_ll.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "driver/gpio.h" + +#include "esp_rom_gpio.h" + +#include "esp32-hal.h" +#include "esp32-hal-periman.h" + +#include "esp32-hal-tinyusb.h" +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/usb/usb_persist.h" +#include "esp32s2/rom/usb/usb_dc.h" +#include "esp32s2/rom/usb/chip_usb_dw_wrapper.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "hal/usb_serial_jtag_ll.h" +#include "hal/usb_phy_ll.h" +#include "esp32s3/rom/usb/usb_persist.h" +#include "esp32s3/rom/usb/usb_dc.h" +#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h" +#endif + +typedef enum{ + TINYUSB_USBDEV_0, +} tinyusb_usbdev_t; + +typedef char *tusb_desc_strarray_device_t[USB_STRING_DESCRIPTOR_ARRAY_SIZE]; + +typedef struct { + bool external_phy; +} tinyusb_config_t; + +static bool usb_otg_deinit(void * busptr) { + // Once USB OTG is initialized, its GPIOs are assigned and it shall never be deinited + return false; +} + +static void configure_pins(usb_hal_context_t *usb) +{ + for (const usb_iopin_dsc_t *iopin = usb_periph_iopins; iopin->pin != -1; ++iopin) { + if ((usb->use_external_phy) || (iopin->ext_phy_only == 0)) { + esp_rom_gpio_pad_select_gpio(iopin->pin); + if (iopin->is_output) { + esp_rom_gpio_connect_out_signal(iopin->pin, iopin->func, false, false); + } else { + esp_rom_gpio_connect_in_signal(iopin->pin, iopin->func, false); + if ((iopin->pin != GPIO_FUNC_IN_LOW) && (iopin->pin != GPIO_FUNC_IN_HIGH)) { + gpio_ll_input_enable(&GPIO, iopin->pin); + } + } + esp_rom_gpio_pad_unhold(iopin->pin); + } + } + if (!usb->use_external_phy) { + gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3); + gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3); + if (perimanSetBusDeinit(ESP32_BUS_TYPE_USB, usb_otg_deinit)) { + // Bus Pointer is not used anyway - once the USB GPIOs are assigned, they can't be detached + perimanSetPinBus(USBPHY_DM_NUM, ESP32_BUS_TYPE_USB, (void *) usb); + perimanSetPinBus(USBPHY_DP_NUM, ESP32_BUS_TYPE_USB, (void *) usb); + } else { + log_e("USB OTG Pins can't be set into Peripheral Manager."); + } + } +} + +esp_err_t tinyusb_driver_install(const tinyusb_config_t *config) +{ + usb_hal_context_t hal = { + .use_external_phy = config->external_phy + }; + usb_hal_init(&hal); + configure_pins(&hal); + if (!tusb_init()) { + log_e("Can't initialize the TinyUSB stack."); + return ESP_FAIL; + } + return ESP_OK; +} + + + + + + + + + + +typedef char tusb_str_t[127]; + +static bool WEBUSB_ENABLED = false; + +static tusb_str_t WEBUSB_URL = ""; +static tusb_str_t USB_DEVICE_PRODUCT = ""; +static tusb_str_t USB_DEVICE_MANUFACTURER = ""; +static tusb_str_t USB_DEVICE_SERIAL = ""; +static tusb_str_t USB_DEVICE_LANGUAGE = "\x09\x04";//English (0x0409) + +static uint8_t USB_DEVICE_ATTRIBUTES = 0; +static uint16_t USB_DEVICE_POWER = 0; + +/* + * Device Descriptor + * */ +static tusb_desc_device_t tinyusb_device_descriptor = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE, + + .idVendor = 0, + .idProduct = 0, + .bcdDevice = 0, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +/* + * String Descriptors + * */ +#define MAX_STRING_DESCRIPTORS 20 +static uint32_t tinyusb_string_descriptor_len = 4; +static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = { + // array of pointer to string descriptors + USB_DEVICE_LANGUAGE, // 0: is supported language + USB_DEVICE_MANUFACTURER,// 1: Manufacturer + USB_DEVICE_PRODUCT, // 2: Product + USB_DEVICE_SERIAL, // 3: Serials, should use chip ID +}; + + +/* Microsoft OS 2.0 registry property descriptor +Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx +device should create DeviceInterfaceGUIDs. It can be done by driver and +in case of real PnP solution device should expose MS "Microsoft OS 2.0 +registry property descriptor". Such descriptor can insert any record +into Windows registry per device/configuration/interface. In our case it +will insert "DeviceInterfaceGUIDs" multistring property. + +GUID is freshly generated and should be OK to use. + +https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/ +(Section Microsoft OS compatibility descriptors) + */ + +#define MS_OS_20_DESC_LEN 0xB2 + +static uint8_t const tinyusb_ms_os_20_descriptor[] = +{ + // Set header: length, type, windows version, total length + U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN), + + // Configuration subset header: length, type, configuration index, reserved, configuration total length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A), + + // Function Subset header: length, type, first interface, reserved, subset length + U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08), + + // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID + U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible + + // MS OS 2.0 Registry property descriptor: length, type + U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY), + U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16 + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, + 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, + U16_TO_U8S_LE(0x0050), // wPropertyDataLength + //bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”. + '{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00, + '0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00, + '8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00, + '8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +TU_VERIFY_STATIC(sizeof(tinyusb_ms_os_20_descriptor) == MS_OS_20_DESC_LEN, "Incorrect size"); + + +/* + * BOS Descriptor (required for webUSB) + * */ +#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN) + +enum { + VENDOR_REQUEST_WEBUSB = 1, + VENDOR_REQUEST_MICROSOFT = 2 +}; + +static uint8_t const tinyusb_bos_descriptor[] = { + // total length, number of device caps + TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2), + + // Vendor Code, iLandingPage + TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1), + + // Microsoft OS 2.0 descriptor + TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT) +}; + +/* + * URL Descriptor (required for webUSB) + * */ +typedef struct TU_ATTR_PACKED { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char url[127]; +} tinyusb_desc_webusb_url_t; + +static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = { + .bLength = 3, + .bDescriptorType = 3, // WEBUSB URL type + .bScheme = 255, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: "" + .url = "" +}; + +/* + * Configuration Descriptor + * */ + +static tinyusb_descriptor_cb_t tinyusb_loaded_interfaces_callbacks[USB_INTERFACE_MAX]; +static uint32_t tinyusb_loaded_interfaces_mask = 0; +static uint8_t tinyusb_loaded_interfaces_num = 0; +static uint16_t tinyusb_config_descriptor_len = 0; +static uint8_t * tinyusb_config_descriptor = NULL; + +/* + * Endpoint Usage Tracking + * */ +typedef union { + struct { + uint32_t in:16; + uint32_t out:16; + }; + uint32_t val; +} tinyusb_endpoints_usage_t; + +static tinyusb_endpoints_usage_t tinyusb_endpoints; + + +/* + * TinyUSB Callbacks + * */ + +/** + * @brief Invoked when received GET CONFIGURATION DESCRIPTOR. + */ +__attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t index) +{ + //log_d("%u", index); + return tinyusb_config_descriptor; +} + +/** + * @brief Invoked when received GET DEVICE DESCRIPTOR. + */ +__attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void) +{ + //log_d(""); + return (uint8_t const *)&tinyusb_device_descriptor; +} + +/** + * @brief Invoked when received GET STRING DESCRIPTOR request. + */ +__attribute__ ((weak)) uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + //log_d("%u (0x%x)", index, langid); + static uint16_t _desc_str[127]; + uint8_t chr_count; + + if (index == 0) { + memcpy(&_desc_str[1], tinyusb_string_descriptor[0], 2); + chr_count = 1; + } else { + // Convert ASCII string into UTF-16 + if (index >= tinyusb_string_descriptor_len) { + return NULL; + } + const char *str = tinyusb_string_descriptor[index]; + // Cap at max char + chr_count = strlen(str); + if (chr_count > 126) { + chr_count = 126; + } + for (uint8_t i = 0; i < chr_count; i++) { + _desc_str[1 + i] = str[i]; + } + } + + // first byte is len, second byte is string type + _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2); + + return _desc_str; +} + +/** + * @brief Invoked when received GET BOS DESCRIPTOR request. + */ +uint8_t const * tud_descriptor_bos_cb(void) +{ + //log_v(""); + return tinyusb_bos_descriptor; +} + +__attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request){ return false; } + +/** + * @brief Handle WebUSB and Vendor requests. + */ +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) +{ + if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB + || (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){ + // we only care for SETUP stage + if (stage == CONTROL_STAGE_SETUP) { + if(request->bRequest == VENDOR_REQUEST_WEBUSB){ + // match vendor request in BOS descriptor + // Get landing page url + tinyusb_url_descriptor.bLength = 3 + strlen(WEBUSB_URL); + snprintf(tinyusb_url_descriptor.url, 127, "%s", WEBUSB_URL); + return tud_control_xfer(rhport, request, (void*) &tinyusb_url_descriptor, tinyusb_url_descriptor.bLength); + } + // Get Microsoft OS 2.0 compatible descriptor + uint16_t total_len; + memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2); + return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len); + } + return true; + } + log_v("rhport: %u, stage: %u, type: 0x%x, request: 0x%x", rhport, stage, request->bmRequestType_bit.type, request->bRequest); + return tinyusb_vendor_control_request_cb(rhport, stage, request); +} + +/* + * Required Callbacks + * */ +#if CFG_TUD_DFU +__attribute__ ((weak)) uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state){return 0;} +__attribute__ ((weak)) void tud_dfu_download_cb (uint8_t alt, uint16_t block_num, uint8_t const *data, uint16_t length){} +__attribute__ ((weak)) void tud_dfu_manifest_cb(uint8_t alt){} +#endif +#if CFG_TUD_HID +__attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(uint8_t itf){return NULL;} +__attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;} +__attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){} +#endif +#if CFG_TUD_MSC +__attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;} +__attribute__ ((weak)) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]){} +__attribute__ ((weak)) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size){} +__attribute__ ((weak)) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){return -1;} +__attribute__ ((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){return -1;} +__attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize){return -1;} +#endif + + +/* + * Private API + * */ +static bool usb_persist_enabled = false; +static restart_type_t usb_persist_mode = RESTART_NO_PERSIST; + +#if CONFIG_IDF_TARGET_ESP32S3 + +static void hw_cdc_reset_handler(void *arg) { + portBASE_TYPE xTaskWoken = 0; + uint32_t usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); + usb_serial_jtag_ll_clr_intsts_mask(usbjtag_intr_status); + + if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) { + xSemaphoreGiveFromISR((SemaphoreHandle_t)arg, &xTaskWoken); + } + + if (xTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +static void usb_switch_to_cdc_jtag(){ + // Disable USB-OTG + periph_ll_reset(PERIPH_USB_MODULE); + //periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE); + periph_ll_disable_clk_set_rst(PERIPH_USB_MODULE); + + // Switch to hardware CDC+JTAG + CLEAR_PERI_REG_MASK(RTC_CNTL_USB_CONF_REG, (RTC_CNTL_SW_HW_USB_PHY_SEL|RTC_CNTL_SW_USB_PHY_SEL|RTC_CNTL_USB_PAD_ENABLE)); + + // Do not use external PHY + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL); + + // Release GPIO pins from CDC+JTAG + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); + + // Force the host to re-enumerate (BUS_RESET) + pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN); + pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN); + digitalWrite(USBPHY_DM_NUM, LOW); + digitalWrite(USBPHY_DP_NUM, LOW); + + // Initialize CDC+JTAG ISR to listen for BUS_RESET + usb_phy_ll_int_jtag_enable(&USB_SERIAL_JTAG); + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_BUS_RESET); + intr_handle_t intr_handle = NULL; + SemaphoreHandle_t reset_sem = xSemaphoreCreateBinary(); + if(reset_sem){ + if(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_reset_handler, reset_sem, &intr_handle) != ESP_OK){ + vSemaphoreDelete(reset_sem); + reset_sem = NULL; + log_e("HW USB CDC failed to init interrupts"); + } + } else { + log_e("reset_sem init failed"); + } + + // Connect GPIOs to integrated CDC+JTAG + SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); + + // Wait for BUS_RESET to give us back the semaphore + if(reset_sem){ + if(xSemaphoreTake(reset_sem, 1000 / portTICK_PERIOD_MS) != pdPASS){ + log_e("reset_sem timeout"); + } + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + esp_intr_free(intr_handle); + vSemaphoreDelete(reset_sem); + } +} +#endif + +static void IRAM_ATTR usb_persist_shutdown_handler(void) +{ + if(usb_persist_mode != RESTART_NO_PERSIST){ + if (usb_persist_enabled) { + usb_dc_prepare_persist(); + } + if (usb_persist_mode == RESTART_BOOTLOADER) { + //USB CDC Download + if (usb_persist_enabled) { + chip_usb_set_persist_flags(USBDC_PERSIST_ENA); +#if CONFIG_IDF_TARGET_ESP32S2 + } else { + periph_ll_reset(PERIPH_USB_MODULE); + periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE); +#endif + } + REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + } else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) { + //DFU Download +#if CONFIG_IDF_TARGET_ESP32S2 + // Reset USB Core + USB0.grstctl |= USB_CSFTRST; + while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){} +#endif + chip_usb_set_persist_flags(USBDC_BOOT_DFU); + REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + } else if (usb_persist_enabled) { + //USB Persist reboot + chip_usb_set_persist_flags(USBDC_PERSIST_ENA); + } + } +} + +void usb_persist_restart(restart_type_t mode) +{ + if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) { + usb_persist_mode = mode; +#if CONFIG_IDF_TARGET_ESP32S3 + if (mode == RESTART_BOOTLOADER) { + usb_switch_to_cdc_jtag(); + } +#endif + esp_restart(); + } +} + +static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){ + if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){ + return false; + } + tinyusb_endpoints.in |= BIT(endpoint); + return true; +} + +static bool tinyusb_reserve_out_endpoint(uint8_t endpoint){ + if(endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0){ + return false; + } + tinyusb_endpoints.out |= BIT(endpoint); + return true; +} + +static bool tinyusb_has_available_fifos(void){ + uint8_t max_endpoints = 4, active_endpoints = 0; + if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) { + max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used + } + for(uint8_t i=1; i<7; i++){ + if((tinyusb_endpoints.in & BIT(i)) != 0){ + active_endpoints++; + } + } + + return active_endpoints < max_endpoints; +} + +static uint16_t tinyusb_load_descriptor(tinyusb_interface_t interface, uint8_t * dst, uint8_t * itf) +{ + if(tinyusb_loaded_interfaces_callbacks[interface]){ + return tinyusb_loaded_interfaces_callbacks[interface](dst, itf); + } + return 0; +} + +static bool tinyusb_load_enabled_interfaces(){ + tinyusb_config_descriptor_len += TUD_CONFIG_DESC_LEN; + tinyusb_config_descriptor = (uint8_t *)malloc(tinyusb_config_descriptor_len); + if (tinyusb_config_descriptor == NULL) { + log_e("Descriptor Malloc Failed"); + return false; + } + uint8_t * dst = tinyusb_config_descriptor + TUD_CONFIG_DESC_LEN; + + for(int i=0; i> 4); + *srl++ = nibble_to_hex_char(b & 0xf); + } + *srl++ = '\0'; +} + +static void tinyusb_apply_device_config(tinyusb_device_config_t *config){ + if(config->product_name){ + snprintf(USB_DEVICE_PRODUCT, 126, "%s", config->product_name); + } + + if(config->manufacturer_name){ + snprintf(USB_DEVICE_MANUFACTURER, 126, "%s", config->manufacturer_name); + } + + if(config->serial_number && config->serial_number[0]){ + snprintf(USB_DEVICE_SERIAL, 126, "%s", config->serial_number); + } else { + set_usb_serial_num(); + } + + if(config->webusb_url){ + snprintf(WEBUSB_URL, 126, "%s", config->webusb_url); + } + + // Windows 10 will not recognize the CDC device if WebUSB is enabled and USB Class is not 2 (CDC) + if( + (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) + && config->webusb_enabled + && (config->usb_class != TUSB_CLASS_CDC) + ){ + config->usb_class = TUSB_CLASS_CDC; + config->usb_protocol = 0x00; + } + + WEBUSB_ENABLED = config->webusb_enabled; + USB_DEVICE_ATTRIBUTES = config->usb_attributes; + USB_DEVICE_POWER = config->usb_power_ma; + + tinyusb_device_descriptor.bcdUSB = config->usb_version; + tinyusb_device_descriptor.idVendor = config->vid; + tinyusb_device_descriptor.idProduct = config->pid; + tinyusb_device_descriptor.bcdDevice = config->fw_version; + tinyusb_device_descriptor.bDeviceClass = config->usb_class; + tinyusb_device_descriptor.bDeviceSubClass = config->usb_subclass; + tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol; +} + +// USB Device Driver task +// This top level thread processes all usb events and invokes callbacks +static void usb_device_task(void *param) { + (void)param; + while(1) tud_task(); // RTOS forever loop +} + +/* + * PUBLIC API + * */ +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR + const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"}; +#endif +static bool tinyusb_is_initialized = false; + +esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb) +{ + if(tinyusb_is_initialized){ + log_e("TinyUSB has already started! Interface %s not enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); + return ESP_FAIL; + } + if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){ + log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]); + return ESP_FAIL; + } + if(interface == USB_INTERFACE_CDC){ + if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){ + log_e("CDC Reserve Endpoints Failed"); + return ESP_FAIL; + } + } + tinyusb_loaded_interfaces_mask |= (1U << interface); + tinyusb_config_descriptor_len += descriptor_len; + tinyusb_loaded_interfaces_callbacks[interface] = cb; + log_d("Interface %s enabled", tinyusb_interface_names[interface]); + return ESP_OK; +} + +esp_err_t tinyusb_init(tinyusb_device_config_t *config) { + if(tinyusb_is_initialized){ + return ESP_OK; + } + tinyusb_is_initialized = true; + + //tinyusb_endpoints.val = 0; + tinyusb_apply_device_config(config); + if (!tinyusb_load_enabled_interfaces()) { + tinyusb_is_initialized = false; + return ESP_FAIL; + } + + bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA); + + //if(usb_did_persist && usb_persist_enabled){ + // Enable USB/IO_MUX peripheral reset, if coming from persistent reboot + REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE); + REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE); + //} else + if(!usb_did_persist || !usb_persist_enabled){ + // Reset USB module + periph_ll_reset(PERIPH_USB_MODULE); + periph_ll_enable_clk_clear_rst(PERIPH_USB_MODULE); + } + + tinyusb_config_t tusb_cfg = { + .external_phy = false // In the most cases you need to use a `false` value + }; + esp_err_t err = tinyusb_driver_install(&tusb_cfg); + if (err != ESP_OK) { + tinyusb_is_initialized = false; + return err; + } + xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL); + return err; +} + +uint8_t tinyusb_add_string_descriptor(const char * str){ + if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){ + return 0; + } + uint8_t index = tinyusb_string_descriptor_len; + tinyusb_string_descriptor[tinyusb_string_descriptor_len++] = (char*)str; + return index; +} + +uint8_t tinyusb_get_free_duplex_endpoint(void){ + if(!tinyusb_has_available_fifos()){ + log_e("No available IN endpoints"); + return 0; + } + for(uint8_t i=1; i<7; i++){ + if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0){ + tinyusb_endpoints.in |= BIT(i); + tinyusb_endpoints.out |= BIT(i); + return i; + } + } + log_e("No available duplex endpoints"); + return 0; +} + +uint8_t tinyusb_get_free_in_endpoint(void){ + if(!tinyusb_has_available_fifos()){ + log_e("No available IN endpoints"); + return 0; + } + for(uint8_t i=1; i<7; i++){ + if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0){ + tinyusb_endpoints.in |= BIT(i); + return i; + } + } + for(uint8_t i=1; i<7; i++){ + if((tinyusb_endpoints.in & BIT(i)) == 0){ + tinyusb_endpoints.in |= BIT(i); + return i; + } + } + return 0; +} + +uint8_t tinyusb_get_free_out_endpoint(void){ + for(uint8_t i=1; i<7; i++){ + if((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0){ + tinyusb_endpoints.out |= BIT(i); + return i; + } + } + for(uint8_t i=1; i<7; i++){ + if((tinyusb_endpoints.out & BIT(i)) == 0){ + tinyusb_endpoints.out |= BIT(i); + return i; + } + } + return 0; +} + +#endif /* CONFIG_TINYUSB_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-tinyusb.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-tinyusb.h new file mode 100644 index 0000000..a9213fd --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-tinyusb.h @@ -0,0 +1,110 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#include "soc/soc_caps.h" +#if SOC_USB_OTG_SUPPORTED + +#include "esp32-hal.h" + +#if CONFIG_TINYUSB_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tusb.h" +#include "tusb_option.h" +#include "tusb_config.h" + +#define USB_ESPRESSIF_VID 0x303A +#define USB_STRING_DESCRIPTOR_ARRAY_SIZE 10 + +typedef struct { + uint16_t vid; + uint16_t pid; + const char * product_name; + const char * manufacturer_name; + const char * serial_number; + uint16_t fw_version; + + uint16_t usb_version; + uint8_t usb_class; + uint8_t usb_subclass; + uint8_t usb_protocol; + uint8_t usb_attributes; + uint16_t usb_power_ma; + + bool webusb_enabled; + const char * webusb_url; +} tinyusb_device_config_t; + +#define TINYUSB_CONFIG_DEFAULT() { \ + .vid = USB_ESPRESSIF_VID, \ + .pid = 0x0002, \ + .product_name = CONFIG_TINYUSB_DESC_PRODUCT_STRING, \ + .manufacturer_name = CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, \ + .serial_number = CONFIG_TINYUSB_DESC_SERIAL_STRING, \ + .fw_version = CONFIG_TINYUSB_DESC_BCDDEVICE, \ + .usb_version = 0x0200, \ + .usb_class = TUSB_CLASS_MISC, \ + .usb_subclass = MISC_SUBCLASS_COMMON, \ + .usb_protocol = MISC_PROTOCOL_IAD, \ + .usb_attributes = TUSB_DESC_CONFIG_ATT_SELF_POWERED, \ + .usb_power_ma = 500, \ + .webusb_enabled = false, \ + .webusb_url = "espressif.github.io/arduino-esp32/webusb.html" \ +} + +esp_err_t tinyusb_init(tinyusb_device_config_t *config); + +/* + * USB Persistence API + * */ +typedef enum { + RESTART_NO_PERSIST, + RESTART_PERSIST, + RESTART_BOOTLOADER, + RESTART_BOOTLOADER_DFU, + RESTART_TYPE_MAX +} restart_type_t; + +void usb_persist_restart(restart_type_t mode); + +// The following definitions and functions are to be used only by the drivers +typedef enum { + USB_INTERFACE_MSC, + USB_INTERFACE_DFU, + USB_INTERFACE_HID, + USB_INTERFACE_VENDOR, + USB_INTERFACE_CDC, + USB_INTERFACE_MIDI, + USB_INTERFACE_CUSTOM, + USB_INTERFACE_MAX +} tinyusb_interface_t; + +typedef uint16_t (*tinyusb_descriptor_cb_t)(uint8_t * dst, uint8_t * itf); + +esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb); +uint8_t tinyusb_add_string_descriptor(const char * str); +uint8_t tinyusb_get_free_duplex_endpoint(void); +uint8_t tinyusb_get_free_in_endpoint(void); +uint8_t tinyusb_get_free_out_endpoint(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_TINYUSB_ENABLED */ +#endif /* SOC_USB_OTG_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-touch.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-touch.c new file mode 100644 index 0000000..9c49ece --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-touch.c @@ -0,0 +1,338 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "soc/soc_caps.h" + +#if SOC_TOUCH_SENSOR_SUPPORTED +#include "driver/touch_sensor.h" +#include "esp32-hal-touch.h" +#include "esp32-hal-periman.h" + +/* + Internal Private Touch Data Structure and Functions +*/ + +#if SOC_TOUCH_VERSION_1 // ESP32 +static uint16_t __touchSleepCycles = 0x1000; +static uint16_t __touchMeasureCycles = 0x1000; +#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 +static uint16_t __touchSleepCycles = TOUCH_PAD_SLEEP_CYCLE_DEFAULT; +static uint16_t __touchMeasureCycles = TOUCH_PAD_MEASURE_CYCLE_DEFAULT; +#endif + +typedef void (*voidFuncPtr)(void); +typedef void (*voidArgFuncPtr)(void *); + +typedef struct { + voidFuncPtr fn; + bool callWithArgs; + void* arg; +#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3 + bool lastStatusIsPressed; +#endif +} TouchInterruptHandle_t; + +static TouchInterruptHandle_t __touchInterruptHandlers[SOC_TOUCH_SENSOR_NUM] = {0,}; + +static uint8_t used_pads = 0; +static bool initialized = false; +static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = { false }; + +static void ARDUINO_ISR_ATTR __touchISR(void * arg) +{ +#if SOC_TOUCH_VERSION_1 // ESP32 + uint32_t pad_intr = touch_pad_get_status(); + //clear interrupt + touch_pad_clear_status(); + // call Pad ISR User callback + for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) { + if ((pad_intr >> i) & 0x01) { + if(__touchInterruptHandlers[i].fn){ + // keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)" + if (__touchInterruptHandlers[i].callWithArgs) { + ((voidArgFuncPtr)__touchInterruptHandlers[i].fn)(__touchInterruptHandlers[i].arg); + } else { + __touchInterruptHandlers[i].fn(); + } + } + } + } +#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 + touch_pad_intr_mask_t evt = touch_pad_read_intr_status_mask(); + uint8_t pad_num = touch_pad_get_current_meas_channel(); + if (evt & TOUCH_PAD_INTR_MASK_ACTIVE) { + // touch has been pressed / touched + __touchInterruptHandlers[pad_num].lastStatusIsPressed = true; + } + if (evt & TOUCH_PAD_INTR_MASK_INACTIVE) { + // touch has been released / untouched + __touchInterruptHandlers[pad_num].lastStatusIsPressed = false; + } + if(__touchInterruptHandlers[pad_num].fn){ + // keeping backward compatibility with "void cb(void)" and with new "void cb(vooid *)" + if (__touchInterruptHandlers[pad_num].callWithArgs) { + ((voidArgFuncPtr)__touchInterruptHandlers[pad_num].fn)(__touchInterruptHandlers[pad_num].arg); + } else { + __touchInterruptHandlers[pad_num].fn(); + } + } +#endif +} + + + +static void __touchSetCycles(uint16_t measure, uint16_t sleep) +{ + __touchSleepCycles = sleep; + __touchMeasureCycles = measure; +#if SOC_TOUCH_VERSION_1 // ESP32 + touch_pad_set_measurement_clock_cycles(measure); +#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 + touch_pad_set_charge_discharge_times(measure); +#endif + touch_pad_set_measurement_interval(sleep); +} + +static bool touchDetachBus(void * pin){ + int8_t pad = digitalPinToTouchChannel((int)(pin-1)); + channels_initialized[pad] = false; + used_pads--; + if (used_pads == 0) { + if (touch_pad_deinit() != ESP_OK) //deinit touch module, as no pads are used + { + log_e("Touch module deinit failed!"); + return false; + } + initialized = false; + } + return true; +} + +static void __touchInit() +{ + if(initialized){ + return; + } + + esp_err_t err = ESP_OK; + +#if SOC_TOUCH_VERSION_1 // ESP32 + err = touch_pad_init(); + if (err != ESP_OK) { + goto err; + } + // the next two lines will drive the touch reading values -- both will return ESP_OK + touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V); + touch_pad_set_measurement_clock_cycles(__touchMeasureCycles); + touch_pad_set_measurement_interval(__touchSleepCycles); + // Touch Sensor Timer initiated + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK + err = touch_pad_filter_start(10); + if (err != ESP_OK) { + goto err; + } + // keep ISR activated - it can run all together (ISR + touchRead()) + err = touch_pad_isr_register(__touchISR, NULL); + if (err != ESP_OK) { + goto err; + } + touch_pad_intr_enable(); // returns ESP_OK +#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 + err = touch_pad_init(); + if (err != ESP_OK) { + goto err; + } + // the next lines will drive the touch reading values -- all os them return ESP_OK + touch_pad_set_charge_discharge_times(__touchMeasureCycles); + touch_pad_set_measurement_interval(__touchSleepCycles); + touch_pad_set_voltage(TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD, TOUCH_PAD_LOW_VOLTAGE_THRESHOLD, TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD); + touch_pad_set_idle_channel_connect(TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT); + touch_pad_denoise_t denoise = { + .grade = TOUCH_PAD_DENOISE_BIT4, + .cap_level = TOUCH_PAD_DENOISE_CAP_L4, + }; + touch_pad_denoise_set_config(&denoise); + touch_pad_denoise_enable(); + // Touch Sensor Timer initiated + touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK + touch_pad_fsm_start(); // returns ESP_OK + //ISR setup moved to __touchChannelInit +#endif + + initialized = true; + return; +err: + log_e(" Touch sensor initialization error."); + initialized = false; + return; +} + +static void __touchChannelInit(int pad) +{ + if(channels_initialized[pad]){ + return; + } + +#if SOC_TOUCH_VERSION_1 // ESP32 + // Initial no Threshold and setup + __touchInterruptHandlers[pad].fn = NULL; + touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK +#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3 + // Initial no Threshold and setup + __touchInterruptHandlers[pad].fn = NULL; + touch_pad_config(pad); // returns ESP_OK + // keep ISR activated - it can run all together (ISR + touchRead()) + esp_err_t err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); + if (err != ESP_OK) { + log_e(" Touch sensor initialization error."); + return; + } + touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK +#endif + + channels_initialized[pad] = true; + used_pads++; + delay(20); //delay needed before reading from touch channel after config +} + +static touch_value_t __touchRead(uint8_t pin) +{ + int8_t pad = digitalPinToTouchChannel(pin); + if(pad < 0){ + log_e(" No touch pad on selected pin!"); + return 0; + } + + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_TOUCH) == NULL){ + perimanSetBusDeinit(ESP32_BUS_TYPE_TOUCH, touchDetachBus); + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_INIT, NULL)){ + return 0; + } + __touchInit(); + __touchChannelInit(pad); + + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_TOUCH, (void *)(pin+1))){ + touchDetachBus((void *)(pin+1)); + return 0; + } + } + + touch_value_t touch_value; + touch_pad_read_raw_data(pad, &touch_value); + + return touch_value; +} + +static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Args, touch_value_t threshold, bool callWithArgs) +{ + int8_t pad = digitalPinToTouchChannel(pin); + if(pad < 0){ + log_e(" No touch pad on selected pin!"); + return; + } + + if (userFunc == NULL) { + // dettach ISR User Call + __touchInterruptHandlers[pad].fn = NULL; + threshold = SOC_TOUCH_PAD_THRESHOLD_MAX; // deactivate the ISR with SOC_TOUCH_PAD_THRESHOLD_MAX + } else { + // attach ISR User Call + __touchInit(); + __touchChannelInit(pad); + __touchInterruptHandlers[pad].fn = userFunc; + __touchInterruptHandlers[pad].callWithArgs = callWithArgs; + __touchInterruptHandlers[pad].arg = Args; + } + + touch_pad_set_thresh(pad, threshold); +} + +// it keeps backwards compatibility +static void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold) +{ + __touchConfigInterrupt(pin, userFunc, NULL, threshold, false); +} + +// new additional version of the API with User Args +static void __touchAttachArgsInterrupt(uint8_t pin, void (*userFunc)(void), void *args, touch_value_t threshold) +{ + __touchConfigInterrupt(pin, userFunc, args, threshold, true); +} + +// new additional API to dettach touch ISR +static void __touchDettachInterrupt(uint8_t pin) +{ + __touchConfigInterrupt(pin, NULL, NULL, 0, false); // userFunc as NULL acts as dettaching +} + + +/* + External Public Touch API Functions +*/ + +#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC +void touchInterruptSetThresholdDirection(bool mustbeLower) { + if (mustbeLower) { + touch_pad_set_trigger_mode(TOUCH_TRIGGER_BELOW); + } else { + touch_pad_set_trigger_mode(TOUCH_TRIGGER_ABOVE); + } +} +#elif SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3 +// returns true if touch pad has been and continues pressed and false otherwise +bool touchInterruptGetLastStatus(uint8_t pin) { + int8_t pad = digitalPinToTouchChannel(pin); + if(pad < 0){ + return false; + } + + return __touchInterruptHandlers[pad].lastStatusIsPressed; +} +#endif + +void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold) +{ + int8_t pad = digitalPinToTouchChannel(pin); + if(pad < 0){ + log_e(" No touch pad on selected pin!"); + return; + } + + if(perimanGetPinBus(pin, ESP32_BUS_TYPE_TOUCH) == NULL){ + perimanSetBusDeinit(ESP32_BUS_TYPE_TOUCH, touchDetachBus); + __touchInit(); + __touchChannelInit(pad); + if(!perimanSetPinBus(pin, ESP32_BUS_TYPE_TOUCH, (void *)(pin+1))){ + log_e("Failed to set bus to Peripheral manager"); + touchDetachBus((void *)(pin+1)); + return; + } + } + #if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC + touch_pad_set_thresh(pad, threshold); + + #elif SOC_TOUCH_VERSION_2 + touch_pad_sleep_channel_enable(pad, true); + touch_pad_sleep_set_threshold(pad, threshold); + + #endif + esp_sleep_enable_touchpad_wakeup(); +} + +extern touch_value_t touchRead(uint8_t) __attribute__ ((weak, alias("__touchRead"))); +extern void touchAttachInterrupt(uint8_t, voidFuncPtr, touch_value_t) __attribute__ ((weak, alias("__touchAttachInterrupt"))); +extern void touchAttachInterruptArg(uint8_t, voidArgFuncPtr, void *, touch_value_t) __attribute__ ((weak, alias("__touchAttachArgsInterrupt"))); +extern void touchDetachInterrupt(uint8_t) __attribute__ ((weak, alias("__touchDettachInterrupt"))); +extern void touchSetCycles(uint16_t, uint16_t) __attribute__ ((weak, alias("__touchSetCycles"))); + +#endif /* SOC_TOUCH_SENSOR_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-touch.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-touch.h new file mode 100644 index 0000000..780b5ab --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-touch.h @@ -0,0 +1,102 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef MAIN_ESP32_HAL_TOUCH_H_ +#define MAIN_ESP32_HAL_TOUCH_H_ + +#include "soc/soc_caps.h" +#if SOC_TOUCH_SENSOR_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp32-hal.h" + +#if !defined(SOC_TOUCH_VERSION_1) && !defined(SOC_TOUCH_VERSION_2) +#error Touch IDF driver Not supported! +#endif + +#if SOC_TOUCH_VERSION_1 // ESP32 +typedef uint16_t touch_value_t; +#elif SOC_TOUCH_VERSION_2 // ESP32S2 ESP32S3 +typedef uint32_t touch_value_t; +#endif + +/* + * Set cycles that measurement operation takes + * The result from touchRead, threshold and detection + * accuracy depend on these values. Defaults are + * 0x1000 for measure and 0x1000 for sleep. + * With default values touchRead takes 0.5ms + * */ +void touchSetCycles(uint16_t measure, uint16_t sleep); + +/* + * Read touch pad (for ESP32 values close to 0 mean touch detected / + * for ESP32-S2/S3 higher values mean touch detected) + * You can use this method to chose a good threshold value + * to use as value for touchAttachInterrupt + * */ +touch_value_t touchRead(uint8_t pin); + +/* + * Set function to be called if touch pad value falls (ESP32) + * below the given threshold / rises (ESP32-S2/S3) by given increment (threshold). + * Use touchRead to determine a proper threshold between touched and untouched state + * */ +void touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), touch_value_t threshold); +void touchAttachInterruptArg(uint8_t pin, void (*userFunc)(void*), void *arg, touch_value_t threshold); +void touchDetachInterrupt(uint8_t pin); + +/* + * Specific functions to ESP32 + * Tells the driver if it shall activate the ISR if the sensor is Lower or Higher than the Threshold + * Default if Lower. + **/ + +#if SOC_TOUCH_VERSION_1 // Only for ESP32 SoC +void touchInterruptSetThresholdDirection(bool mustbeLower); +#endif + + +/* + * Specific functions to ESP32-S2 and ESP32-S3 + * Returns true when the latest ISR status for the Touchpad is that it is touched (Active) + * and false when the Touchpad is untoouched (Inactive) + * This function can be used in conjunction with ISR User callback in order to take action + * as soon as the touchpad is touched and/or released + **/ + +#if SOC_TOUCH_VERSION_2 // Only for ESP32S2 and ESP32S3 +// returns true if touch pad has been and continues pressed and false otherwise +bool touchInterruptGetLastStatus(uint8_t pin); +#endif + +/* + * Setup touch pad wake up from deep sleep with given threshold. + **/ +void touchSleepWakeUpEnable(uint8_t pin, touch_value_t threshold); + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_TOUCH_SENSOR_SUPPORTED */ +#endif /* MAIN_ESP32_HAL_TOUCH_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-uart.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-uart.c new file mode 100644 index 0000000..243eb16 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-uart.c @@ -0,0 +1,1018 @@ +// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-uart.h" + +#if SOC_UART_SUPPORTED +#include "esp32-hal.h" +#include "esp32-hal-periman.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "driver/uart.h" +#include "hal/uart_ll.h" +#include "soc/soc_caps.h" +#include "soc/uart_struct.h" +#include "soc/uart_periph.h" +#include "rom/ets_sys.h" +#include "rom/gpio.h" + +#include "driver/gpio.h" +#include "hal/gpio_hal.h" +#include "esp_rom_gpio.h" + +static int s_uart_debug_nr = 0; + +struct uart_struct_t { + +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t lock; +#endif + + uint8_t num; + bool has_peek; + uint8_t peek_byte; + QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function + int8_t _rxPin, _txPin, _ctsPin, _rtsPin; // UART GPIOs +}; + +#if CONFIG_DISABLE_HAL_LOCKS + +#define UART_MUTEX_LOCK() +#define UART_MUTEX_UNLOCK() + +static uart_t _uart_bus_array[] = { + {0, false, 0, NULL, -1, -1, -1, -1}, +#if SOC_UART_NUM > 1 + {1, false, 0, NULL, -1, -1, -1, -1}, +#endif +#if SOC_UART_NUM > 2 + {2, false, 0, NULL, -1, -1, -1, -1}, +#endif +}; + +#else + +#define UART_MUTEX_LOCK() if(uart->lock != NULL) do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS) +#define UART_MUTEX_UNLOCK() if(uart->lock != NULL) xSemaphoreGive(uart->lock) + +static uart_t _uart_bus_array[] = { + {NULL, 0, false, 0, NULL, -1, -1, -1, -1}, +#if SOC_UART_NUM > 1 + {NULL, 1, false, 0, NULL, -1, -1, -1, -1}, +#endif +#if SOC_UART_NUM > 2 + {NULL, 2, false, 0, NULL, -1, -1, -1, -1}, +#endif +}; + +#endif + +// Negative Pin Number will keep it unmodified, thus this function can detach individual pins +// This function will also unset the pins in the Peripheral Manager and set the pin to -1 after detaching +static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + bool retCode = true; + //log_v("detaching UART%d pins: prev,pin RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + // detaches pins and sets Peripheral Manager and UART information + if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + uart->_rxPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(rxPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach RX pin %d", uart_num, rxPin); + } + } + if (txPin >= 0 && uart->_txPin == txPin && perimanGetPinBusType(txPin) == ESP32_BUS_TYPE_UART_TX) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[txPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(txPin, SIG_GPIO_OUT_IDX, false, false); + uart->_txPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(txPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach TX pin %d", uart_num, txPin); + } + } + if (ctsPin >= 0 && uart->_ctsPin == ctsPin && perimanGetPinBusType(ctsPin) == ESP32_BUS_TYPE_UART_CTS) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[ctsPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); + uart->_ctsPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach CTS pin %d", uart_num, ctsPin); + } + } + if (rtsPin >= 0 && uart->_rtsPin == rtsPin && perimanGetPinBusType(rtsPin) == ESP32_BUS_TYPE_UART_RTS) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rtsPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(rtsPin, SIG_GPIO_OUT_IDX, false, false); + uart->_rtsPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach RTS pin %d", uart_num, rtsPin); + } + } + return retCode; +} + +// Peripheral Manager detach callback for each specific UART PIN +static bool _uartDetachBus_RX(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_RX bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, bus->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + +static bool _uartDetachBus_TX(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_TX bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, bus->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + + +static bool _uartDetachBus_CTS(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_CTS bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_ctsPin, UART_PIN_NO_CHANGE); +} + +static bool _uartDetachBus_RTS(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_RTS bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_rtsPin); +} + +// Attach function for UART +// connects the IO Pad, set Paripheral Manager and internal UART structure data +static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + //log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + + bool retCode = true; + if (rxPin >= 0) { + // connect RX Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(rxPin, ESP32_BUS_TYPE_UART_RX, (void *)uart); + if (ret) uart->_rxPin = rxPin; + } + if (!ret) { + log_e("UART%d failed to attach RX pin %d", uart_num, rxPin); + } + retCode &= ret; + } + if (txPin >= 0) { + // connect TX Pad + bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(txPin, ESP32_BUS_TYPE_UART_TX, (void *)uart); + if (ret) uart->_txPin = txPin; + } + if (!ret) { + log_e("UART%d failed to attach TX pin %d", uart_num, txPin); + } + retCode &= ret; + } + if (ctsPin >= 0) { + // connect CTS Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin); + if (ret) { + ret &= perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_UART_CTS, (void *)uart); + if (ret) uart->_ctsPin = ctsPin; + } + if (!ret) { + log_e("UART%d failed to attach CTS pin %d", uart_num, ctsPin); + } + retCode &= ret; + } + if (rtsPin >= 0) { + // connect RTS Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_UART_RTS, (void *)uart); + if (ret) uart->_rtsPin = rtsPin; + } + if (!ret) { + log_e("UART%d failed to attach RTS pin %d", uart_num, rtsPin); + } + retCode &= ret; + } + return retCode; +} + +// just helper functions +int8_t uart_get_RxPin(uint8_t uart_num) +{ + return _uart_bus_array[uart_num]._rxPin; +} + +int8_t uart_get_TxPin(uint8_t uart_num) +{ + return _uart_bus_array[uart_num]._txPin; +} + +void uart_init_PeriMan(void) +{ + // set Peripheral Manager deInit Callback for each UART pin + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RX, _uartDetachBus_RX); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_TX, _uartDetachBus_TX); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_CTS, _uartDetachBus_CTS); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RTS, _uartDetachBus_RTS); +} + +// Routines that take care of UART events will be in the HardwareSerial Class code +void uartGetEventQueue(uart_t* uart, QueueHandle_t *q) +{ + // passing back NULL for the Queue pointer when UART is not initialized yet + *q = NULL; + if(uart == NULL) { + return; + } + *q = uart->uart_event_queue; + return; +} + +bool uartIsDriverInstalled(uart_t* uart) +{ + if(uart == NULL) { + return false; + } + + if (uart_is_driver_installed(uart->num)) { + return true; + } + return false; +} + +// Negative Pin Number will keep it unmodified, thus this function can set individual pins +// When pins are changed, it will detach the previous one +bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + + bool retCode = true; + UART_MUTEX_LOCK(); + + //log_v("setting UART%d pins: prev->new RX(%d->%d) TX(%d->%d) CTS(%d->%d) RTS(%d->%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + // First step: detachs all previous UART pins + bool rxPinChanged = rxPin >= 0 && rxPin != uart->_rxPin; + if (rxPinChanged) { + retCode &= _uartDetachPins(uart_num, uart->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + bool txPinChanged = txPin >= 0 && txPin != uart->_txPin; + if (txPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, uart->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + bool ctsPinChanged = ctsPin >= 0 && ctsPin != uart->_ctsPin; + if (ctsPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart->_ctsPin, UART_PIN_NO_CHANGE); + } + bool rtsPinChanged = rtsPin >= 0 && rtsPin != uart->_rtsPin; + if (rtsPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart->_rtsPin); + } + + // Second step: attach all UART new pins + if (rxPinChanged) { + retCode &= _uartAttachPins(uart_num, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + if (txPinChanged) { + retCode &= _uartAttachPins(uart_num, UART_PIN_NO_CHANGE, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + if (ctsPinChanged) { + retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin, UART_PIN_NO_CHANGE); + } + if (rtsPinChanged) { + retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin); + } + UART_MUTEX_UNLOCK(); + + if (!retCode) { + log_e("UART%d set pins failed."); + } + return retCode; +} + +// +bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t threshold) { + if(uart == NULL) { + return false; + } + // IDF will issue corresponding error message when mode or threshold are wrong and prevent crashing + // IDF will check (mode > HW_FLOWCTRL_CTS_RTS || threshold >= SOC_UART_FIFO_LEN) + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_hw_flow_ctrl(uart->num, mode, threshold)); + UART_MUTEX_UNLOCK(); + return retCode; +} + +uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd) +{ + if(uart_nr >= SOC_UART_NUM) { + return NULL; + } + uart_t* uart = &_uart_bus_array[uart_nr]; + + if (uart_is_driver_installed(uart_nr)) { + uartEnd(uart_nr); + } + +#if !CONFIG_DISABLE_HAL_LOCKS + if(uart->lock == NULL) { + uart->lock = xSemaphoreCreateMutex(); + if(uart->lock == NULL) { + log_e("HAL LOCK error."); + return NULL; + } + } +#endif + UART_MUTEX_LOCK(); + + uart_config_t uart_config; + uart_config.data_bits = (config & 0xc) >> 2; + uart_config.parity = (config & 0x3); + uart_config.stop_bits = (config & 0x30) >> 4; + uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; + uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd; + uart_config.baud_rate = baudrate; + // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6 + uart_config.source_clk = UART_SCLK_DEFAULT; + bool retCode = ESP_OK == uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0); + if (retCode) retCode &= ESP_OK == uart_param_config(uart_nr, &uart_config); + + // Is it right or the idea is to swap rx and tx pins? + if (retCode && inverted) { + // invert signal for both Rx and Tx + retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV); + } + + UART_MUTEX_UNLOCK(); + // uartSetPins detaches previous pins if new ones are used over a previous begin() + if (retCode) retCode &= uartSetPins(uart_nr, rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + + if (retCode) uartFlush(uart); + else { + uartEnd(uart_nr); + uart = NULL; + log_e("UART%d initialization error.", uart->num); + } + + log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin); + return uart; +} + +// This function code is under testing - for now just keep it here +void uartSetFastReading(uart_t* uart) +{ + if(uart == NULL) { + return; + } + + UART_MUTEX_LOCK(); + // override default RX IDF Driver Interrupt - no BREAK, PARITY or OVERFLOW + uart_intr_config_t uart_intr = { + .intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT, // only these IRQs - no BREAK, PARITY or OVERFLOW + .rx_timeout_thresh = 1, + .txfifo_empty_intr_thresh = 10, + .rxfifo_full_thresh = 2, + }; + + ESP_ERROR_CHECK(uart_intr_config(uart->num, &uart_intr)); + UART_MUTEX_UNLOCK(); +} + + +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) +{ + if(uart == NULL) { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout)); + UART_MUTEX_UNLOCK(); + return retCode; +} + +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) +{ + if(uart == NULL) { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_rx_full_threshold(uart->num, numBytesFIFOFull)); + UART_MUTEX_UNLOCK(); + return retCode; +} + + +void uartEnd(uint8_t uart_num) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + + UART_MUTEX_LOCK(); + _uartDetachPins(uart_num, uart->_rxPin, uart->_txPin, uart->_ctsPin, uart->_rtsPin); + if(uart_is_driver_installed(uart_num)) { + uart_driver_delete(uart_num); + } + UART_MUTEX_UNLOCK(); +} + + +void uartSetRxInvert(uart_t* uart, bool invert) +{ + if (uart == NULL) + return; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + // POTENTIAL ISSUE :: original code only set/reset rxd_inv bit + // IDF or LL set/reset the whole inv_mask! + // if (invert) + // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV)); + // else + // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE)); + +#else + // this implementation is better over IDF API because it only affects RXD + // this is supported in ESP32, ESP32-S2 and ESP32-C3 + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + if (invert) + hw->conf0.rxd_inv = 1; + else + hw->conf0.rxd_inv = 0; +#endif +} + + +uint32_t uartAvailable(uart_t* uart) +{ + + if(uart == NULL) { + return 0; + } + + UART_MUTEX_LOCK(); + size_t available; + uart_get_buffered_data_len(uart->num, &available); + if (uart->has_peek) available++; + UART_MUTEX_UNLOCK(); + return available; +} + + +uint32_t uartAvailableForWrite(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + UART_MUTEX_LOCK(); + uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num)); + size_t txRingBufferAvailable = 0; + if (ESP_OK == uart_get_tx_buffer_free_size(uart->num, &txRingBufferAvailable)) { + available += txRingBufferAvailable; + } + UART_MUTEX_UNLOCK(); + return available; +} + +size_t uartReadBytes(uart_t* uart, uint8_t *buffer, size_t size, uint32_t timeout_ms) +{ + if(uart == NULL || size == 0 || buffer == NULL) { + return 0; + } + + size_t bytes_read = 0; + + UART_MUTEX_LOCK(); + + if (uart->has_peek) { + uart->has_peek = false; + *buffer++ = uart->peek_byte; + size--; + bytes_read = 1; + } + + if (size > 0) { + int len = uart_read_bytes(uart->num, buffer, size, pdMS_TO_TICKS(timeout_ms)); + if (len < 0) len = 0; // error reading UART + bytes_read += len; + } + + + UART_MUTEX_UNLOCK(); + return bytes_read; +} + +// DEPRICATED but the original code will be kepts here as future reference when a final solution +// to the UART driver is defined in the use case of reading byte by byte from UART. +uint8_t uartRead(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + uint8_t c = 0; + + UART_MUTEX_LOCK(); + + if (uart->has_peek) { + uart->has_peek = false; + c = uart->peek_byte; + } else { + + int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_PERIOD_MS); + if (len <= 0) { // includes negative return from IDF in case of error + c = 0; + } + } + UART_MUTEX_UNLOCK(); + return c; +} + + +uint8_t uartPeek(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + uint8_t c = 0; + + UART_MUTEX_LOCK(); + + if (uart->has_peek) { + c = uart->peek_byte; + } else { + int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_PERIOD_MS); + if (len <= 0) { // includes negative return from IDF in case of error + c = 0; + } else { + uart->has_peek = true; + uart->peek_byte = c; + } + } + UART_MUTEX_UNLOCK(); + return c; +} + +void uartWrite(uart_t* uart, uint8_t c) +{ + if(uart == NULL) { + return; + } + UART_MUTEX_LOCK(); + uart_write_bytes(uart->num, &c, 1); + UART_MUTEX_UNLOCK(); +} + +void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len) +{ + if(uart == NULL || data == NULL || !len) { + return; + } + + UART_MUTEX_LOCK(); + uart_write_bytes(uart->num, data, len); + UART_MUTEX_UNLOCK(); +} + +void uartFlush(uart_t* uart) +{ + uartFlushTxOnly(uart, true); +} + +void uartFlushTxOnly(uart_t* uart, bool txOnly) +{ + if(uart == NULL) { + return; + } + + UART_MUTEX_LOCK(); + while(!uart_ll_is_tx_idle(UART_LL_GET_HW(uart->num))); + + if ( !txOnly ) { + ESP_ERROR_CHECK(uart_flush_input(uart->num)); + } + UART_MUTEX_UNLOCK(); +} + +void uartSetBaudRate(uart_t* uart, uint32_t baud_rate) +{ + if(uart == NULL) { + return; + } + UART_MUTEX_LOCK(); + uint32_t sclk_freq; + if(uart_get_sclk_freq(UART_SCLK_DEFAULT, &sclk_freq) == ESP_OK){ + uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate, sclk_freq); + } + UART_MUTEX_UNLOCK(); +} + +uint32_t uartGetBaudRate(uart_t* uart) +{ + uint32_t baud_rate = 0; + uint32_t sclk_freq; + + if(uart == NULL) { + return 0; + } + + UART_MUTEX_LOCK(); + if(uart_get_sclk_freq(UART_SCLK_DEFAULT, &sclk_freq) == ESP_OK){ + baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num), sclk_freq); + } + UART_MUTEX_UNLOCK(); + return baud_rate; +} + +static void ARDUINO_ISR_ATTR uart0_write_char(char c) +{ + while (uart_ll_get_txfifo_len(&UART0) == 0); + uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1); +} + +#if SOC_UART_NUM > 1 +static void ARDUINO_ISR_ATTR uart1_write_char(char c) +{ + while (uart_ll_get_txfifo_len(&UART1) == 0); + uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1); +} +#endif + +#if SOC_UART_NUM > 2 +static void ARDUINO_ISR_ATTR uart2_write_char(char c) +{ + while (uart_ll_get_txfifo_len(&UART2) == 0); + uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1); +} +#endif + +void uart_install_putc() +{ + switch(s_uart_debug_nr) { + case 0: + ets_install_putc1((void (*)(char)) &uart0_write_char); + break; +#if SOC_UART_NUM > 1 + case 1: + ets_install_putc1((void (*)(char)) &uart1_write_char); + break; +#endif +#if SOC_UART_NUM > 2 + case 2: + ets_install_putc1((void (*)(char)) &uart2_write_char); + break; +#endif + default: + ets_install_putc1(NULL); + break; + } +} + +// Routines that take care of UART mode in the HardwareSerial Class code +// used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips +bool uartSetMode(uart_t *uart, uart_mode_t mode) +{ + if (uart == NULL || uart->num >= SOC_UART_NUM) + { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_mode(uart->num, mode)); + UART_MUTEX_UNLOCK(); + return retCode; +} + +void uartSetDebug(uart_t* uart) +{ + if(uart == NULL || uart->num >= SOC_UART_NUM) { + s_uart_debug_nr = -1; + } else { + s_uart_debug_nr = uart->num; + } + uart_install_putc(); +} + +int uartGetDebug() +{ + return s_uart_debug_nr; +} + +int log_printfv(const char *format, va_list arg) +{ + static char loc_buf[64]; + char * temp = loc_buf; + uint32_t len; + va_list copy; + va_copy(copy, arg); + len = vsnprintf(NULL, 0, format, copy); + va_end(copy); + if(len >= sizeof(loc_buf)){ + temp = (char*)malloc(len+1); + if(temp == NULL) { + return 0; + } + } +#if !CONFIG_DISABLE_HAL_LOCKS + if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ + xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY); + } +#endif + +#if CONFIG_IDF_TARGET_ESP32C3 + vsnprintf(temp, len+1, format, arg); + ets_printf("%s", temp); +#else + int wlen = vsnprintf(temp, len+1, format, arg); + for (int i = 0; i < wlen; i++) { + ets_write_char_uart(temp[i]); + } +#endif + +#if !CONFIG_DISABLE_HAL_LOCKS + if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ + xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock); + } +#endif + if(len >= sizeof(loc_buf)){ + free(temp); + } + return len; +} + +int log_printf(const char *format, ...) +{ + int len; + va_list arg; + va_start(arg, format); + len = log_printfv(format, arg); + va_end(arg); + return len; +} + + +static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){ + for(size_t i = 0; i 16){ + for(size_t i = len; i<16; i++){ + log_printf(" "); + } + log_printf(" // "); + } else { + log_printf(" // "); + } + for(size_t i = 0; i= 0x20) && (b[i] < 0x80))?b[i]:'.'); + } + log_printf("\n"); +} + +void log_print_buf(const uint8_t *b, size_t len){ + if(!len || !b){ + return; + } + for(size_t i = 0; i 16){ + log_printf("/* 0x%04X */ ", i); + } + log_print_buf_line(b+i, ((len-i)<16)?(len - i):16, len); + } +} + +/* + * if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two. + * This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses. + */ +unsigned long uartBaudrateDetect(uart_t *uart, bool flg) +{ +// Baud rate detection only works for ESP32 and ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + if(uart == NULL) { + return 0; + } + + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + + while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num) + if(flg) return 0; + ets_delay_us(1000); + } + + UART_MUTEX_LOCK(); + //log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt); + unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1); + UART_MUTEX_UNLOCK(); + + return ret; +#else + return 0; +#endif +} + + +/* + * To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is + * detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is + * rounded to the closed real baudrate. + * + * ESP32-C3 reports wrong baud rate detection as shown below: + * + * This will help in a future recall for the C3. + * Baud Sent: Baud Read: + * 300 --> 19536 + * 2400 --> 19536 + * 4800 --> 19536 + * 9600 --> 28818 + * 19200 --> 57678 + * 38400 --> 115440 + * 57600 --> 173535 + * 115200 --> 347826 + * 230400 --> 701754 + * + * +*/ +void uartStartDetectBaudrate(uart_t *uart) { + if(uart == NULL) { + return; + } + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + + // ESP32-C3 requires further testing + // Baud rate detection returns wrong values + + log_e("ESP32-C3 baud rate detection is not supported."); + return; + + // Code bellow for C3 kept for future recall + //hw->rx_filt.glitch_filt = 0x08; + //hw->rx_filt.glitch_filt_en = 1; + //hw->conf0.autobaud_en = 0; + //hw->conf0.autobaud_en = 1; +#elif CONFIG_IDF_TARGET_ESP32S3 + log_e("ESP32-S3 baud rate detection is not supported."); + return; +#else + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + hw->auto_baud.glitch_filt = 0x08; + hw->auto_baud.en = 0; + hw->auto_baud.en = 1; +#endif +} + +unsigned long +uartDetectBaudrate(uart_t *uart) +{ + if(uart == NULL) { + return 0; + } + +// Baud rate detection only works for ESP32 and ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + + static bool uartStateDetectingBaudrate = false; + + if(!uartStateDetectingBaudrate) { + uartStartDetectBaudrate(uart); + uartStateDetectingBaudrate = true; + } + + unsigned long divisor = uartBaudrateDetect(uart, true); + if (!divisor) { + return 0; + } + + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + hw->auto_baud.en = 0; + + uartStateDetectingBaudrate = false; // Initialize for the next round + + unsigned long baudrate = getApbFrequency() / divisor; + + //log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate); + + static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; + + size_t i; + for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate + { + if (baudrate <= default_rates[i]) + { + if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) { + i--; + } + break; + } + } + + return default_rates[i]; +#else +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + log_e("ESP32-C3 baud rate detection is not supported."); +#else + log_e("ESP32-S3 baud rate detection is not supported."); +#endif + return 0; +#endif +} + +/* + These functions are for testing puspose only and can be used in Arduino Sketches + Those are used in the UART examples +*/ + +/* + This is intended to make an internal loopback connection using IOMUX + The function uart_internal_loopback() shall be used right after Arduino Serial.begin(...) + This code "replaces" the physical wiring for connecting TX <--> RX in a loopback +*/ + +// gets the right TX SIGNAL, based on the UART number +#if SOC_UART_NUM > 2 +#define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX)) +#else +#define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : U1TXD_OUT_IDX) +#endif +/* + Make sure UART's RX signal is connected to TX pin + This creates a loop that lets us receive anything we send on the UART +*/ +void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) +{ + if (uartNum > SOC_UART_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) return; + esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false); +} + +/* + This is intended to generate BREAK in an UART line +*/ + +// Forces a BREAK in the line based on SERIAL_8N1 configuration at any baud rate +void uart_send_break(uint8_t uartNum) +{ + uint32_t currentBaudrate = 0; + uart_get_baudrate(uartNum, ¤tBaudrate); + // calculates 10 bits of breaks in microseconds for baudrates up to 500mbps + // This is very sensetive timing... it works fine for SERIAL_8N1 + uint32_t breakTime = (uint32_t) (10.0 * (1000000.0 / currentBaudrate)); + uart_set_line_inverse(uartNum, UART_SIGNAL_TXD_INV); + esp_rom_delay_us(breakTime); + uart_set_line_inverse(uartNum, UART_SIGNAL_INV_DISABLE); +} + +// Sends a buffer and at the end of the stream, it generates BREAK in the line +int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize) +{ + // 12 bits long BREAK for 8N1 + return uart_write_bytes_with_break(uartNum, (const void *)msg, msgSize, 12); +} + +#endif /* SOC_UART_SUPPORTED */ \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-uart.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-uart.h new file mode 100644 index 0000000..fbb9694 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal-uart.h @@ -0,0 +1,118 @@ +// Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MAIN_ESP32_HAL_UART_H_ +#define MAIN_ESP32_HAL_UART_H_ + +#include "soc/soc_caps.h" +#if SOC_UART_SUPPORTED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "hal/uart_types.h" + +struct uart_struct_t; +typedef struct uart_struct_t uart_t; + +uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd); +void uartEnd(uint8_t uart_num); + +// This is used to retrieve the Event Queue pointer from a UART IDF Driver in order to allow user to deal with its events +void uartGetEventQueue(uart_t* uart, QueueHandle_t *q); + +uint32_t uartAvailable(uart_t* uart); +uint32_t uartAvailableForWrite(uart_t* uart); +size_t uartReadBytes(uart_t* uart, uint8_t *buffer, size_t size, uint32_t timeout_ms); +uint8_t uartRead(uart_t* uart); +uint8_t uartPeek(uart_t* uart); + +void uartWrite(uart_t* uart, uint8_t c); +void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len); + +void uartFlush(uart_t* uart); +void uartFlushTxOnly(uart_t* uart, bool txOnly ); + +void uartSetBaudRate(uart_t* uart, uint32_t baud_rate); +uint32_t uartGetBaudRate(uart_t* uart); + +void uartSetRxInvert(uart_t* uart, bool invert); +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout); +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull); +void uartSetFastReading(uart_t* uart); + +void uartSetDebug(uart_t* uart); +int uartGetDebug(); + +bool uartIsDriverInstalled(uart_t* uart); + +// Negative Pin Number will keep it unmodified, thus this function can set individual pins +// When pins are changed, it will detach the previous ones +// Can be called before or after begin() +bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin); + +// helper functions +int8_t uart_get_RxPin(uint8_t uart_num); +int8_t uart_get_TxPin(uint8_t uart_num); +void uart_init_PeriMan(void); + + +// Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins +// UART_HW_FLOWCTRL_DISABLE = 0x0 disable hardware flow control +// UART_HW_FLOWCTRL_RTS = 0x1 enable RX hardware flow control (rts) +// UART_HW_FLOWCTRL_CTS = 0x2 enable TX hardware flow control (cts) +// UART_HW_FLOWCTRL_CTS_RTS = 0x3 enable hardware flow control +bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t threshold); + +// Used to set RS485 function -- needs to disable HW Flow Control and set RTS pin to use +// RTS pin becomes RS485 half duplex RE/DE +// UART_MODE_UART = 0x00 mode: regular UART mode +// UART_MODE_RS485_HALF_DUPLEX = 0x01 mode: half duplex RS485 UART mode control by RTS pin +// UART_MODE_IRDA = 0x02 mode: IRDA UART mode +// UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes) +// UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes) +bool uartSetMode(uart_t *uart, uart_mode_t mode); + +void uartStartDetectBaudrate(uart_t *uart); +unsigned long uartDetectBaudrate(uart_t *uart); + +/* + These functions are for testing puspose only and can be used in Arduino Sketches + Those are used in the UART examples +*/ + +// Make sure UART's RX signal is connected to TX pin +// This creates a loop that lets us receive anything we send on the UART +void uart_internal_loopback(uint8_t uartNum, int8_t rxPin); + +// Routines that generate BREAK in the UART for testing purpose + +// Forces a BREAK in the line based on SERIAL_8N1 configuration at any baud rate +void uart_send_break(uint8_t uartNum); +// Sends a buffer and at the end of the stream, it generates BREAK in the line +int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize); + + +#ifdef __cplusplus +} +#endif + +#endif /* SOC_UART_SUPPORTED */ +#endif /* MAIN_ESP32_HAL_UART_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal.h new file mode 100644 index 0000000..2f53bb2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp32-hal.h @@ -0,0 +1,160 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef HAL_ESP32_HAL_H_ +#define HAL_ESP32_HAL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_system.h" +#include "esp_sleep.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/event_groups.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef F_CPU +#define F_CPU (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * 1000000U) +#endif + +#if CONFIG_ARDUINO_ISR_IRAM +#define ARDUINO_ISR_ATTR IRAM_ATTR +#define ARDUINO_ISR_FLAG ESP_INTR_FLAG_IRAM +#else +#define ARDUINO_ISR_ATTR +#define ARDUINO_ISR_FLAG (0) +#endif + +#ifndef ARDUINO_RUNNING_CORE +#define ARDUINO_RUNNING_CORE CONFIG_ARDUINO_RUNNING_CORE +#endif + +#ifndef ARDUINO_EVENT_RUNNING_CORE +#define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE +#endif + +//forward declaration from freertos/portmacro.h +void vPortYield(void); +void yield(void); +#define optimistic_yield(u) + +#define ESP_REG(addr) *((volatile uint32_t *)(addr)) +#define NOP() asm volatile ("nop") + +#include "esp32-hal-log.h" +#include "esp32-hal-matrix.h" +#include "esp32-hal-uart.h" +#include "esp32-hal-gpio.h" +#include "esp32-hal-touch.h" +#include "esp32-hal-dac.h" +#include "esp32-hal-adc.h" +#include "esp32-hal-spi.h" +#include "esp32-hal-i2c.h" +#include "esp32-hal-ledc.h" +#include "esp32-hal-rmt.h" +#include "esp32-hal-sigmadelta.h" +#include "esp32-hal-timer.h" +#include "esp32-hal-bt.h" +#include "esp32-hal-psram.h" +#include "esp32-hal-rgb-led.h" +#include "esp32-hal-cpu.h" + +void analogWrite(uint8_t pin, int value); +void analogWriteFrequency(uint8_t pin, uint32_t freq); +void analogWriteResolution(uint8_t pin, uint8_t bits); + +//returns chip temperature in Celsius +float temperatureRead(); + +//allows user to bypass SPI RAM test routine +bool testSPIRAM(void); + +#if CONFIG_AUTOSTART_ARDUINO +//enable/disable WDT for Arduino's setup and loop functions +void enableLoopWDT(); +void disableLoopWDT(); +//feed WDT for the loop task +void feedLoopWDT(); +#endif + +//enable/disable WDT for the IDLE task on Core 0 (SYSTEM) +void enableCore0WDT(); +void disableCore0WDT(); +#ifndef CONFIG_FREERTOS_UNICORE +//enable/disable WDT for the IDLE task on Core 1 (Arduino) +void enableCore1WDT(); +void disableCore1WDT(); +#endif + +//if xCoreID < 0 or CPU is unicore, it will use xTaskCreate, else xTaskCreatePinnedToCore +//allows to easily handle all possible situations without repetitive code +BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask, + const BaseType_t xCoreID ); + +unsigned long micros(); +unsigned long millis(); +void delay(uint32_t); +void delayMicroseconds(uint32_t us); + +#if !CONFIG_ESP32_PHY_AUTO_INIT +void arduino_phy_init(); +#endif + +#if !CONFIG_AUTOSTART_ARDUINO +void initArduino(); +#endif + +typedef struct { + int core; // core which triggered panic + const char* reason; // exception string + const void* pc; // instruction address that triggered the exception + bool backtrace_corrupt; // if backtrace is corrupt + bool backtrace_continues; // if backtrace continues, but did not fit + unsigned int backtrace_len; // number of backtrace addresses + unsigned int backtrace[60]; // backtrace addresses array +} arduino_panic_info_t; + +typedef void (*arduino_panic_handler_t)(arduino_panic_info_t * info, void * arg); + +void set_arduino_panic_handler(arduino_panic_handler_t handler, void * arg); +arduino_panic_handler_t get_arduino_panic_handler(void); +void * get_arduino_panic_handler_arg(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HAL_ESP32_HAL_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp8266-compat.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp8266-compat.h new file mode 100644 index 0000000..9f9dd63 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp8266-compat.h @@ -0,0 +1,24 @@ +// esp8266-compat.h - Compatibility functions to help ESP8266 libraries and user code run on ESP32 + +// Copyright (c) 2017 Evandro Luis Copercini. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ESP8266_COMPAT_H_ +#define _ESP8266_COMPAT_H_ + +#define ICACHE_FLASH_ATTR +#define ICACHE_RAM_ATTR ARDUINO_ISR_ATTR + + +#endif /* _ESP8266_COMPAT_H_ */ \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp_arduino_version.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp_arduino_version.h new file mode 100644 index 0000000..e319d97 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/esp_arduino_version.h @@ -0,0 +1,53 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** Major version number (X.x.x) */ +#define ESP_ARDUINO_VERSION_MAJOR 3 +/** Minor version number (x.X.x) */ +#define ESP_ARDUINO_VERSION_MINOR 0 +/** Patch version number (x.x.X) */ +#define ESP_ARDUINO_VERSION_PATCH 0 + +/** + * Macro to convert ARDUINO version number into an integer + * + * To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) + */ +#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) + +/** + * Current ARDUINO version, as an integer + * + * To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) + */ +#define ESP_ARDUINO_VERSION ESP_ARDUINO_VERSION_VAL(ESP_ARDUINO_VERSION_MAJOR, \ + ESP_ARDUINO_VERSION_MINOR, \ + ESP_ARDUINO_VERSION_PATCH) + +/** + * Current ARDUINO version, as string + */ +#define df2xstr(s) #s +#define df2str(s) df2xstr(s) +#define ESP_ARDUINO_VERSION_STR df2str(ESP_ARDUINO_VERSION_MAJOR) "." df2str(ESP_ARDUINO_VERSION_MINOR) "." df2str(ESP_ARDUINO_VERSION_PATCH) + +#ifdef __cplusplus +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/firmware_msc_fat.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/firmware_msc_fat.c new file mode 100644 index 0000000..30a1a64 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/firmware_msc_fat.c @@ -0,0 +1,204 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "firmware_msc_fat.h" +//copy up to max_len chars from src to dst and do not terminate +static size_t cplstr(void *dst, const void * src, size_t max_len){ + if(!src || !dst || !max_len){ + return 0; + } + size_t l = strlen((const char *)src); + if(l > max_len){ + l = max_len; + } + memcpy(dst, src, l); + return l; +} + +//copy up to max_len chars from src to dst, adding spaces up to max_len. do not terminate +static void cplstrsp(void *dst, const void * src, size_t max_len){ + size_t l = cplstr(dst, src, max_len); + for(; l < max_len; l++){ + ((uint8_t*)dst)[l] = 0x20; + } +} + +// FAT12 +static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12"; + +static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){ + uint32_t required_bytes = (((sector_num * 3)+1)/2); + return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0); +} + +static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){ + memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE); + uint8_t * d = dst + DISK_SECTOR_SIZE; + d[0] = 0xF8; + d[1] = 0xFF; + d[2] = 0xFF; + return d; +} + +static void fat12_set_table_index(uint8_t * table, uint16_t index, uint16_t value){ + uint16_t offset = (index >> 1) * 3; + uint8_t * data = table + offset; + if(index & 1){ + data[2] = (value >> 4) & 0xFF; + data[1] = (data[1] & 0xF) | ((value & 0xF) << 4); + } else { + data[0] = value & 0xFF; + data[1] = (data[1] & 0xF0) | ((value >> 8) & 0xF); + } +} + +//FAT16 +static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16"; + +static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){ + uint32_t required_bytes = sector_num * 2; + return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & (DISK_SECTOR_SIZE - 1))?1:0); +} + +static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){ + memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE); + uint16_t * d = (uint16_t *)(dst + DISK_SECTOR_SIZE); + d[0] = 0xFFF8; + d[1] = 0xFFFF; + return (uint8_t *)d; +} + +static void fat16_set_table_index(uint8_t * table, uint16_t index, uint16_t value){ + uint16_t offset = index * 2; + *(uint16_t *)(table + offset) = value; +} + +//Interface +const char * fat_file_system_type(bool fat16) { + return ((fat16)?FAT16_FILE_SYSTEM_TYPE:FAT12_FILE_SYSTEM_TYPE); +} + +uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16){ + if(fat16){ + return fat16_sectors_per_alloc_table(sector_num); + } + return fat12_sectors_per_alloc_table(sector_num); +} + +uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16){ + if(fat16){ + return fat16_add_table(dst, boot); + } + return fat12_add_table(dst, boot); +} + +void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16){ + if(fat16){ + fat16_set_table_index(table, index, value); + } else { + fat12_set_table_index(table, index, value); + } +} + +fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number){ + fat_boot_sector_t *boot = (fat_boot_sector_t*)dst; + boot->jump_instruction[0] = 0xEB; + boot->jump_instruction[1] = 0x3C; + boot->jump_instruction[2] = 0x90; + cplstr(boot->oem_name, "MSDOS5.0", 8); + boot->bytes_per_sector = DISK_SECTOR_SIZE; + boot->sectors_per_cluster = 1; + boot->reserved_sectors_count = 1; + boot->file_alloc_tables_num = 1; + boot->max_root_dir_entries = 16; + boot->fat12_sector_num = sector_num; + boot->media_descriptor = 0xF8; + boot->sectors_per_alloc_table = table_sectors; + boot->sectors_per_track = 1; + boot->num_heads = 1; + boot->hidden_sectors_count = 0; + boot->total_sectors_32 = 0; + boot->physical_drive_number = 0x80; + boot->reserved0 = 0x00; + boot->extended_boot_signature = 0x29; + boot->serial_number = serial_number; + cplstrsp(boot->volume_label, volume_label, 11); + memset(boot->reserved, 0, 448); + cplstrsp(boot->file_system_type, file_system_type, 8); + boot->signature = 0xAA55; + return boot; +} + +fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label){ + fat_boot_sector_t * boot = (fat_boot_sector_t *)dst; + fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE)); + memset(entry, 0, sizeof(fat_dir_entry_t)); + cplstrsp(entry->volume_label, volume_label, 11); + entry->file_attr = FAT_FILE_ATTR_VOLUME_LABEL; + return entry; +} + +fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16){ + fat_boot_sector_t * boot = (fat_boot_sector_t *)dst; + uint8_t * table = dst + DISK_SECTOR_SIZE; + fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t))); + memset(entry, 0, sizeof(fat_dir_entry_t)); + cplstrsp(entry->file_name, file_name, 8); + cplstrsp(entry->file_extension, file_extension, 3); + entry->file_attr = FAT_FILE_ATTR_ARCHIVE; + entry->file_size = file_size; + entry->data_start_sector = data_start_sector; + entry->extended_attr = 0; + + uint16_t file_sectors = file_size / DISK_SECTOR_SIZE; + if(file_size % DISK_SECTOR_SIZE){ + file_sectors++; + } + + uint16_t data_end_sector = data_start_sector + file_sectors; + for(uint16_t i=data_start_sector; i<(data_end_sector-1); i++){ + fat_set_table_index(table, i, i+1, is_fat16); + } + fat_set_table_index(table, data_end_sector-1, 0xFFFF, is_fat16); + + //Set Firmware Date based on the build time + static const char * month_names_short[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + char mstr[8] = {'\0',}; + const char *str = __DATE__ " " __TIME__; + int ms=0, seconds=0, minutes=0, hours=0, year=0, date=0, month=0; + int r = sscanf(str,"%s %d %d %d:%d:%d", mstr, &date, &year, &hours, &minutes, &seconds); + if(r >= 0){ + for(int i=0; i<12; i++){ + if(!strcmp(mstr, month_names_short[i])){ + month = i; + break; + } + } + entry->creation_time_ms = FAT_MS2V(seconds, ms); + entry->creation_time_hms = FAT_HMS2V(hours, minutes, seconds); + entry->creation_time_ymd = FAT_YMD2V(year, month, date); + entry->last_access_ymd = entry->creation_time_ymd; + entry->last_modified_hms = entry->creation_time_hms; + entry->last_modified_ymd = entry->creation_time_ymd; + } + return entry; +} + +uint8_t fat_lfn_checksum(const uint8_t *short_filename){ + uint8_t sum = 0; + for (uint8_t i = 11; i; i--) { + sum = ((sum & 1) << 7) + (sum >> 1) + *short_filename++; + } + return sum; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/firmware_msc_fat.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/firmware_msc_fat.h new file mode 100644 index 0000000..dd88cdc --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/firmware_msc_fat.h @@ -0,0 +1,141 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#define FAT_U8(v) ((v) & 0xFF) +#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8) +#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24) + +#define FAT12_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4) + +#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) +#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) +#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) + +#define FAT_MS2V(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10) +#define FAT_HMS2V(h,m,s) (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8)) +#define FAT_YMD2V(y,m,d) (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8)) + +#define FAT_B2HMS(hms) ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1) +#define FAT_B2YMD(ymd) (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F) + +#define FAT_FILE_ATTR_READ_ONLY 0x01 +#define FAT_FILE_ATTR_HIDDEN 0x02 +#define FAT_FILE_ATTR_SYSTEM 0x04 +#define FAT_FILE_ATTR_VOLUME_LABEL 0x08 +#define FAT_FILE_ATTR_SUBDIRECTORY 0x10 +#define FAT_FILE_ATTR_ARCHIVE 0x20 +#define FAT_FILE_ATTR_DEVICE 0x40 + +static const uint16_t DISK_SECTOR_SIZE = 512; + +#define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0) + +typedef struct __attribute__ ((packed)) { + uint8_t jump_instruction[3]; + char oem_name[8];//padded with spaces (0x20) + uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512 + uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128 + uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32 + uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1 + uint16_t max_root_dir_entries;//FAT12 and FAT16 + uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16 + uint8_t media_descriptor; + uint16_t sectors_per_alloc_table;//FAT12 and FAT16 + uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access + uint16_t num_heads; + uint32_t hidden_sectors_count; + uint32_t total_sectors_32; + uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk + uint8_t reserved0; + uint8_t extended_boot_signature;//should be 0x29 + uint32_t serial_number;//0x1234 => 1234 + char volume_label[11];//padded with spaces (0x20) + char file_system_type[8];//padded with spaces (0x20) + uint8_t reserved[448]; + uint16_t signature;//should be 0xAA55 +} fat_boot_sector_t; + +typedef struct __attribute__ ((packed)) { + union { + struct { + char file_name[8];//padded with spaces (0x20) + char file_extension[3];//padded with spaces (0x20) + }; + struct { + uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..) + char file_magic_data[10]; + }; + char volume_label[11];//padded with spaces (0x20) + }; + uint8_t file_attr;//mask of FAT_FILE_ATTR_* + uint8_t reserved;//always 0 + uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms) + uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2) + uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d + uint16_t last_access_ymd; + uint16_t extended_attr; + uint16_t last_modified_hms; + uint16_t last_modified_ymd; + uint16_t data_start_sector; + uint32_t file_size; +} fat_dir_entry_t; + +typedef struct __attribute__ ((packed)) { + union { + struct { + uint8_t number:5; + uint8_t reserved0:1; + uint8_t llfp:1; + uint8_t reserved1:1; + } seq; + uint8_t seq_num; //0xE5: Deleted Entry + }; + uint16_t name0[5]; + uint8_t attr; //ALWAYS 0x0F + uint8_t type; //ALWAYS 0x00 + uint8_t dos_checksum; + uint16_t name1[6]; + uint16_t first_cluster; //ALWAYS 0x0000 + uint16_t name2[2]; +} fat_lfn_entry_t; + +typedef union { + fat_dir_entry_t dir; + fat_lfn_entry_t lfn; +} fat_entry_t; + +const char * fat_file_system_type(bool fat16); +uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16); +uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16); +void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16); +fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number); +fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label); +fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16); +uint8_t fat_lfn_checksum(const uint8_t *short_filename); + +#ifdef __cplusplus + } +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/AUTHORS b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/AUTHORS new file mode 100644 index 0000000..af68737 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/AUTHORS @@ -0,0 +1,7 @@ +libb64: Base64 Encoding/Decoding Routines +====================================== + +Authors: +------- + +Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/LICENSE b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/LICENSE new file mode 100644 index 0000000..a6b5606 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/LICENSE @@ -0,0 +1,29 @@ +Copyright-Only Dedication (based on United States law) +or Public Domain Certification + +The person or persons who have associated work with this document (the +"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of +his knowledge, the work of authorship identified is in the public domain of the +country from which the work is published, or (b) hereby dedicates whatever +copyright the dedicators holds in the work of authorship identified below (the +"Work") to the public domain. A certifier, moreover, dedicates any copyright +interest he may have in the associated work, and for these purposes, is +described as a "dedicator" below. + +A certifier has taken reasonable steps to verify the copyright status of this +work. Certifier recognizes that his good faith efforts may not shield him from +liability if in fact the work certified is not in the public domain. + +Dedicator makes this dedication for the benefit of the public at large and to +the detriment of the Dedicator's heirs and successors. Dedicator intends this +dedication to be an overt act of relinquishment in perpetuity of all present +and future rights under copyright law, whether vested or contingent, in the +Work. Dedicator understands that such relinquishment of all rights includes +the relinquishment of all rights to enforce (by lawsuit or otherwise) those +copyrights in the Work. + +Dedicator recognizes that, once placed in the public domain, the Work may be +freely reproduced, distributed, transmitted, used, modified, built upon, or +otherwise exploited by anyone for any purpose, commercial or non-commercial, +and in any way, including by methods that have not yet been invented or +conceived. \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cdecode.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cdecode.c new file mode 100644 index 0000000..c4712b7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cdecode.c @@ -0,0 +1,102 @@ +/* +cdecoder.c - c source to a base64 decoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cdecode.h" +#include + +static int base64_decode_value_signed(int8_t value_in){ + static const int8_t decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; + static const int8_t decoding_size = sizeof(decoding); + value_in -= 43; + if (value_in < 0 || value_in >= decoding_size) return -1; + return decoding[(int)value_in]; +} + +void base64_init_decodestate(base64_decodestate* state_in){ + state_in->step = step_a; + state_in->plainchar = 0; +} + +static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in){ + const int8_t* codechar = code_in; + int8_t* plainchar = plaintext_out; + int8_t fragment; + + *plainchar = state_in->plainchar; + + switch (state_in->step){ + while (1){ + case step_a: + do { + if (codechar == code_in+length_in){ + state_in->step = step_a; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar = (fragment & 0x03f) << 2; + // fall through + case step_b: + do { + if (codechar == code_in+length_in){ + state_in->step = step_b; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x030) >> 4; + *plainchar = (fragment & 0x00f) << 4; + // fall through + case step_c: + do { + if (codechar == code_in+length_in){ + state_in->step = step_c; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03c) >> 2; + *plainchar = (fragment & 0x003) << 6; + // fall through + case step_d: + do { + if (codechar == code_in+length_in){ + state_in->step = step_d; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (int8_t)base64_decode_value_signed(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03f); + } + } + /* control should not reach here */ + return plainchar - plaintext_out; +} + +static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out){ + base64_decodestate _state; + base64_init_decodestate(&_state); + int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state); + if(len > 0) plaintext_out[len] = 0; + return len; +} + +int base64_decode_value(char value_in){ + return base64_decode_value_signed(*((int8_t *) &value_in)); +} + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){ + return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in); +} + +int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){ + return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cdecode.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cdecode.h new file mode 100644 index 0000000..44f114f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cdecode.h @@ -0,0 +1,38 @@ +/* +cdecode.h - c header for a base64 decoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CDECODE_H +#define BASE64_CDECODE_H + +#define base64_decode_expected_len(n) ((n * 3) / 4) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + step_a, step_b, step_c, step_d +} base64_decodestep; + +typedef struct { + base64_decodestep step; + char plainchar; +} base64_decodestate; + +void base64_init_decodestate(base64_decodestate* state_in); + +int base64_decode_value(char value_in); + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); + +int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* BASE64_CDECODE_H */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cencode.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cencode.c new file mode 100644 index 0000000..f5388e5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cencode.c @@ -0,0 +1,104 @@ +/* +cencoder.c - c source to a base64 encoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cencode.h" + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) { + return '='; + } + return encoding[(int)value_in]; +} + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) +{ + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) { + while (1) { + case step_A: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + // fall through + case step_B: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + // fall through + case step_C: + if (plainchar == plaintextend) { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in) +{ + char* codechar = code_out; + + switch (state_in->step) { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar = 0x00; + + return codechar - code_out; +} + +int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) +{ + base64_encodestate _state; + base64_init_encodestate(&_state); + int len = base64_encode_block(plaintext_in, length_in, code_out, &_state); + return len + base64_encode_blockend((code_out + len), &_state); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cencode.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cencode.h new file mode 100644 index 0000000..51bb3f3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/libb64/cencode.h @@ -0,0 +1,41 @@ +/* +cencode.h - c header for a base64 encoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CENCODE_H +#define BASE64_CENCODE_H + +#define base64_encode_expected_len(n) ((((4 * n) / 3) + 3) & ~3) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + step_A, step_B, step_C +} base64_encodestep; + +typedef struct { + base64_encodestep step; + char result; + int stepcount; +} base64_encodestate; + +void base64_init_encodestate(base64_encodestate* state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in); + +int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* BASE64_CENCODE_H */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/main.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/main.cpp new file mode 100644 index 0000000..303a81d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/main.cpp @@ -0,0 +1,94 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_task_wdt.h" +#include "Arduino.h" +#if (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT) && !ARDUINO_USB_MODE +#include "USB.h" +#if ARDUINO_USB_MSC_ON_BOOT +#include "FirmwareMSC.h" +#endif +#endif + +#include "chip-debug-report.h" + +#ifndef ARDUINO_LOOP_STACK_SIZE +#ifndef CONFIG_ARDUINO_LOOP_STACK_SIZE +#define ARDUINO_LOOP_STACK_SIZE 8192 +#else +#define ARDUINO_LOOP_STACK_SIZE CONFIG_ARDUINO_LOOP_STACK_SIZE +#endif +#endif + +TaskHandle_t loopTaskHandle = NULL; + +#if CONFIG_AUTOSTART_ARDUINO +#if CONFIG_FREERTOS_UNICORE +void yieldIfNecessary(void){ + static uint64_t lastYield = 0; + uint64_t now = millis(); + if((now - lastYield) > 2000) { + lastYield = now; + vTaskDelay(5); //delay 1 RTOS tick + } +} +#endif + +bool loopTaskWDTEnabled; + +__attribute__((weak)) size_t getArduinoLoopTaskStackSize(void) { + return ARDUINO_LOOP_STACK_SIZE; +} + +__attribute__((weak)) bool shouldPrintChipDebugReport(void) { + return false; +} + +void loopTask(void *pvParameters) +{ +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + printBeforeSetupInfo(); +#else + if(shouldPrintChipDebugReport()){ + printBeforeSetupInfo(); + } +#endif + setup(); +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + printAfterSetupInfo(); +#else + if(shouldPrintChipDebugReport()){ + printAfterSetupInfo(); + } +#endif + for(;;) { +#if CONFIG_FREERTOS_UNICORE + yieldIfNecessary(); +#endif + if(loopTaskWDTEnabled){ + esp_task_wdt_reset(); + } + loop(); + if (serialEventRun) serialEventRun(); + } +} + +extern "C" void app_main() +{ +#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE + Serial.begin(); +#endif +#if ARDUINO_USB_MSC_ON_BOOT && !ARDUINO_USB_MODE + MSC_Update.begin(); +#endif +#if ARDUINO_USB_DFU_ON_BOOT && !ARDUINO_USB_MODE + USB.enableDFU(); +#endif +#if ARDUINO_USB_ON_BOOT && !ARDUINO_USB_MODE + USB.begin(); +#endif + loopTaskWDTEnabled = false; + initArduino(); + xTaskCreateUniversal(loopTask, "loopTask", getArduinoLoopTaskStackSize(), NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE); +} + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/pgmspace.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/pgmspace.h new file mode 100644 index 0000000..75f7e80 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/pgmspace.h @@ -0,0 +1,89 @@ +/* + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the RaspberryPi core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef PGMSPACE_INCLUDE +#define PGMSPACE_INCLUDE + +typedef void prog_void; +typedef char prog_char; +typedef unsigned char prog_uchar; +typedef char prog_int8_t; +typedef unsigned char prog_uint8_t; +typedef short prog_int16_t; +typedef unsigned short prog_uint16_t; +typedef long prog_int32_t; +typedef unsigned long prog_uint32_t; + +#define PROGMEM +#define PGM_P const char * +#define PGM_VOID_P const void * +#define PSTR(s) (s) +#define _SFR_BYTE(n) (n) + +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#define pgm_read_word(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(const unsigned short *)(_addr); \ +}) +#define pgm_read_dword(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(const unsigned long *)(_addr); \ +}) +#define pgm_read_float(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(const float *)(_addr); \ +}) +#define pgm_read_ptr(addr) ({ \ + typeof(addr) _addr = (addr); \ + *(void * const *)(_addr); \ +}) + +#define pgm_get_far_address(x) ((uint32_t)(&(x))) + +#define pgm_read_byte_near(addr) pgm_read_byte(addr) +#define pgm_read_word_near(addr) pgm_read_word(addr) +#define pgm_read_dword_near(addr) pgm_read_dword(addr) +#define pgm_read_float_near(addr) pgm_read_float(addr) +#define pgm_read_ptr_near(addr) pgm_read_ptr(addr) +#define pgm_read_byte_far(addr) pgm_read_byte(addr) +#define pgm_read_word_far(addr) pgm_read_word(addr) +#define pgm_read_dword_far(addr) pgm_read_dword(addr) +#define pgm_read_float_far(addr) pgm_read_float(addr) +#define pgm_read_ptr_far(addr) pgm_read_ptr(addr) + +#define memcmp_P memcmp +#define memccpy_P memccpy +#define memmem_P memmem +#define memcpy_P memcpy +#define strcpy_P strcpy +#define strncpy_P strncpy +#define strcat_P strcat +#define strncat_P strncat +#define strcmp_P strcmp +#define strncmp_P strncmp +#define strcasecmp_P strcasecmp +#define strncasecmp_P strncasecmp +#define strlen_P strlen +#define strnlen_P strnlen +#define strstr_P strstr +#define printf_P printf +#define sprintf_P sprintf +#define snprintf_P snprintf +#define vsnprintf_P vsnprintf + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/stdlib_noniso.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/stdlib_noniso.c new file mode 100644 index 0000000..e1e9eed --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/stdlib_noniso.c @@ -0,0 +1,210 @@ +/* + core_esp8266_noniso.c - nonstandard (but usefull) conversion functions + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 03 April 2015 by Markus Sattler + + */ + +#include +#include +#include +#include +#include +#include "stdlib_noniso.h" +#include "esp_system.h" + +static void reverse(char* begin, char* end) { + char *is = begin; + char *ie = end - 1; + while(is < ie) { + char tmp = *ie; + *ie = *is; + *is = tmp; + ++is; + --ie; + } +} + +char* ltoa(long value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + long quotient = abs(value); + + do { + const long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) + *out++ = '-'; + + reverse(result, out); + *out = 0; + return result; +} + +char* lltoa (long long val, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + long long quotient = val > 0 ? val : -val; + + do { + const long long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(val < 0) + *out++ = '-'; + + reverse(result, out); + *out = 0; + return result; +} + +char* ultoa(unsigned long value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned long quotient = value; + + do { + const unsigned long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; +} + +char* ulltoa (unsigned long long val, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned long long quotient = val; + + do { + const unsigned long long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; +} + +char * dtostrf(double number, signed int width, unsigned int prec, char *s) { + bool negative = false; + + if (isnan(number)) { + strcpy(s, "nan"); + return s; + } + if (isinf(number)) { + strcpy(s, "inf"); + return s; + } + + char* out = s; + + int fillme = width; // how many cells to fill for the integer part + if (prec > 0) { + fillme -= (prec+1); + } + + // Handle negative numbers + if (number < 0.0) { + negative = true; + fillme--; + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + // I optimized out most of the divisions + double rounding = 2.0; + for (unsigned int i = 0; i < prec; ++i) + rounding *= 10.0; + rounding = 1.0 / rounding; + + number += rounding; + + // Figure out how big our number really is + double tenpow = 1.0; + unsigned int digitcount = 1; + while (number >= 10.0 * tenpow) { + tenpow *= 10.0; + digitcount++; + } + + number /= tenpow; + fillme -= digitcount; + + // Pad unused cells with spaces + while (fillme-- > 0) { + *out++ = ' '; + } + + // Handle negative sign + if (negative) *out++ = '-'; + + // Print the digits, and if necessary, the decimal point + digitcount += prec; + int8_t digit = 0; + while (digitcount-- > 0) { + digit = (int8_t)number; + if (digit > 9) digit = 9; // insurance + *out++ = (char)('0' | digit); + if ((digitcount == prec) && (prec > 0)) { + *out++ = '.'; + } + number -= digit; + number *= 10.0; + } + + // make sure the string is terminated + *out = 0; + return s; +} + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/stdlib_noniso.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/stdlib_noniso.h new file mode 100644 index 0000000..8356c11 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/stdlib_noniso.h @@ -0,0 +1,53 @@ +/* + stdlib_noniso.h - nonstandard (but usefull) conversion functions + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef STDLIB_NONISO_H +#define STDLIB_NONISO_H + +#ifdef __cplusplus +extern "C" { +#endif + +int atoi(const char *s); + +long atol(const char* s); + +double atof(const char* s); + +char* itoa (int val, char *s, int radix); + +char* ltoa (long val, char *s, int radix); + +char* lltoa (long long val, char* s, int radix); + +char* utoa (unsigned int val, char *s, int radix); + +char* ultoa (unsigned long val, char *s, int radix); + +char* ulltoa (unsigned long long val, char* s, int radix); + +char* dtostrf (double val, signed int width, unsigned int prec, char *s); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_private.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_private.h new file mode 100644 index 0000000..2c53565 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_private.h @@ -0,0 +1,45 @@ +/* + wiring_private.h - Internal header file. + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2005-2006 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 239 2007-01-12 17:58:39Z mellis $ + */ + +#ifndef WiringPrivate_h +#define WiringPrivate_h + +#include +#include + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*voidFuncPtr)(void); + +void initPins(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_pulse.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_pulse.c new file mode 100644 index 0000000..8c55e72 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_pulse.c @@ -0,0 +1,48 @@ +/* + pulse.c - wiring pulseIn implementation for esp8266 + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +//#include +#include "wiring_private.h" +#include "pins_arduino.h" +#include "esp_cpu.h" + +#define WAIT_FOR_PIN_STATE(state) \ + while (digitalRead(pin) != (state)) { \ + if (esp_cpu_get_cycle_count() - start_cycle_count > timeout_cycles) { \ + return 0; \ + } \ + } + +// max timeout is 27 seconds at 160MHz clock and 54 seconds at 80MHz clock +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + const uint32_t max_timeout_us = clockCyclesToMicroseconds(UINT_MAX); + if (timeout > max_timeout_us) { + timeout = max_timeout_us; + } + const uint32_t timeout_cycles = microsecondsToClockCycles(timeout); + const uint32_t start_cycle_count = esp_cpu_get_cycle_count(); + WAIT_FOR_PIN_STATE(!state); + WAIT_FOR_PIN_STATE(state); + const uint32_t pulse_start_cycle_count = esp_cpu_get_cycle_count(); + WAIT_FOR_PIN_STATE(!state); + return clockCyclesToMicroseconds(esp_cpu_get_cycle_count() - pulse_start_cycle_count); +} + +unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout) +{ + return pulseIn(pin, state, timeout); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_shift.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_shift.c new file mode 100644 index 0000000..41cf8a0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/cores/esp32/wiring_shift.c @@ -0,0 +1,51 @@ +/* + wiring_shift.c - shiftOut() function + Part of Arduino - http://www.arduino.cc/ + Copyright (c) 2005-2006 David A. Mellis + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ + */ + +#include "esp32-hal.h" +#include "wiring_private.h" + +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { + uint8_t value = 0; + uint8_t i; + + for(i = 0; i < 8; ++i) { + //digitalWrite(clockPin, HIGH); + if(bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) { + uint8_t i; + + for(i = 0; i < 8; i++) { + if(bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/idf_component.yml b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/idf_component.yml new file mode 100644 index 0000000..56246fa --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/idf_component.yml @@ -0,0 +1,33 @@ +dependencies: + chmorgan/esp-libhelix-mp3: + version: 1.0.3 + idf: + version: '>=5.1' + mdns: + version: ^1.1.0 +description: Arduino core for ESP32, ESP32-S and ESP32-C series of SoCs +files: + exclude: + - '**/*' + include: + - cores/**/* + - variants/esp32/**/* + - variants/esp32s2/**/* + - variants/esp32s3/**/* + - variants/esp32c3/**/* + - variants/esp32c6/**/* + - variants/esp32h2/**/* + - libraries/**/* + - CMakeLists.txt + - Kconfig.projbuild +tags: +- arduino +targets: +- esp32 +- esp32s2 +- esp32s3 +- esp32c3 +- esp32c6 +- esp32h2 +url: https://github.com/espressif/arduino-esp32 +version: 3.0.0-alpha2 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/BasicOTA/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/BasicOTA/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino new file mode 100644 index 0000000..8365249 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +const char* ssid = ".........."; +const char* password = ".........."; + +void setup() { + Serial.begin(115200); + Serial.println("Booting"); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("Connection Failed! Rebooting..."); + delay(5000); + ESP.restart(); + } + + // Port defaults to 3232 + // ArduinoOTA.setPort(3232); + + // Hostname defaults to esp3232-[MAC] + // ArduinoOTA.setHostname("myesp32"); + + // No authentication by default + // ArduinoOTA.setPassword("admin"); + + // Password can be set with it's md5 value as well + // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 + // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); + + ArduinoOTA + .onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + + // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() + Serial.println("Start updating " + type); + }) + .onEnd([]() { + Serial.println("\nEnd"); + }) + .onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }) + .onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + + ArduinoOTA.begin(); + + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); +} + +void loop() { + ArduinoOTA.handle(); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/OTAWebUpdater/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/OTAWebUpdater/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino new file mode 100644 index 0000000..4c4adc7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/examples/OTAWebUpdater/OTAWebUpdater.ino @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include + +const char* host = "esp32"; +const char* ssid = "xxx"; +const char* password = "xxxx"; + +WebServer server(80); + +/* + * Login page + */ + +const char* loginIndex = + "
" + "" + "" + "" + "
" + "
" + "" + "" + "" + "" + "" + "
" + "
" + "" + "" + "" + "
" + "
" + "" + "" + "" + "" + "
" + "
ESP32 Login Page
" + "
" + "
Username:
Password:
" +"
" +""; + +/* + * Server Index Page + */ + +const char* serverIndex = +"" +"
" + "" + "" + "
" + "
progress: 0%
" + ""; + +/* + * setup function + */ +void setup(void) { + Serial.begin(115200); + + // Connect to WiFi network + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + /*use mdns for host name resolution*/ + if (!MDNS.begin(host)) { //http://esp32.local + Serial.println("Error setting up MDNS responder!"); + while (1) { + delay(1000); + } + } + Serial.println("mDNS responder started"); + /*return index page which is stored in serverIndex */ + server.on("/", HTTP_GET, []() { + server.sendHeader("Connection", "close"); + server.send(200, "text/html", loginIndex); + }); + server.on("/serverIndex", HTTP_GET, []() { + server.sendHeader("Connection", "close"); + server.send(200, "text/html", serverIndex); + }); + /*handling uploading firmware file */ + server.on("/update", HTTP_POST, []() { + server.sendHeader("Connection", "close"); + server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); + ESP.restart(); + }, []() { + HTTPUpload& upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + Serial.printf("Update: %s\n", upload.filename.c_str()); + if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size + Update.printError(Serial); + } + } else if (upload.status == UPLOAD_FILE_WRITE) { + /* flashing firmware to ESP*/ + if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { + Update.printError(Serial); + } + } else if (upload.status == UPLOAD_FILE_END) { + if (Update.end(true)) { //true to set the size to the current progress + Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } else { + Update.printError(Serial); + } + } + }); + server.begin(); +} + +void loop(void) { + server.handleClient(); + delay(1); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/keywords.txt new file mode 100644 index 0000000..1c14d9e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ArduinoOTA KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setup KEYWORD2 +handle KEYWORD2 +onStart KEYWORD2 +onEnd KEYWORD2 +onError KEYWORD2 +onProgress KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/library.properties new file mode 100644 index 0000000..f8a3b50 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/library.properties @@ -0,0 +1,9 @@ +name=ArduinoOTA +version=2.0.0 +author=Ivan Grokhotkov and Hristo Gochkov +maintainer=Hristo Gochkov +sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download. +paragraph=With this library you can enable your sketch to be upgraded over network. Includes mdns anounces to get discovered by the arduino IDE. +category=Communication +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/src/ArduinoOTA.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/src/ArduinoOTA.cpp new file mode 100644 index 0000000..f7ad910 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/src/ArduinoOTA.cpp @@ -0,0 +1,395 @@ +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif +#include +#include +#include "ArduinoOTA.h" +#include "ESPmDNS.h" +#include "MD5Builder.h" +#include "Update.h" + + +// #define OTA_DEBUG Serial + +ArduinoOTAClass::ArduinoOTAClass() +: _port(0) +, _initialized(false) +, _rebootOnSuccess(true) +, _mdnsEnabled(true) +, _state(OTA_IDLE) +, _size(0) +, _cmd(0) +, _ota_port(0) +, _ota_timeout(1000) +, _start_callback(NULL) +, _end_callback(NULL) +, _error_callback(NULL) +, _progress_callback(NULL) +{ +} + +ArduinoOTAClass::~ArduinoOTAClass(){ + _udp_ota.stop(); +} + +ArduinoOTAClass& ArduinoOTAClass::onStart(THandlerFunction fn) { + _start_callback = fn; + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::onEnd(THandlerFunction fn) { + _end_callback = fn; + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::onProgress(THandlerFunction_Progress fn) { + _progress_callback = fn; + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::onError(THandlerFunction_Error fn) { + _error_callback = fn; + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::setPort(uint16_t port) { + if (!_initialized && !_port && port) { + _port = port; + } + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::setHostname(const char * hostname) { + if (!_initialized && !_hostname.length() && hostname) { + _hostname = hostname; + } + return *this; +} + +String ArduinoOTAClass::getHostname() { + return _hostname; +} + +ArduinoOTAClass& ArduinoOTAClass::setPassword(const char * password) { + if (!_initialized && !_password.length() && password) { + MD5Builder passmd5; + passmd5.begin(); + passmd5.add(password); + passmd5.calculate(); + _password = passmd5.toString(); + } + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::setPasswordHash(const char * password) { + if (!_initialized && !_password.length() && password) { + _password = password; + } + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::setPartitionLabel(const char * partition_label) { + if (!_initialized && !_partition_label.length() && partition_label) { + _partition_label = partition_label; + } + return *this; +} + +String ArduinoOTAClass::getPartitionLabel() { + return _partition_label; +} + +ArduinoOTAClass& ArduinoOTAClass::setRebootOnSuccess(bool reboot){ + _rebootOnSuccess = reboot; + return *this; +} + +ArduinoOTAClass& ArduinoOTAClass::setMdnsEnabled(bool enabled){ + _mdnsEnabled = enabled; + return *this; +} + +void ArduinoOTAClass::begin() { + if (_initialized){ + log_w("already initialized"); + return; + } + + if (!_port) { + _port = 3232; + } + + if(!_udp_ota.begin(_port)){ + log_e("udp bind failed"); + return; + } + + + if (!_hostname.length()) { + char tmp[20]; + uint8_t mac[6]; + WiFi.macAddress(mac); + sprintf(tmp, "esp32-%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + _hostname = tmp; + } + if(_mdnsEnabled){ + MDNS.begin(_hostname.c_str()); + MDNS.enableArduino(_port, (_password.length() > 0)); + } + _initialized = true; + _state = OTA_IDLE; + log_i("OTA server at: %s.local:%u", _hostname.c_str(), _port); +} + +int ArduinoOTAClass::parseInt(){ + char data[INT_BUFFER_SIZE]; + uint8_t index = 0; + char value; + while(_udp_ota.peek() == ' ') _udp_ota.read(); + while(index < INT_BUFFER_SIZE - 1){ + value = _udp_ota.peek(); + if(value < '0' || value > '9'){ + data[index++] = '\0'; + return atoi(data); + } + data[index++] = _udp_ota.read(); + } + return 0; +} + +String ArduinoOTAClass::readStringUntil(char end){ + String res = ""; + int value; + while(true){ + value = _udp_ota.read(); + if(value <= 0 || value == end){ + return res; + } + res += (char)value; + } + return res; +} + +void ArduinoOTAClass::_onRx(){ + if (_state == OTA_IDLE) { + int cmd = parseInt(); + if (cmd != U_FLASH && cmd != U_SPIFFS) + return; + _cmd = cmd; + _ota_port = parseInt(); + _size = parseInt(); + _udp_ota.read(); + _md5 = readStringUntil('\n'); + _md5.trim(); + if(_md5.length() != 32){ + log_e("bad md5 length"); + return; + } + + if (_password.length()){ + MD5Builder nonce_md5; + nonce_md5.begin(); + nonce_md5.add(String(micros())); + nonce_md5.calculate(); + _nonce = nonce_md5.toString(); + + _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); + _udp_ota.printf("AUTH %s", _nonce.c_str()); + _udp_ota.endPacket(); + _state = OTA_WAITAUTH; + return; + } else { + _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); + _udp_ota.print("OK"); + _udp_ota.endPacket(); + _ota_ip = _udp_ota.remoteIP(); + _state = OTA_RUNUPDATE; + } + } else if (_state == OTA_WAITAUTH) { + int cmd = parseInt(); + if (cmd != U_AUTH) { + log_e("%d was expected. got %d instead", U_AUTH, cmd); + _state = OTA_IDLE; + return; + } + _udp_ota.read(); + String cnonce = readStringUntil(' '); + String response = readStringUntil('\n'); + if (cnonce.length() != 32 || response.length() != 32) { + log_e("auth param fail"); + _state = OTA_IDLE; + return; + } + + String challenge = _password + ":" + String(_nonce) + ":" + cnonce; + MD5Builder _challengemd5; + _challengemd5.begin(); + _challengemd5.add(challenge); + _challengemd5.calculate(); + String result = _challengemd5.toString(); + + if(result.equals(response)){ + _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); + _udp_ota.print("OK"); + _udp_ota.endPacket(); + _ota_ip = _udp_ota.remoteIP(); + _state = OTA_RUNUPDATE; + } else { + _udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort()); + _udp_ota.print("Authentication Failed"); + log_w("Authentication Failed"); + _udp_ota.endPacket(); + if (_error_callback) _error_callback(OTA_AUTH_ERROR); + _state = OTA_IDLE; + } + } +} + +void ArduinoOTAClass::_runUpdate() { + const char *partition_label = _partition_label.length() ? _partition_label.c_str() : NULL; + if (!Update.begin(_size, _cmd, -1, LOW, partition_label)) { + + log_e("Begin ERROR: %s", Update.errorString()); + + if (_error_callback) { + _error_callback(OTA_BEGIN_ERROR); + } + _state = OTA_IDLE; + return; + } + Update.setMD5(_md5.c_str()); + + if (_start_callback) { + _start_callback(); + } + if (_progress_callback) { + _progress_callback(0, _size); + } + + WiFiClient client; + if (!client.connect(_ota_ip, _ota_port)) { + if (_error_callback) { + _error_callback(OTA_CONNECT_ERROR); + } + _state = OTA_IDLE; + } + + uint32_t written = 0, total = 0, tried = 0; + + while (!Update.isFinished() && client.connected()) { + size_t waited = _ota_timeout; + size_t available = client.available(); + while (!available && waited){ + delay(1); + waited -=1 ; + available = client.available(); + } + if (!waited){ + if(written && tried++ < 3){ + log_i("Try[%u]: %u", tried, written); + if(!client.printf("%lu", written)){ + log_e("failed to respond"); + _state = OTA_IDLE; + break; + } + continue; + } + log_e("Receive Failed"); + if (_error_callback) { + _error_callback(OTA_RECEIVE_ERROR); + } + _state = OTA_IDLE; + Update.abort(); + return; + } + if(!available){ + log_e("No Data: %u", waited); + _state = OTA_IDLE; + break; + } + tried = 0; + static uint8_t buf[1460]; + if(available > 1460){ + available = 1460; + } + size_t r = client.read(buf, available); + if(r != available){ + log_w("didn't read enough! %u != %u", r, available); + } + + written = Update.write(buf, r); + if (written > 0) { + if(written != r){ + log_w("didn't write enough! %u != %u", written, r); + } + if(!client.printf("%lu", written)){ + log_w("failed to respond"); + } + total += written; + if(_progress_callback) { + _progress_callback(total, _size); + } + } else { + log_e("Write ERROR: %s", Update.errorString()); + } + } + + if (Update.end()) { + client.print("OK"); + client.stop(); + delay(10); + if (_end_callback) { + _end_callback(); + } + if(_rebootOnSuccess){ + //let serial/network finish tasks that might be given in _end_callback + delay(100); + ESP.restart(); + } + } else { + if (_error_callback) { + _error_callback(OTA_END_ERROR); + } + Update.printError(client); + client.stop(); + delay(10); + log_e("Update ERROR: %s", Update.errorString()); + _state = OTA_IDLE; + } +} + +void ArduinoOTAClass::end() { + _initialized = false; + _udp_ota.stop(); + if(_mdnsEnabled){ + MDNS.end(); + } + _state = OTA_IDLE; + log_i("OTA server stopped."); +} + +void ArduinoOTAClass::handle() { + if (!_initialized) { + return; + } + if (_state == OTA_RUNUPDATE) { + _runUpdate(); + _state = OTA_IDLE; + } + if(_udp_ota.parsePacket()){ + _onRx(); + } + _udp_ota.flush(); // always flush, even zero length packets must be flushed. +} + +int ArduinoOTAClass::getCommand() { + return _cmd; +} + +void ArduinoOTAClass::setTimeout(int timeoutInMillis) { + _ota_timeout = timeoutInMillis; +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA) +ArduinoOTAClass ArduinoOTA; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/src/ArduinoOTA.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/src/ArduinoOTA.h new file mode 100644 index 0000000..cd0ba05 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ArduinoOTA/src/ArduinoOTA.h @@ -0,0 +1,116 @@ +#ifndef __ARDUINO_OTA_H +#define __ARDUINO_OTA_H + +#include +#include +#include "Update.h" + +#define INT_BUFFER_SIZE 16 + +typedef enum { + OTA_IDLE, + OTA_WAITAUTH, + OTA_RUNUPDATE +} ota_state_t; + +typedef enum { + OTA_AUTH_ERROR, + OTA_BEGIN_ERROR, + OTA_CONNECT_ERROR, + OTA_RECEIVE_ERROR, + OTA_END_ERROR +} ota_error_t; + +class ArduinoOTAClass +{ + public: + typedef std::function THandlerFunction; + typedef std::function THandlerFunction_Error; + typedef std::function THandlerFunction_Progress; + + ArduinoOTAClass(); + ~ArduinoOTAClass(); + + //Sets the service port. Default 3232 + ArduinoOTAClass& setPort(uint16_t port); + + //Sets the device hostname. Default esp32-xxxxxx + ArduinoOTAClass& setHostname(const char *hostname); + String getHostname(); + + //Sets the password that will be required for OTA. Default NULL + ArduinoOTAClass& setPassword(const char *password); + + //Sets the password as above but in the form MD5(password). Default NULL + ArduinoOTAClass& setPasswordHash(const char *password); + + //Sets the partition label to write to when updating SPIFFS. Default NULL + ArduinoOTAClass &setPartitionLabel(const char *partition_label); + String getPartitionLabel(); + + //Sets if the device should be rebooted after successful update. Default true + ArduinoOTAClass& setRebootOnSuccess(bool reboot); + + //Sets if the device should advertise itself to Arduino IDE. Default true + ArduinoOTAClass& setMdnsEnabled(bool enabled); + + //This callback will be called when OTA connection has begun + ArduinoOTAClass& onStart(THandlerFunction fn); + + //This callback will be called when OTA has finished + ArduinoOTAClass& onEnd(THandlerFunction fn); + + //This callback will be called when OTA encountered Error + ArduinoOTAClass& onError(THandlerFunction_Error fn); + + //This callback will be called when OTA is receiving data + ArduinoOTAClass& onProgress(THandlerFunction_Progress fn); + + //Starts the ArduinoOTA service + void begin(); + + //Ends the ArduinoOTA service + void end(); + + //Call this in loop() to run the service + void handle(); + + //Gets update command type after OTA has started. Either U_FLASH or U_SPIFFS + int getCommand(); + + void setTimeout(int timeoutInMillis); + + private: + int _port; + String _password; + String _hostname; + String _partition_label; + String _nonce; + WiFiUDP _udp_ota; + bool _initialized; + bool _rebootOnSuccess; + bool _mdnsEnabled; + ota_state_t _state; + int _size; + int _cmd; + int _ota_port; + int _ota_timeout; + IPAddress _ota_ip; + String _md5; + + THandlerFunction _start_callback; + THandlerFunction _end_callback; + THandlerFunction_Error _error_callback; + THandlerFunction_Progress _progress_callback; + + void _runUpdate(void); + void _onRx(void); + int parseInt(void); + String readStringUntil(char end); +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA) +extern ArduinoOTAClass ArduinoOTA; +#endif + +#endif /* __ARDUINO_OTA_H */ \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPClient/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPClient/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPClient/AsyncUDPClient.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPClient/AsyncUDPClient.ino new file mode 100644 index 0000000..3348f8a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPClient/AsyncUDPClient.ino @@ -0,0 +1,51 @@ +#include "WiFi.h" +#include "AsyncUDP.h" + +const char * ssid = "***********"; +const char * password = "***********"; + +AsyncUDP udp; + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + if (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi Failed"); + while(1) { + delay(1000); + } + } + if(udp.connect(IPAddress(192,168,1,100), 1234)) { + Serial.println("UDP connected"); + udp.onPacket([](AsyncUDPPacket packet) { + Serial.print("UDP Packet Type: "); + Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); + Serial.print(", From: "); + Serial.print(packet.remoteIP()); + Serial.print(":"); + Serial.print(packet.remotePort()); + Serial.print(", To: "); + Serial.print(packet.localIP()); + Serial.print(":"); + Serial.print(packet.localPort()); + Serial.print(", Length: "); + Serial.print(packet.length()); + Serial.print(", Data: "); + Serial.write(packet.data(), packet.length()); + Serial.println(); + //reply to the client + packet.printf("Got %u bytes of data", packet.length()); + }); + //Send unicast + udp.print("Hello Server!"); + } +} + +void loop() +{ + delay(1000); + //Send broadcast on port 1234 + udp.broadcastTo("Anyone here?", 1234); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/AsyncUDPMulticastServer.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/AsyncUDPMulticastServer.ino new file mode 100644 index 0000000..2bbbac5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPMulticastServer/AsyncUDPMulticastServer.ino @@ -0,0 +1,52 @@ +#include "WiFi.h" +#include "AsyncUDP.h" + +const char * ssid = "***********"; +const char * password = "***********"; + +AsyncUDP udp; + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + if (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi Failed"); + while(1) { + delay(1000); + } + } + if(udp.listenMulticast(IPAddress(239,1,2,3), 1234)) { + Serial.print("UDP Listening on IP: "); + Serial.println(WiFi.localIP()); + udp.onPacket([](AsyncUDPPacket packet) { + Serial.print("UDP Packet Type: "); + Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); + Serial.print(", From: "); + Serial.print(packet.remoteIP()); + Serial.print(":"); + Serial.print(packet.remotePort()); + Serial.print(", To: "); + Serial.print(packet.localIP()); + Serial.print(":"); + Serial.print(packet.localPort()); + Serial.print(", Length: "); + Serial.print(packet.length()); + Serial.print(", Data: "); + Serial.write(packet.data(), packet.length()); + Serial.println(); + //reply to the client + packet.printf("Got %u bytes of data", packet.length()); + }); + //Send multicast + udp.print("Hello!"); + } +} + +void loop() +{ + delay(1000); + //Send multicast + udp.print("Anyone here?"); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPServer/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPServer/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPServer/AsyncUDPServer.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPServer/AsyncUDPServer.ino new file mode 100644 index 0000000..1f8529b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/examples/AsyncUDPServer/AsyncUDPServer.ino @@ -0,0 +1,50 @@ +#include "WiFi.h" +#include "AsyncUDP.h" + +const char * ssid = "***********"; +const char * password = "***********"; + +AsyncUDP udp; + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + if (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("WiFi Failed"); + while(1) { + delay(1000); + } + } + if(udp.listen(1234)) { + Serial.print("UDP Listening on IP: "); + Serial.println(WiFi.localIP()); + udp.onPacket([](AsyncUDPPacket packet) { + Serial.print("UDP Packet Type: "); + Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast"); + Serial.print(", From: "); + Serial.print(packet.remoteIP()); + Serial.print(":"); + Serial.print(packet.remotePort()); + Serial.print(", To: "); + Serial.print(packet.localIP()); + Serial.print(":"); + Serial.print(packet.localPort()); + Serial.print(", Length: "); + Serial.print(packet.length()); + Serial.print(", Data: "); + Serial.write(packet.data(), packet.length()); + Serial.println(); + //reply to the client + packet.printf("Got %u bytes of data", packet.length()); + }); + } +} + +void loop() +{ + delay(1000); + //Send broadcast + udp.broadcast("Anyone here?"); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/keywords.txt new file mode 100644 index 0000000..67c0b97 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +AsyncUDP KEYWORD1 +AsyncUDPPacket KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +connect KEYWORD2 +connected KEYWORD2 +listen KEYWORD2 +listenMulticast KEYWORD2 +close KEYWORD2 +write KEYWORD2 +broadcast KEYWORD2 +onPacket KEYWORD2 +data KEYWORD2 +length KEYWORD2 +localIP KEYWORD2 +localPort KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/library.properties new file mode 100644 index 0000000..f606bb8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/library.properties @@ -0,0 +1,9 @@ +name=ESP32 Async UDP +version=2.0.0 +author=Me-No-Dev +maintainer=Me-No-Dev +sentence=Async UDP Library for ESP32 +paragraph=Async UDP Library for ESP32 +category=Other +url=https://github.com/me-no-dev/ESPAsyncUDP +architectures=* diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/src/AsyncUDP.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/src/AsyncUDP.cpp new file mode 100644 index 0000000..e533755 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/src/AsyncUDP.cpp @@ -0,0 +1,923 @@ +#include "Arduino.h" +#include "AsyncUDP.h" + +extern "C" { +#include "lwip/opt.h" +#include "lwip/inet.h" +#include "lwip/udp.h" +#include "lwip/igmp.h" +#include "lwip/ip_addr.h" +#include "lwip/mld6.h" +#include "lwip/prot/ethernet.h" +#include +#include +} + +#include "lwip/priv/tcpip_priv.h" + +static const char * netif_ifkeys[TCPIP_ADAPTER_IF_MAX] = { + "WIFI_STA_DEF", "WIFI_AP_DEF", "ETH_DEF", "PPP_DEF" +}; + +static esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif){ + *netif = NULL; + if(tcpip_if < TCPIP_ADAPTER_IF_MAX){ + esp_netif_t *esp_netif = esp_netif_get_handle_from_ifkey(netif_ifkeys[tcpip_if]); + if(esp_netif == NULL){ + return ESP_FAIL; + } + int netif_index = esp_netif_get_netif_impl_index(esp_netif); + if(netif_index < 0){ + return ESP_FAIL; + } + *netif = (void*)netif_get_by_index(netif_index); + } else { + *netif = netif_default; + } + return (*netif != NULL)?ESP_OK:ESP_FAIL; +} + +typedef struct { + struct tcpip_api_call_data call; + udp_pcb * pcb; + const ip_addr_t *addr; + uint16_t port; + struct pbuf *pb; + struct netif *netif; + err_t err; +} udp_api_call_t; + +static err_t _udp_connect_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_connect(msg->pcb, msg->addr, msg->port); + return msg->err; +} + +static err_t _udp_connect(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + tcpip_api_call(_udp_connect_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _udp_disconnect_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = 0; + udp_disconnect(msg->pcb); + return msg->err; +} + +static void _udp_disconnect(struct udp_pcb *pcb){ + udp_api_call_t msg; + msg.pcb = pcb; + tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call_data*)&msg); +} + +static err_t _udp_remove_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = 0; + udp_remove(msg->pcb); + return msg->err; +} + +static void _udp_remove(struct udp_pcb *pcb){ + udp_api_call_t msg; + msg.pcb = pcb; + tcpip_api_call(_udp_remove_api, (struct tcpip_api_call_data*)&msg); +} + +static err_t _udp_bind_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_bind(msg->pcb, msg->addr, msg->port); + return msg->err; +} + +static err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + tcpip_api_call(_udp_bind_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _udp_sendto_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_sendto(msg->pcb, msg->pb, msg->addr, msg->port); + return msg->err; +} + +static err_t _udp_sendto(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + msg.pb = pb; + tcpip_api_call(_udp_sendto_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _udp_sendto_if_api(struct tcpip_api_call_data *api_call_msg){ + udp_api_call_t * msg = (udp_api_call_t *)api_call_msg; + msg->err = udp_sendto_if(msg->pcb, msg->pb, msg->addr, msg->port, msg->netif); + return msg->err; +} + +static err_t _udp_sendto_if(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *addr, u16_t port, struct netif *netif){ + udp_api_call_t msg; + msg.pcb = pcb; + msg.addr = addr; + msg.port = port; + msg.pb = pb; + msg.netif = netif; + tcpip_api_call(_udp_sendto_if_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +typedef struct { + void *arg; + udp_pcb *pcb; + pbuf *pb; + const ip_addr_t *addr; + uint16_t port; + struct netif * netif; +} lwip_event_packet_t; + +static QueueHandle_t _udp_queue; +static volatile TaskHandle_t _udp_task_handle = NULL; + +static void _udp_task(void *pvParameters){ + lwip_event_packet_t * e = NULL; + for (;;) { + if(xQueueReceive(_udp_queue, &e, portMAX_DELAY) == pdTRUE){ + if(!e->pb){ + free((void*)(e)); + continue; + } + AsyncUDP::_s_recv(e->arg, e->pcb, e->pb, e->addr, e->port, e->netif); + free((void*)(e)); + } + } + _udp_task_handle = NULL; + vTaskDelete(NULL); +} + +static bool _udp_task_start(){ + if(!_udp_queue){ + _udp_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); + if(!_udp_queue){ + return false; + } + } + if(!_udp_task_handle){ + xTaskCreateUniversal(_udp_task, "async_udp", 4096, NULL, CONFIG_ARDUINO_UDP_TASK_PRIORITY, (TaskHandle_t*)&_udp_task_handle, CONFIG_ARDUINO_UDP_RUNNING_CORE); + if(!_udp_task_handle){ + return false; + } + } + return true; +} + +static bool _udp_task_post(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif *netif) +{ + if(!_udp_task_handle || !_udp_queue){ + return false; + } + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + if(!e){ + return false; + } + e->arg = arg; + e->pcb = pcb; + e->pb = pb; + e->addr = addr; + e->port = port; + e->netif = netif; + if (xQueueSend(_udp_queue, &e, portMAX_DELAY) != pdPASS) { + free((void*)(e)); + return false; + } + return true; +} + +static void _udp_recv(void *arg, udp_pcb *pcb, pbuf *pb, const ip_addr_t *addr, uint16_t port) +{ + while(pb != NULL) { + pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + if(!_udp_task_post(arg, pcb, this_pb, addr, port, ip_current_input_netif())){ + pbuf_free(this_pb); + } + } +} +/* +static bool _udp_task_stop(){ + if(!_udp_task_post(NULL, NULL, NULL, NULL, 0, NULL)){ + return false; + } + while(_udp_task_handle){ + vTaskDelay(10); + } + + lwip_event_packet_t * e; + while (xQueueReceive(_udp_queue, &e, 0) == pdTRUE) { + if(e->pb){ + pbuf_free(e->pb); + } + free((void*)(e)); + } + vQueueDelete(_udp_queue); + _udp_queue = NULL; +} +*/ + + + +#define UDP_MUTEX_LOCK() //xSemaphoreTake(_lock, portMAX_DELAY) +#define UDP_MUTEX_UNLOCK() //xSemaphoreGive(_lock) + + +AsyncUDPMessage::AsyncUDPMessage(size_t size) +{ + _index = 0; + if(size > CONFIG_TCP_MSS) { + size = CONFIG_TCP_MSS; + } + _size = size; + _buffer = (uint8_t *)malloc(size); +} + +AsyncUDPMessage::~AsyncUDPMessage() +{ + if(_buffer) { + free(_buffer); + } +} + +size_t AsyncUDPMessage::write(const uint8_t *data, size_t len) +{ + if(_buffer == NULL) { + return 0; + } + size_t s = space(); + if(len > s) { + len = s; + } + memcpy(_buffer + _index, data, len); + _index += len; + return len; +} + +size_t AsyncUDPMessage::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t AsyncUDPMessage::space() +{ + if(_buffer == NULL) { + return 0; + } + return _size - _index; +} + +uint8_t * AsyncUDPMessage::data() +{ + return _buffer; +} + +size_t AsyncUDPMessage::length() +{ + return _index; +} + +void AsyncUDPMessage::flush() +{ + _index = 0; +} + +AsyncUDPPacket::AsyncUDPPacket(AsyncUDPPacket &packet){ + _udp = packet._udp; + _pb = packet._pb; + _if = packet._if; + _data = packet._data; + _len = packet._len; + _index = 0; + + memcpy(&_remoteIp, &packet._remoteIp, sizeof(ip_addr_t)); + memcpy(&_localIp, &packet._localIp, sizeof(ip_addr_t)); + _localPort = packet._localPort; + _remotePort = packet._remotePort; + memcpy(_remoteMac, packet._remoteMac, 6); + + pbuf_ref(_pb); +} + +AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr, uint16_t rport, struct netif * ntif) +{ + _udp = udp; + _pb = pb; + _if = TCPIP_ADAPTER_IF_MAX; + _data = (uint8_t*)(pb->payload); + _len = pb->len; + _index = 0; + + pbuf_ref(_pb); + + //memcpy(&_remoteIp, raddr, sizeof(ip_addr_t)); + _remoteIp.type = raddr->type; + _localIp.type = _remoteIp.type; + + eth_hdr* eth = NULL; + udp_hdr* udphdr = (udp_hdr *)(_data - UDP_HLEN); + _localPort = ntohs(udphdr->dest); + _remotePort = ntohs(udphdr->src); + + if (_remoteIp.type == IPADDR_TYPE_V4) { + eth = (eth_hdr *)(_data - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR); + struct ip_hdr * iphdr = (struct ip_hdr *)(_data - UDP_HLEN - IP_HLEN); + _localIp.u_addr.ip4.addr = iphdr->dest.addr; + _remoteIp.u_addr.ip4.addr = iphdr->src.addr; + } else { + eth = (eth_hdr *)(_data - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR); + struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(_data - UDP_HLEN - IP6_HLEN); + memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16); + memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16); + } + memcpy(_remoteMac, eth->src.addr, 6); + + struct netif * netif = NULL; + void * nif = NULL; + int i; + for (i=0; i a){ + len = a; + } + for(i=0;iwriteTo(data, len, &_remoteIp, _remotePort, _if); +} + +size_t AsyncUDPPacket::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t AsyncUDPPacket::send(AsyncUDPMessage &message) +{ + return write(message.data(), message.length()); +} + +bool AsyncUDP::_init(){ + if(_pcb){ + return true; + } + _pcb = udp_new(); + if(!_pcb){ + return false; + } + //_lock = xSemaphoreCreateMutex(); + udp_recv(_pcb, &_udp_recv, (void *) this); + return true; +} + +AsyncUDP::AsyncUDP() +{ + _pcb = NULL; + _connected = false; + _lastErr = ERR_OK; + _handler = NULL; +} + +AsyncUDP::~AsyncUDP() +{ + close(); + UDP_MUTEX_LOCK(); + udp_recv(_pcb, NULL, NULL); + _udp_remove(_pcb); + _pcb = NULL; + UDP_MUTEX_UNLOCK(); + //vSemaphoreDelete(_lock); +} + +void AsyncUDP::close() +{ + UDP_MUTEX_LOCK(); + if(_pcb != NULL) { + if(_connected) { + _udp_disconnect(_pcb); + } + _connected = false; + //todo: unjoin multicast group + } + UDP_MUTEX_UNLOCK(); +} + +bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port) +{ + if(!_udp_task_start()){ + log_e("failed to start task"); + return false; + } + if(!_init()) { + return false; + } + close(); + UDP_MUTEX_LOCK(); + _lastErr = _udp_connect(_pcb, addr, port); + if(_lastErr != ERR_OK) { + UDP_MUTEX_UNLOCK(); + return false; + } + _connected = true; + UDP_MUTEX_UNLOCK(); + return true; +} + +bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port) +{ + if(!_udp_task_start()){ + log_e("failed to start task"); + return false; + } + if(!_init()) { + return false; + } + close(); + if(addr){ + IP_SET_TYPE_VAL(_pcb->local_ip, addr->type); + IP_SET_TYPE_VAL(_pcb->remote_ip, addr->type); + } + UDP_MUTEX_LOCK(); + if(_udp_bind(_pcb, addr, port) != ERR_OK) { + UDP_MUTEX_UNLOCK(); + return false; + } + _connected = true; + UDP_MUTEX_UNLOCK(); + return true; +} + +static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX) +{ + struct netif * netif = NULL; + if(tcpip_if < TCPIP_ADAPTER_IF_MAX){ + void * nif = NULL; + esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif); + if (err) { + return ESP_ERR_INVALID_ARG; + } + netif = (struct netif *)nif; + + if (addr->type == IPADDR_TYPE_V4) { + if(join){ + if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) { + return ESP_ERR_INVALID_STATE; + } + } + } else { + if(join){ + if (mld6_joingroup_netif(netif, &(addr->u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (mld6_leavegroup_netif(netif, &(addr->u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + } + } + } else { + if (addr->type == IPADDR_TYPE_V4) { + if(join){ + if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (igmp_leavegroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) { + return ESP_ERR_INVALID_STATE; + } + } + } else { + if(join){ + if (mld6_joingroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + } else { + if (mld6_leavegroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) { + return ESP_ERR_INVALID_STATE; + } + } + } + } + return ESP_OK; +} + +bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) +{ + if(!ip_addr_ismulticast(addr)) { + return false; + } + + if (joinMulticastGroup(addr, true, tcpip_if)!= ERR_OK) { + return false; + } + + if(!listen(NULL, port)) { + return false; + } + + UDP_MUTEX_LOCK(); + _pcb->mcast_ttl = ttl; + _pcb->remote_port = port; + ip_addr_copy(_pcb->remote_ip, *addr); + //ip_addr_copy(_pcb->remote_ip, ip_addr_any_type); + UDP_MUTEX_UNLOCK(); + + return true; +} + +size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * addr, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + if(!_pcb) { + UDP_MUTEX_LOCK(); + _pcb = udp_new(); + UDP_MUTEX_UNLOCK(); + if(_pcb == NULL) { + return 0; + } + } + if(len > CONFIG_TCP_MSS) { + len = CONFIG_TCP_MSS; + } + _lastErr = ERR_OK; + pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if(pbt != NULL) { + uint8_t* dst = reinterpret_cast(pbt->payload); + memcpy(dst, data, len); + UDP_MUTEX_LOCK(); + if(tcpip_if < TCPIP_ADAPTER_IF_MAX){ + void * nif = NULL; + tcpip_adapter_get_netif((tcpip_adapter_if_t)tcpip_if, &nif); + if(!nif){ + _lastErr = _udp_sendto(_pcb, pbt, addr, port); + } else { + _lastErr = _udp_sendto_if(_pcb, pbt, addr, port, (struct netif *)nif); + } + } else { + _lastErr = _udp_sendto(_pcb, pbt, addr, port); + } + UDP_MUTEX_UNLOCK(); + pbuf_free(pbt); + if(_lastErr < ERR_OK) { + return 0; + } + return len; + } + return 0; +} + +void AsyncUDP::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif) +{ + while(pb != NULL) { + pbuf * this_pb = pb; + pb = pb->next; + this_pb->next = NULL; + if(_handler) { + AsyncUDPPacket packet(this, this_pb, addr, port, netif); + _handler(packet); + } + pbuf_free(this_pb); + } +} + +void AsyncUDP::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif) +{ + reinterpret_cast(arg)->_recv(upcb, p, addr, port, netif); +} + +bool AsyncUDP::listen(uint16_t port) +{ + return listen(IP_ANY_TYPE, port); +} + +bool AsyncUDP::listen(const IPAddress addr, uint16_t port) +{ + ip_addr_t laddr; + laddr.type = IPADDR_TYPE_V4; + laddr.u_addr.ip4.addr = addr; + return listen(&laddr, port); +} + +bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) +{ + ip_addr_t laddr; + laddr.type = IPADDR_TYPE_V4; + laddr.u_addr.ip4.addr = addr; + return listenMulticast(&laddr, port, ttl, tcpip_if); +} + +bool AsyncUDP::connect(const IPAddress addr, uint16_t port) +{ + ip_addr_t daddr; + daddr.type = IPADDR_TYPE_V4; + daddr.u_addr.ip4.addr = addr; + return connect(&daddr, port); +} + +size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + ip_addr_t daddr; + daddr.type = IPADDR_TYPE_V4; + daddr.u_addr.ip4.addr = addr; + return writeTo(data, len, &daddr, port, tcpip_if); +} + +IPAddress AsyncUDP::listenIP() +{ + if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V4){ + return IPAddress(); + } + return IPAddress(_pcb->remote_ip.u_addr.ip4.addr); +} + +bool AsyncUDP::listen(const IPv6Address addr, uint16_t port) +{ + ip_addr_t laddr; + laddr.type = IPADDR_TYPE_V6; + memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); + return listen(&laddr, port); +} + +bool AsyncUDP::listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) +{ + ip_addr_t laddr; + laddr.type = IPADDR_TYPE_V6; + memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); + return listenMulticast(&laddr, port, ttl, tcpip_if); +} + +bool AsyncUDP::connect(const IPv6Address addr, uint16_t port) +{ + ip_addr_t daddr; + daddr.type = IPADDR_TYPE_V6; + memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); + return connect(&daddr, port); +} + +size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + ip_addr_t daddr; + daddr.type = IPADDR_TYPE_V6; + memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); + return writeTo(data, len, &daddr, port, tcpip_if); +} + +IPv6Address AsyncUDP::listenIPv6() +{ + if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6){ + return IPv6Address(); + } + return IPv6Address(_pcb->remote_ip.u_addr.ip6.addr); +} + +size_t AsyncUDP::write(const uint8_t *data, size_t len) +{ + return writeTo(data, len, &(_pcb->remote_ip), _pcb->remote_port); +} + +size_t AsyncUDP::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t AsyncUDP::broadcastTo(uint8_t *data, size_t len, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + return writeTo(data, len, IP_ADDR_BROADCAST, port, tcpip_if); +} + +size_t AsyncUDP::broadcastTo(const char * data, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + return broadcastTo((uint8_t *)data, strlen(data), port, tcpip_if); +} + +size_t AsyncUDP::broadcast(uint8_t *data, size_t len) +{ + if(_pcb->local_port != 0) { + return broadcastTo(data, len, _pcb->local_port); + } + return 0; +} + +size_t AsyncUDP::broadcast(const char * data) +{ + return broadcast((uint8_t *)data, strlen(data)); +} + + +size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), addr, port, tcpip_if); +} + +size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), addr, port, tcpip_if); +} + +size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), addr, port, tcpip_if); +} + +size_t AsyncUDP::send(AsyncUDPMessage &message) +{ + if(!message) { + return 0; + } + return writeTo(message.data(), message.length(), &(_pcb->remote_ip), _pcb->remote_port); +} + +size_t AsyncUDP::broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if) +{ + if(!message) { + return 0; + } + return broadcastTo(message.data(), message.length(), port, tcpip_if); +} + +size_t AsyncUDP::broadcast(AsyncUDPMessage &message) +{ + if(!message) { + return 0; + } + return broadcast(message.data(), message.length()); +} + +AsyncUDP::operator bool() +{ + return _connected; +} + +bool AsyncUDP::connected() +{ + return _connected; +} + +esp_err_t AsyncUDP::lastErr() { + return _lastErr; +} + +void AsyncUDP::onPacket(AuPacketHandlerFunctionWithArg cb, void * arg) +{ + onPacket(std::bind(cb, arg, std::placeholders::_1)); +} + +void AsyncUDP::onPacket(AuPacketHandlerFunction cb) +{ + _handler = cb; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/src/AsyncUDP.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/src/AsyncUDP.h new file mode 100644 index 0000000..c9f365d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/AsyncUDP/src/AsyncUDP.h @@ -0,0 +1,165 @@ +#ifndef ESPASYNCUDP_H +#define ESPASYNCUDP_H + +#include "IPAddress.h" +#include "IPv6Address.h" +#include "Print.h" +#include "Stream.h" +#include +extern "C" { +#include "esp_netif.h" +#include "lwip/ip_addr.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +} + +// This enum and it's uses are copied and adapted for compatibility from ESP-IDF 4- +typedef enum { + TCPIP_ADAPTER_IF_STA = 0, /**< Wi-Fi STA (station) interface */ + TCPIP_ADAPTER_IF_AP, /**< Wi-Fi soft-AP interface */ + TCPIP_ADAPTER_IF_ETH, /**< Ethernet interface */ + TCPIP_ADAPTER_IF_PPP, /**< PPP interface */ + TCPIP_ADAPTER_IF_MAX +} tcpip_adapter_if_t; + +class AsyncUDP; +class AsyncUDPPacket; +class AsyncUDPMessage; +struct udp_pcb; +struct pbuf; +struct netif; + +typedef std::function AuPacketHandlerFunction; +typedef std::function AuPacketHandlerFunctionWithArg; + +class AsyncUDPMessage : public Print +{ +protected: + uint8_t *_buffer; + size_t _index; + size_t _size; +public: + AsyncUDPMessage(size_t size=CONFIG_TCP_MSS); + virtual ~AsyncUDPMessage(); + size_t write(const uint8_t *data, size_t len); + size_t write(uint8_t data); + size_t space(); + uint8_t * data(); + size_t length(); + void flush(); + operator bool() + { + return _buffer != NULL; + } +}; + +class AsyncUDPPacket : public Stream +{ +protected: + AsyncUDP *_udp; + pbuf *_pb; + tcpip_adapter_if_t _if; + ip_addr_t _localIp; + uint16_t _localPort; + ip_addr_t _remoteIp; + uint16_t _remotePort; + uint8_t _remoteMac[6]; + uint8_t *_data; + size_t _len; + size_t _index; +public: + AsyncUDPPacket(AsyncUDPPacket &packet); + AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif); + virtual ~AsyncUDPPacket(); + + uint8_t * data(); + size_t length(); + bool isBroadcast(); + bool isMulticast(); + bool isIPv6(); + + tcpip_adapter_if_t interface(); + + IPAddress localIP(); + IPv6Address localIPv6(); + uint16_t localPort(); + IPAddress remoteIP(); + IPv6Address remoteIPv6(); + uint16_t remotePort(); + void remoteMac(uint8_t * mac); + + size_t send(AsyncUDPMessage &message); + + int available(); + size_t read(uint8_t *data, size_t len); + int read(); + int peek(); + void flush(); + + size_t write(const uint8_t *data, size_t len); + size_t write(uint8_t data); +}; + +class AsyncUDP : public Print +{ +protected: + udp_pcb *_pcb; + //SemaphoreHandle_t _lock; + bool _connected; + esp_err_t _lastErr; + AuPacketHandlerFunction _handler; + + bool _init(); + void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif); + +public: + AsyncUDP(); + virtual ~AsyncUDP(); + + void onPacket(AuPacketHandlerFunctionWithArg cb, void * arg=NULL); + void onPacket(AuPacketHandlerFunction cb); + + bool listen(const ip_addr_t *addr, uint16_t port); + bool listen(const IPAddress addr, uint16_t port); + bool listen(const IPv6Address addr, uint16_t port); + bool listen(uint16_t port); + + bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + + bool connect(const ip_addr_t *addr, uint16_t port); + bool connect(const IPAddress addr, uint16_t port); + bool connect(const IPv6Address addr, uint16_t port); + + void close(); + + size_t writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t write(const uint8_t *data, size_t len); + size_t write(uint8_t data); + + size_t broadcastTo(uint8_t *data, size_t len, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t broadcastTo(const char * data, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t broadcast(uint8_t *data, size_t len); + size_t broadcast(const char * data); + + size_t sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t send(AsyncUDPMessage &message); + + size_t broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); + size_t broadcast(AsyncUDPMessage &message); + + IPAddress listenIP(); + IPv6Address listenIPv6(); + bool connected(); + esp_err_t lastErr(); + operator bool(); + + static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif); +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/LICENSE b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/LICENSE new file mode 100644 index 0000000..4558f79 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Neil Kolban + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/README.md new file mode 100644 index 0000000..e80fbe0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/README.md @@ -0,0 +1,15 @@ +# ESP32 BLE for Arduino +The Arduino IDE provides an excellent library package manager where versions of libraries can be downloaded and installed. This Github project provides the repository for the ESP32 BLE support for Arduino. + +The actual source of the project which is being maintained can be found here: + +https://github.com/nkolban/esp32-snippets + +Issues and questions should be raised here: + +https://github.com/nkolban/esp32-snippets/issues + + +Documentation for using the library can be found here: + +https://github.com/nkolban/esp32-snippets/tree/master/Documentation \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/BLE5_extended_scan.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/BLE5_extended_scan.ino new file mode 100644 index 0000000..ebba036 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_extended_scan/BLE5_extended_scan.ino @@ -0,0 +1,50 @@ +/* + BLE5 extended scan example for esp32 C3 and S3 + with this code it is simple to scan legacy (BLE4) compatible advertising, + and BLE5 extended advertising. New coded added in BLEScan is not changing old behavior, + which can be used with old esp32, but is adding functionality to use on C3/S3. + With this new API advertised device wont be stored in API, it is now user responsibility + + author: chegewara +*/ +#ifndef SOC_BLE_50_SUPPORTED +#warning "This SoC does not support BLE5. Try using ESP32-C3, or ESP32-S3" +#else + +#include +#include +#include +#include + +uint32_t scanTime = 100; //In 10ms (1000ms) +BLEScan* pBLEScan; + +class MyBLEExtAdvertisingCallbacks: public BLEExtAdvertisingCallbacks { + void onResult(esp_ble_gap_ext_adv_reprot_t report) { + if(report.event_type & ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY){ + // here we can receive regular advertising data from BLE4.x devices + Serial.println("BLE4.2"); + } else { + // here we will get extended advertising data that are advertised over data channel by BLE5 divices + Serial.printf("Ext advertise: data_le: %d, data_status: %d \n", report.adv_data_len, report.data_status); + } + } +}; + +void setup() { + Serial.begin(115200); + Serial.println("Scanning..."); + + BLEDevice::init(""); + pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setExtendedScanCallback(new MyBLEExtAdvertisingCallbacks()); + pBLEScan->setExtScanParams(); // use with pre-defined/default values, overloaded function allows to pass parameters + delay(1000); // it is just for simplicity this example, to let ble stack to set extended scan params + pBLEScan->startExtScan(scanTime, 3); // scan duration in n * 10ms, period - repeat after n seconds (period >= duration) +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} +#endif // SOC_BLE_50_SUPPORTED diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/BLE5_multi_advertising.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/BLE5_multi_advertising.ino new file mode 100644 index 0000000..5193504 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_multi_advertising/BLE5_multi_advertising.ino @@ -0,0 +1,159 @@ +/* + Simple BLE5 multi advertising example on esp32 C3/S3 + only ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND is backward compatible + and can be scanned with BLE4.2 devices + + author: chegewara +*/ + +#ifndef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + #error "This SoC does not support BLE5. Try using ESP32-C3, or ESP32-S3" +#else + +#include +#include + +esp_ble_gap_ext_adv_params_t ext_adv_params_1M = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_CONNECTABLE, + .interval_min = 0x30, + .interval_max = 0x30, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr = {0,0,0,0,0,0}, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE, + .primary_phy = ESP_BLE_GAP_PHY_CODED, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_1M, + .sid = 0, + .scan_req_notif = false, +}; + +esp_ble_gap_ext_adv_params_t ext_adv_params_2M = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE, + .interval_min = 0x40, + .interval_max = 0x40, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr = {0,0,0,0,0,0}, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_2M, + .sid = 1, + .scan_req_notif = false, +}; + +esp_ble_gap_ext_adv_params_t legacy_adv_params = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND, + .interval_min = 0x45, + .interval_max = 0x45, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr = {0,0,0,0,0,0}, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_1M, + .sid = 2, + .scan_req_notif = false, +}; + +esp_ble_gap_ext_adv_params_t ext_adv_params_coded = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_SCANNABLE, + .interval_min = 0x50, + .interval_max = 0x50, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr = {0,0,0,0,0,0}, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_CODED, + .sid = 3, + .scan_req_notif = false, +}; + +static uint8_t raw_adv_data_1m[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x12, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', '1', 'M', 0X0 +}; + +static uint8_t raw_scan_rsp_data_2m[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x12, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', '2', 'M', 0X0 +}; + +static uint8_t legacy_adv_data[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x15, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', 'C', 'O', 'D', 'E', 'D', 0X0 +}; + +static uint8_t legacy_scan_rsp_data[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x16, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', 'L', 'E', 'G', 'A', 'C', 'Y', 0X0 +}; + +static uint8_t raw_scan_rsp_data_coded[] = { + 0x37, 0x09, 'V', 'E', 'R', 'Y', '_', 'L', 'O', 'N', 'G', '_', 'D', 'E', 'V', 'I', 'C', 'E', '_', 'N', 'A', 'M', 'E', '_', + 'S', 'E', 'N', 'T', '_', 'U', 'S', 'I', 'N', 'G', '_', 'E', 'X', 'T', 'E', 'N', 'D', 'E', 'D', '_', 'A', 'D', 'V', 'E', 'R', 'T', 'I', 'S', 'I', 'N', 'G', 0X0 +}; + + +uint8_t addr_1m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x01}; +uint8_t addr_2m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x02}; +uint8_t addr_legacy[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x03}; +uint8_t addr_coded[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x04}; + +BLEMultiAdvertising advert(4); // max number of advertisement data + +void setup() { + Serial.begin(115200); + Serial.println("Multi-Advertising..."); + + BLEDevice::init(""); + + advert.setAdvertisingParams(0, &ext_adv_params_1M); + advert.setAdvertisingData(0, sizeof(raw_adv_data_1m), &raw_adv_data_1m[0]); + advert.setInstanceAddress(0, addr_1m); + advert.setDuration(0); + + advert.setAdvertisingParams(1, &ext_adv_params_2M); + advert.setScanRspData(1, sizeof(raw_scan_rsp_data_2m), &raw_scan_rsp_data_2m[0]); + advert.setInstanceAddress(1, addr_2m); + advert.setDuration(1); + + advert.setAdvertisingParams(2, &legacy_adv_params); + advert.setAdvertisingData(2, sizeof(legacy_adv_data), &legacy_adv_data[0]); + advert.setScanRspData(2, sizeof(legacy_scan_rsp_data), &legacy_scan_rsp_data[0]); + advert.setInstanceAddress(2, addr_legacy); + advert.setDuration(2); + + advert.setAdvertisingParams(3, &ext_adv_params_coded); + advert.setDuration(3); + advert.setScanRspData(3, sizeof(raw_scan_rsp_data_coded), &raw_scan_rsp_data_coded[0]); + advert.setInstanceAddress(3, addr_coded); + + delay(1000); + advert.start(4, 0); +} + +void loop() { + delay(2000); +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino new file mode 100644 index 0000000..123a5d1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_advertising/BLE5_periodic_advertising.ino @@ -0,0 +1,79 @@ +/* + Simple BLE5 multi advertising example on esp32 C3/S3 + only ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED can be used for periodic advertising + + author: chegewara +*/ + +#ifndef CONFIG_BT_BLE_50_FEATURES_SUPPORTED + #error "This SoC does not support BLE5. Try using ESP32-C3, or ESP32-S3" +#else +#include +#include + + +esp_ble_gap_ext_adv_params_t ext_adv_params_2M = { + .type = ESP_BLE_GAP_SET_EXT_ADV_PROP_NONCONN_NONSCANNABLE_UNDIRECTED, + .interval_min = 0x40, + .interval_max = 0x40, + .channel_map = ADV_CHNL_ALL, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr_type = BLE_ADDR_TYPE_RANDOM, + .peer_addr = {0,0,0,0,0,0}, + .filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, + .tx_power = EXT_ADV_TX_PWR_NO_PREFERENCE, + .primary_phy = ESP_BLE_GAP_PHY_1M, + .max_skip = 0, + .secondary_phy = ESP_BLE_GAP_PHY_2M, + .sid = 1, + .scan_req_notif = false, +}; + +static uint8_t raw_scan_rsp_data_2m[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x12, 0x09, 'E', 'S', 'P', '_', 'M', 'U', 'L', 'T', 'I', '_', 'A', + 'D', 'V', '_', '2', 'M', 0X0 +}; + +static esp_ble_gap_periodic_adv_params_t periodic_adv_params = { + .interval_min = 0x320, // 1000 ms interval + .interval_max = 0x640, + .properties = 0, // Do not include TX power +}; + +static uint8_t periodic_adv_raw_data[] = { + 0x02, 0x01, 0x06, + 0x02, 0x0a, 0xeb, + 0x03, 0x03, 0xab, 0xcd, + 0x11, 0x09, 'E', 'S', 'P', '_', 'P', 'E', 'R', 'I', 'O', 'D', 'I', + 'C', '_', 'A', 'D', 'V' +}; + + +uint8_t addr_2m[6] = {0xc0, 0xde, 0x52, 0x00, 0x00, 0x02}; + +BLEMultiAdvertising advert(1); // max number of advertisement data + +void setup() { + Serial.begin(115200); + Serial.println("Multi-Advertising..."); + + BLEDevice::init(""); + + advert.setAdvertisingParams(0, &ext_adv_params_2M); + advert.setAdvertisingData(0, sizeof(raw_scan_rsp_data_2m), &raw_scan_rsp_data_2m[0]); + advert.setInstanceAddress(0, addr_2m); + advert.setDuration(0, 0, 0); + + delay(100); + advert.start(); + advert.setPeriodicAdvertisingParams(0, &periodic_adv_params); + advert.setPeriodicAdvertisingData(0, sizeof(periodic_adv_raw_data), &periodic_adv_raw_data[0]); + advert.startPeriodicAdvertising(0); +} + +void loop() { + delay(2000); +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/BLE5_periodic_sync.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/BLE5_periodic_sync.ino new file mode 100644 index 0000000..c3d9eb6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/BLE5_periodic_sync/BLE5_periodic_sync.ino @@ -0,0 +1,108 @@ +/* + BLE5 extended scan example for esp32 C3 and S3 + with this code it is simple to scan legacy (BLE4) compatible advertising, + and BLE5 extended advertising. New coded added in BLEScan is not changing old behavior, + which can be used with old esp32, but is adding functionality to use on C3/S3. + With this new API advertised device wont be stored in API, it is now user responsibility + + author: chegewara +*/ +#ifndef SOC_BLE_50_SUPPORTED +#warning "This SoC does not support BLE5. Try using ESP32-C3, or ESP32-S3" +#else +#include +#include +#include + +BLEScan *pBLEScan; +static bool periodic_sync = false; + +static esp_ble_gap_periodic_adv_sync_params_t periodic_adv_sync_params = { + .filter_policy = 0, + .sid = 0, + .addr_type = BLE_ADDR_TYPE_RANDOM, + .addr = {0,0,0,0,0,0}, + .skip = 10, + .sync_timeout = 1000, // timeout: 1000 * 10ms +}; + +class MyBLEExtAdvertisingCallbacks : public BLEExtAdvertisingCallbacks +{ + void onResult(esp_ble_gap_ext_adv_reprot_t params) + { + uint8_t *adv_name = NULL; + uint8_t adv_name_len = 0; + adv_name = esp_ble_resolve_adv_data(params.adv_data, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); + if ((adv_name != NULL) && (memcmp(adv_name, "ESP_MULTI_ADV_2M", adv_name_len) == 0) && !periodic_sync) + { + periodic_sync = true; + char adv_temp_name[60] = {'0'}; + memcpy(adv_temp_name, adv_name, adv_name_len); + log_i("Start create sync with the peer device %s", adv_temp_name); + periodic_adv_sync_params.sid = params.sid; + // periodic_adv_sync_params.addr_type = params.addr_type; + memcpy(periodic_adv_sync_params.addr, params.addr, sizeof(esp_bd_addr_t)); + esp_ble_gap_periodic_adv_create_sync(&periodic_adv_sync_params); + } + } +}; + +class MyPeriodicScan : public BLEPeriodicScanCallbacks +{ + // void onCreateSync(esp_bt_status_t status){} + // void onCancelSync(esp_bt_status_t status){} + // void onTerminateSync(esp_bt_status_t status){} + + void onStop(esp_bt_status_t status) + { + log_i("ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT"); + periodic_sync = false; + pBLEScan->startExtScan(0, 0); // scan duration in n * 10ms, period - repeat after n seconds (period >= duration) + } + + void onLostSync(uint16_t sync_handle) + { + log_i("ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT"); + esp_ble_gap_stop_ext_scan(); + } + + void onSync(esp_ble_periodic_adv_sync_estab_param_t params) + { + log_i("ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT, status %d", params.status); + // esp_log_buffer_hex("sync addr", param->periodic_adv_sync_estab.adv_addr, 6); + log_i("sync handle %d sid %d perioic adv interval %d adv phy %d", params.sync_handle, + params.sid, + params.period_adv_interval, + params.adv_phy); + } + + void onReport(esp_ble_gap_periodic_adv_report_t params) + { + log_i("periodic adv report, sync handle %d data status %d data len %d rssi %d", params.sync_handle, + params.data_status, + params.data_length, + params.rssi); + } +}; + +void setup() +{ + Serial.begin(115200); + Serial.println("Periodic scan..."); + + BLEDevice::init(""); + pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setExtendedScanCallback(new MyBLEExtAdvertisingCallbacks()); + pBLEScan->setExtScanParams(); // use with pre-defined/default values, overloaded function allows to pass parameters + pBLEScan->setPeriodicScanCallback(new MyPeriodicScan()); + delay(100); // it is just for simplicity this example, to let ble stack to set extended scan params + pBLEScan->startExtScan(0, 0); + +} + +void loop() +{ + delay(2000); +} + +#endif // SOC_BLE_50_SUPPORTED diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.ino new file mode 100644 index 0000000..ce36dd7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.ino @@ -0,0 +1,120 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp + Ported to Arduino ESP32 by Evandro Copercini + Changed to a beacon scanner to report iBeacon, EddystoneURL and EddystoneTLM beacons by beegee-tokyo + Upgraded Eddystone part by Tomas Pilny on Feb 20, 2023 +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +int scanTime = 5; //In seconds +BLEScan *pBLEScan; + +class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks +{ + void onResult(BLEAdvertisedDevice advertisedDevice) + { + if (advertisedDevice.haveName()) + { + Serial.print("Device name: "); + Serial.println(advertisedDevice.getName().c_str()); + Serial.println(""); + } + + if (advertisedDevice.haveServiceUUID()) + { + BLEUUID devUUID = advertisedDevice.getServiceUUID(); + Serial.print("Found ServiceUUID: "); + Serial.println(devUUID.toString().c_str()); + Serial.println(""); + } + + if (advertisedDevice.haveManufacturerData() == true) + { + String strManufacturerData = advertisedDevice.getManufacturerData(); + + uint8_t cManufacturerData[100]; + memcpy(cManufacturerData, strManufacturerData.c_str(), strManufacturerData.length()); + + if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00) + { + Serial.println("Found an iBeacon!"); + BLEBeacon oBeacon = BLEBeacon(); + oBeacon.setData(strManufacturerData); + Serial.printf("iBeacon Frame\n"); + Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower()); + } + else + { + Serial.println("Found another manufacturers beacon!"); + Serial.printf("strManufacturerData: %d ", strManufacturerData.length()); + for (int i = 0; i < strManufacturerData.length(); i++) + { + Serial.printf("[%X]", cManufacturerData[i]); + } + Serial.printf("\n"); + } + } + + if (advertisedDevice.getFrameType() == BLE_EDDYSTONE_URL_FRAME) + { + Serial.println("Found an EddystoneURL beacon!"); + BLEEddystoneURL EddystoneURL = BLEEddystoneURL(&advertisedDevice); + Serial.printf("URL bytes: 0x"); + String url = EddystoneURL.getURL(); + for(auto byte : url){ + Serial.printf("%02X", byte); + } + Serial.printf("\n"); + Serial.printf("Decoded URL: %s\n", EddystoneURL.getDecodedURL().c_str()); + Serial.printf("EddystoneURL.getDecodedURL(): %s\n", EddystoneURL.getDecodedURL().c_str()); + Serial.printf("TX power %d (Raw 0x%02X)\n", EddystoneURL.getPower(), EddystoneURL.getPower()); + Serial.println("\n"); + } + + if (advertisedDevice.getFrameType() == BLE_EDDYSTONE_TLM_FRAME) + { + Serial.println("Found an EddystoneTLM beacon!"); + BLEEddystoneTLM EddystoneTLM(&advertisedDevice); + Serial.printf("Reported battery voltage: %dmV\n", EddystoneTLM.getVolt()); + Serial.printf("Reported temperature: %.2f°C (raw data=0x%04X)\n", EddystoneTLM.getTemp(), EddystoneTLM.getRawTemp()); + Serial.printf("Reported advertise count: %lu\n", EddystoneTLM.getCount()); + Serial.printf("Reported time since last reboot: %lus\n", EddystoneTLM.getTime()); + Serial.println("\n"); + Serial.print(EddystoneTLM.toString().c_str()); + Serial.println("\n"); + } + } +}; + +void setup() +{ + Serial.begin(115200); + Serial.println("Scanning..."); + + BLEDevice::init(""); + pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster + pBLEScan->setInterval(100); + pBLEScan->setWindow(99); // less or equal setInterval value +} + +void loop() +{ + // put your main code here, to run repeatedly: + BLEScanResults foundDevices = pBLEScan->start(scanTime, false); + Serial.print("Devices found: "); + Serial.println(foundDevices.getCount()); + Serial.println("Scan done!"); + pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory + delay(2000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.md new file mode 100644 index 0000000..558c3e7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Beacon_Scanner/Beacon_Scanner.md @@ -0,0 +1,9 @@ +## BLE Beacon Scanner + +Initiates a BLE device scan. +Checks if the discovered devices are +- an iBeacon +- an Eddystone TLM beacon +- an Eddystone URL beacon + +and sends the decoded beacon information over Serial log \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Client/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Client/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Client/Client.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Client/Client.ino new file mode 100644 index 0000000..5d7f5d5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Client/Client.ino @@ -0,0 +1,163 @@ +/** + * A BLE client example that is rich in capabilities. + * There is a lot new capabilities implemented. + * author unknown + * updated by chegewara + */ + +#include "BLEDevice.h" +//#include "BLEScan.h" + +// The remote service we wish to connect to. +static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b"); +// The characteristic of the remote service we are interested in. +static BLEUUID charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8"); + +static boolean doConnect = false; +static boolean connected = false; +static boolean doScan = false; +static BLERemoteCharacteristic* pRemoteCharacteristic; +static BLEAdvertisedDevice* myDevice; + +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); + Serial.print("data: "); + Serial.write(pData, length); + Serial.println(); +} + +class MyClientCallback : public BLEClientCallbacks { + void onConnect(BLEClient* pclient) { + } + + void onDisconnect(BLEClient* pclient) { + connected = false; + Serial.println("onDisconnect"); + } +}; + +bool connectToServer() { + Serial.print("Forming a connection to "); + Serial.println(myDevice->getAddress().toString().c_str()); + + BLEClient* pClient = BLEDevice::createClient(); + Serial.println(" - Created client"); + + pClient->setClientCallbacks(new MyClientCallback()); + + // Connect to the remove BLE Server. + pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private) + Serial.println(" - Connected to server"); + pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise) + + // 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()); + pClient->disconnect(); + 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()); + pClient->disconnect(); + return false; + } + Serial.println(" - Found our characteristic"); + + // Read the value of the characteristic. + if(pRemoteCharacteristic->canRead()) { + String value = pRemoteCharacteristic->readValue(); + Serial.print("The characteristic value was: "); + Serial.println(value.c_str()); + } + + if(pRemoteCharacteristic->canNotify()) + pRemoteCharacteristic->registerForNotify(notifyCallback); + + connected = true; + return true; +} +/** + * 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.isAdvertisingService(serviceUUID)) { + + BLEDevice::getScan()->stop(); + myDevice = new BLEAdvertisedDevice(advertisedDevice); + doConnect = true; + doScan = 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 5 seconds. + BLEScan* pBLEScan = BLEDevice::getScan(); + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setInterval(1349); + pBLEScan->setWindow(449); + pBLEScan->setActiveScan(true); + pBLEScan->start(5, false); +} // 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()) { + Serial.println("We are now connected to the BLE Server."); + } 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()); + }else if(doScan){ + BLEDevice::getScan()->start(0); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino + } + + delay(1000); // Delay a second between loops. +} // End of loop diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/EddystoneTLM_Beacon.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/EddystoneTLM_Beacon.ino new file mode 100644 index 0000000..c608133 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/EddystoneTLM_Beacon.ino @@ -0,0 +1,96 @@ +/* + EddystoneTLM beacon by BeeGee based on https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino + EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md +*/ + +/* + Create a BLE server that will send periodic Eddystone URL frames. + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create advertising data + 3. Start advertising. + 4. wait + 5. Stop advertising. + 6. deep sleep + + To read data advertised by this beacon use second ESP with example sketch BLE_Beacon_Scanner +*/ +#include "sys/time.h" + +#include + +#include "BLEDevice.h" +#include "BLEUtils.h" +#include "BLEBeacon.h" +#include "BLEAdvertising.h" +#include "BLEEddystoneTLM.h" + +#include "esp_sleep.h" + +#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up +#define BEACON_POWER ESP_PWR_LVL_N12 +RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory +RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ +BLEAdvertising *pAdvertising; +struct timeval nowTimeStruct; + +time_t lastTenth; + +#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) + +// Check +// https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md +// and http://www.hugi.scene.org/online/coding/hugi%2015%20-%20cmtadfix.htm +// for the temperature value. It is a 8.8 fixed-point notation +void setBeacon() +{ + BLEEddystoneTLM EddystoneTLM; + EddystoneTLM.setVolt((uint16_t)random(2800, 3700)); // 3300mV = 3.3V + EddystoneTLM.setTemp(random(-3000, 3000) / 100.0f); // 3000 = 30.00 ˚C + Serial.printf("Random Battery voltage is %d mV = 0x%04X\n", EddystoneTLM.getVolt(), EddystoneTLM.getVolt()); + Serial.printf("Random temperature is %.2f°C\n", EddystoneTLM.getTemp()); + Serial.printf("Converted to 8.8 format: 0x%04X\n", EddystoneTLM.getRawTemp()); + + BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); + BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); + oScanResponseData.setServiceData(BLEUUID((uint16_t)0xFEAA), String(EddystoneTLM.getData().c_str(), EddystoneTLM.getData().length())); + + oAdvertisementData.setName("ESP32 TLM Beacon"); + pAdvertising->setAdvertisementData(oAdvertisementData); + pAdvertising->setScanResponseData(oScanResponseData); +} + +void setup() +{ + Serial.begin(115200); + gettimeofday(&nowTimeStruct, NULL); + + Serial.printf("Starting ESP32. Bootcount = %lu\n", bootcount++); + Serial.printf("Deep sleep (%llds since last reset, %llds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last); + + last = nowTimeStruct.tv_sec; + lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter + + // Create the BLE Device + BLEDevice::init("TLMBeacon"); + + BLEDevice::setPower(BEACON_POWER); + + pAdvertising = BLEDevice::getAdvertising(); + + setBeacon(); + // Start advertising + pAdvertising->start(); + Serial.println("Advertising started for 10s ..."); + delay(10000); + pAdvertising->stop(); + Serial.printf("Enter deep sleep for 10s\n"); + esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); +} + +void loop() +{ +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/EddystoneTLM_Beacon.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/EddystoneTLM_Beacon.md new file mode 100644 index 0000000..2e34029 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneTLM_Beacon/EddystoneTLM_Beacon.md @@ -0,0 +1,14 @@ +## Eddystone TLM beacon +EddystoneTLM beacon by BeeGee based on +[pcbreflux ESP32 Eddystone TLM deepsleep](https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino) + +[EddystoneTLM frame specification](https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md) + + Create a BLE server that will send periodic Eddystone TLM frames. + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create advertising data + 3. Start advertising. + 4. wait + 5. Stop advertising. + 6. deep sleep diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/EddystoneURL_Beacon.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/EddystoneURL_Beacon.ino new file mode 100644 index 0000000..d2d9b2d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/EddystoneURL_Beacon.ino @@ -0,0 +1,109 @@ +/* + EddystoneURL beacon by BeeGee + EddystoneURL frame specification https://github.com/google/eddystone/blob/master/eddystone-url/README.md + + Upgraded on: Feb 20, 2023 + By: Tomas Pilny +*/ + +/* + Create a BLE server that will send periodic Eddystone URL frames. + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create advertising data + 3. Start advertising. + 4. wait + 5. Stop advertising. + 6. deep sleep + +*/ +#include "sys/time.h" + +#include + +#include "BLEDevice.h" +#include "BLEUtils.h" +#include "BLEBeacon.h" +#include "BLEAdvertising.h" +#include "BLEEddystoneURL.h" +#include "esp_sleep.h" + +char unprintable[] = {0x01, 0xFF, 0xDE, 0xAD}; +String URL[] = { + "http://www.espressif.com/", // prefix 0x00, suffix 0x00 + "https://www.texas.gov", // prefix 0x01, suffix 0x0D + "http://en.mapy.cz", // prefix 0x02, no valid suffix + "https://arduino.cc", // prefix 0x03, no valid suffix + "google.com", // URL without specified prefix - the function will assume default prefix "http://www." = 0x00 + "diginfo.tv", // URL without specified prefix - the function will assume default prefix "http://www." = 0x00 +// "http://www.URLsAbove17BytesAreNotAllowed.com", // Too long URL - setSmartURL() will return 0 = ERR +// "", // Empty string - setSmartURL() will return 0 = ERR +// String(unprintable), // Unprintable characters / corrupted String - setSmartURL() will return 0 = ERR +}; + +#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up +#define BEACON_POWER ESP_PWR_LVL_N12 +RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory +RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ +BLEAdvertising *pAdvertising; +struct timeval now; + +int setBeacon() +{ + BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); + BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); + + BLEEddystoneURL EddystoneURL; + EddystoneURL.setPower(BEACON_POWER); // This is only information about the power. The actual power is set by `BLEDevice::setPower(BEACON_POWER)` + if(EddystoneURL.setSmartURL(URL[bootcount%(sizeof(URL)/sizeof(URL[0]))])){ + String frame = EddystoneURL.getFrame(); + String data(EddystoneURL.getFrame().c_str(), frame.length()); + oAdvertisementData.addData(data); + oScanResponseData.setName("ESP32 URLBeacon"); + pAdvertising->setAdvertisementData(oAdvertisementData); + pAdvertising->setScanResponseData(oScanResponseData); + Serial.printf("Advertise URL \"%s\"\n", URL[bootcount%(sizeof(URL)/sizeof(URL[0]))].c_str()); + return 1; // OK + }else{ + Serial.println("Smart URL set ERR"); + return 0; // ERR + } +} + +void setup() +{ + Serial.begin(115200); + gettimeofday(&now, NULL); + + Serial.printf("Start ESP32 %lu\n", bootcount++); + Serial.printf("Deep sleep (%llds since last reset, %llds since last boot)\n", now.tv_sec, now.tv_sec - last); + + last = now.tv_sec; + + // Create the BLE Device + BLEDevice::init("URLBeacon"); + BLEDevice::setPower(BEACON_POWER); + + // Create the BLE Server + // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage + + pAdvertising = BLEDevice::getAdvertising(); + + if(setBeacon()){ + // Start advertising + pAdvertising->start(); + Serial.println("Advertising started..."); + delay(10000); + pAdvertising->stop(); + } + Serial.println("Enter deep sleep"); + bootcount++; + esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); +} + +void loop() +{ +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/EddystoneURL_Beacon.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/EddystoneURL_Beacon.md new file mode 100644 index 0000000..2baf1cc --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/EddystoneURL_Beacon/EddystoneURL_Beacon.md @@ -0,0 +1,14 @@ +## Eddystone URL beacon +EddystoneURL beacon by BeeGee based on +[pcbreflux ESP32 Eddystone URL deepsleep](https://github.com/pcbreflux/espressif/tree/master/esp32/arduino/sketchbook/ESP32_Eddystone_URL_deepsleep) + +[EddystoneURL frame specification](https://github.com/google/eddystone/blob/master/eddystone-url/README.md) + + Create a BLE server that will send periodic Eddystone URL frames. + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create advertising data + 3. Start advertising. + 4. wait + 5. Stop advertising. + 6. deep sleep diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Notify/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Notify/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Notify/Notify.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Notify/Notify.ino new file mode 100644 index 0000000..42b9e72 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Notify/Notify.ino @@ -0,0 +1,110 @@ +/* + Video: https://www.youtube.com/watch?v=oCMOYS71NIU + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp + Ported to Arduino ESP32 by Evandro Copercini + updated by chegewara + + Create a BLE server that, once we receive a connection, will send periodic notifications. + The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b + And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 + + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create a BLE Service + 3. Create a BLE Characteristic on the Service + 4. Create a BLE Descriptor on the characteristic + 5. Start the service. + 6. Start advertising. + + A connect hander associated with the server starts a background task that performs notification + every couple of seconds. +*/ +#include +#include +#include +#include + +BLEServer* pServer = NULL; +BLECharacteristic* pCharacteristic = NULL; +bool deviceConnected = false; +bool oldDeviceConnected = false; +uint32_t value = 0; + +// 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" + + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + }; + + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + } +}; + + + +void setup() { + Serial.begin(115200); + + // Create the BLE Device + BLEDevice::init("ESP32"); + + // Create the BLE Server + pServer = BLEDevice::createServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + // Create the BLE Service + BLEService *pService = pServer->createService(SERVICE_UUID); + + // Create a BLE Characteristic + pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_NOTIFY | + BLECharacteristic::PROPERTY_INDICATE + ); + + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + // Create a BLE Descriptor + pCharacteristic->addDescriptor(new BLE2902()); + + // Start the service + pService->start(); + + // Start advertising + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + pAdvertising->setScanResponse(false); + pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter + BLEDevice::startAdvertising(); + Serial.println("Waiting a client connection to notify..."); +} + +void loop() { + // notify changed value + if (deviceConnected) { + pCharacteristic->setValue((uint8_t*)&value, 4); + pCharacteristic->notify(); + value++; + delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms + } + // disconnecting + if (!deviceConnected && oldDeviceConnected) { + delay(500); // give the bluetooth stack the chance to get things ready + pServer->startAdvertising(); // restart advertising + Serial.println("start advertising"); + oldDeviceConnected = deviceConnected; + } + // connecting + if (deviceConnected && !oldDeviceConnected) { + // do stuff here on connecting + oldDeviceConnected = deviceConnected; + } +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Scan/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Scan/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Scan/Scan.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Scan/Scan.ino new file mode 100644 index 0000000..094f793 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Scan/Scan.ino @@ -0,0 +1,40 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp + Ported to Arduino ESP32 by Evandro Copercini +*/ + +#include +#include +#include +#include + +int scanTime = 5; //In seconds +BLEScan* pBLEScan; + +class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { + void onResult(BLEAdvertisedDevice advertisedDevice) { + Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str()); + } +}; + +void setup() { + Serial.begin(115200); + Serial.println("Scanning..."); + + BLEDevice::init(""); + pBLEScan = BLEDevice::getScan(); //create new scan + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster + pBLEScan->setInterval(100); + pBLEScan->setWindow(99); // less or equal setInterval value +} + +void loop() { + // put your main code here, to run repeatedly: + BLEScanResults foundDevices = pBLEScan->start(scanTime, false); + Serial.print("Devices found: "); + Serial.println(foundDevices.getCount()); + Serial.println("Scan done!"); + pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory + delay(2000); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server/Server.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server/Server.ino new file mode 100644 index 0000000..3f9176a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server/Server.ino @@ -0,0 +1,45 @@ +/* + 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 + updates by chegewara +*/ + +#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("Long name works now"); + BLEServer *pServer = BLEDevice::createServer(); + BLEService *pService = pServer->createService(SERVICE_UUID); + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE + ); + + pCharacteristic->setValue("Hello World says Neil"); + pService->start(); + // BLEAdvertising *pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + pAdvertising->setScanResponse(true); + pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue + pAdvertising->setMinPreferred(0x12); + BLEDevice::startAdvertising(); + Serial.println("Characteristic defined! Now you can read it in your phone!"); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server_multiconnect/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server_multiconnect/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server_multiconnect/Server_multiconnect.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server_multiconnect/Server_multiconnect.ino new file mode 100644 index 0000000..90704ef --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Server_multiconnect/Server_multiconnect.ino @@ -0,0 +1,111 @@ +/* + Video: https://www.youtube.com/watch?v=oCMOYS71NIU + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp + Ported to Arduino ESP32 by Evandro Copercini + updated by chegewara + + Create a BLE server that, once we receive a connection, will send periodic notifications. + The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b + And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8 + + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create a BLE Service + 3. Create a BLE Characteristic on the Service + 4. Create a BLE Descriptor on the characteristic + 5. Start the service. + 6. Start advertising. + + A connect hander associated with the server starts a background task that performs notification + every couple of seconds. +*/ +#include +#include +#include +#include + +BLEServer* pServer = NULL; +BLECharacteristic* pCharacteristic = NULL; +bool deviceConnected = false; +bool oldDeviceConnected = false; +uint32_t value = 0; + +// 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" + + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + BLEDevice::startAdvertising(); + }; + + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + } +}; + + + +void setup() { + Serial.begin(115200); + + // Create the BLE Device + BLEDevice::init("ESP32"); + + // Create the BLE Server + pServer = BLEDevice::createServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + // Create the BLE Service + BLEService *pService = pServer->createService(SERVICE_UUID); + + // Create a BLE Characteristic + pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_NOTIFY | + BLECharacteristic::PROPERTY_INDICATE + ); + + // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + // Create a BLE Descriptor + pCharacteristic->addDescriptor(new BLE2902()); + + // Start the service + pService->start(); + + // Start advertising + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + pAdvertising->setScanResponse(false); + pAdvertising->setMinPreferred(0x0); // set value to 0x00 to not advertise this parameter + BLEDevice::startAdvertising(); + Serial.println("Waiting a client connection to notify..."); +} + +void loop() { + // notify changed value + if (deviceConnected) { + pCharacteristic->setValue((uint8_t*)&value, 4); + pCharacteristic->notify(); + value++; + delay(10); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms + } + // disconnecting + if (!deviceConnected && oldDeviceConnected) { + delay(500); // give the bluetooth stack the chance to get things ready + pServer->startAdvertising(); // restart advertising + Serial.println("start advertising"); + oldDeviceConnected = deviceConnected; + } + // connecting + if (deviceConnected && !oldDeviceConnected) { + // do stuff here on connecting + oldDeviceConnected = deviceConnected; + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/UART/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/UART/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/UART/UART.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/UART/UART.ino new file mode 100644 index 0000000..3a50bf7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/UART/UART.ino @@ -0,0 +1,125 @@ +/* + Video: https://www.youtube.com/watch?v=oCMOYS71NIU + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp + Ported to Arduino ESP32 by Evandro Copercini + + Create a BLE server that, once we receive a connection, will send periodic notifications. + The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" + Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY" + + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create a BLE Service + 3. Create a BLE Characteristic on the Service + 4. Create a BLE Descriptor on the characteristic + 5. Start the service. + 6. Start advertising. + + In this example rxValue is the data received (only accessible inside that function). + And txValue is the data to be sent, in this example just a byte incremented every second. +*/ +#include +#include +#include +#include + +BLEServer *pServer = NULL; +BLECharacteristic * pTxCharacteristic; +bool deviceConnected = false; +bool oldDeviceConnected = false; +uint8_t txValue = 0; + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ + +#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID +#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" +#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" + + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + }; + + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + } +}; + +class MyCallbacks: public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *pCharacteristic) { + String rxValue = pCharacteristic->getValue(); + + if (rxValue.length() > 0) { + Serial.println("*********"); + Serial.print("Received Value: "); + for (int i = 0; i < rxValue.length(); i++) + Serial.print(rxValue[i]); + + Serial.println(); + Serial.println("*********"); + } + } +}; + + +void setup() { + Serial.begin(115200); + + // Create the BLE Device + BLEDevice::init("UART Service"); + + // Create the BLE Server + pServer = BLEDevice::createServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + // Create the BLE Service + BLEService *pService = pServer->createService(SERVICE_UUID); + + // Create a BLE Characteristic + pTxCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID_TX, + BLECharacteristic::PROPERTY_NOTIFY + ); + + pTxCharacteristic->addDescriptor(new BLE2902()); + + BLECharacteristic * pRxCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID_RX, + BLECharacteristic::PROPERTY_WRITE + ); + + pRxCharacteristic->setCallbacks(new MyCallbacks()); + + // Start the service + pService->start(); + + // Start advertising + pServer->getAdvertising()->start(); + Serial.println("Waiting a client connection to notify..."); +} + +void loop() { + + if (deviceConnected) { + pTxCharacteristic->setValue(&txValue, 1); + pTxCharacteristic->notify(); + txValue++; + delay(10); // bluetooth stack will go into congestion, if too many packets are sent + } + + // disconnecting + if (!deviceConnected && oldDeviceConnected) { + delay(500); // give the bluetooth stack the chance to get things ready + pServer->startAdvertising(); // restart advertising + Serial.println("start advertising"); + oldDeviceConnected = deviceConnected; + } + // connecting + if (deviceConnected && !oldDeviceConnected) { + // do stuff here on connecting + oldDeviceConnected = deviceConnected; + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Write/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Write/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Write/Write.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Write/Write.ino new file mode 100644 index 0000000..138bfa6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/Write/Write.ino @@ -0,0 +1,65 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.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" + + +class MyCallbacks: public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *pCharacteristic) { + String value = pCharacteristic->getValue(); + + if (value.length() > 0) { + Serial.println("*********"); + Serial.print("New value: "); + for (int i = 0; i < value.length(); i++) + Serial.print(value[i]); + + Serial.println(); + Serial.println("*********"); + } + } +}; + +void setup() { + Serial.begin(115200); + + Serial.println("1- Download and install an BLE scanner app in your phone"); + Serial.println("2- Scan for BLE devices in the app"); + Serial.println("3- Connect to MyESP32"); + Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something"); + Serial.println("5- See the magic =)"); + + BLEDevice::init("MyESP32"); + BLEServer *pServer = BLEDevice::createServer(); + + BLEService *pService = pServer->createService(SERVICE_UUID); + + BLECharacteristic *pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE + ); + + pCharacteristic->setCallbacks(new MyCallbacks()); + + pCharacteristic->setValue("Hello World"); + pService->start(); + + BLEAdvertising *pAdvertising = pServer->getAdvertising(); + pAdvertising->start(); +} + +void loop() { + // put your main code here, to run repeatedly: + delay(2000); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/iBeacon/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/iBeacon/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/iBeacon/iBeacon.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/iBeacon/iBeacon.ino new file mode 100644 index 0000000..756e2ee --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/examples/iBeacon/iBeacon.ino @@ -0,0 +1,138 @@ +/* + Based on 31337Ghost's reference code from https://github.com/nkolban/esp32-snippets/issues/385#issuecomment-362535434 + which is based on pcbreflux's Arduino ESP32 port of Neil Kolban's example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp +*/ + +/* + Create a BLE server that will send periodic iBeacon frames. + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create advertising data + 3. Start advertising. + 4. wait + 5. Stop advertising. +*/ +#include +#include +#include +#include +#include + +#define DEVICE_NAME "ESP32" +#define SERVICE_UUID "7A0247E7-8E88-409B-A959-AB5092DDB03E" +#define BEACON_UUID "2D7A9F0C-E0E8-4CC9-A71B-A21DB2D034A1" +#define BEACON_UUID_REV "A134D0B2-1DA2-1BA7-C94C-E8E00C9F7A2D" +#define CHARACTERISTIC_UUID "82258BAA-DF72-47E8-99BC-B73D7ECD08A5" + +BLEServer *pServer; +BLECharacteristic *pCharacteristic; +bool deviceConnected = false; +uint8_t value = 0; + +class MyServerCallbacks: public BLEServerCallbacks { + void onConnect(BLEServer* pServer) { + deviceConnected = true; + Serial.println("deviceConnected = true"); + }; + + void onDisconnect(BLEServer* pServer) { + deviceConnected = false; + Serial.println("deviceConnected = false"); + + // Restart advertising to be visible and connectable again + BLEAdvertising* pAdvertising; + pAdvertising = pServer->getAdvertising(); + pAdvertising->start(); + Serial.println("iBeacon advertising restarted"); + } +}; + +class MyCallbacks: public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *pCharacteristic) { + String rxValue = pCharacteristic->getValue(); + + if (rxValue.length() > 0) { + Serial.println("*********"); + Serial.print("Received Value: "); + for (int i = 0; i < rxValue.length(); i++) { + Serial.print(rxValue[i]); + } + Serial.println(); + Serial.println("*********"); + + } + } +}; + + +void init_service() { + BLEAdvertising* pAdvertising; + pAdvertising = pServer->getAdvertising(); + pAdvertising->stop(); + + // Create the BLE Service + BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID)); + + // Create a BLE Characteristic + pCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_NOTIFY + ); + pCharacteristic->setCallbacks(new MyCallbacks()); + pCharacteristic->addDescriptor(new BLE2902()); + + pAdvertising->addServiceUUID(BLEUUID(SERVICE_UUID)); + + // Start the service + pService->start(); + + pAdvertising->start(); +} + +void init_beacon() { + BLEAdvertising* pAdvertising; + pAdvertising = pServer->getAdvertising(); + pAdvertising->stop(); + // iBeacon + BLEBeacon myBeacon; + myBeacon.setManufacturerId(0x4c00); + myBeacon.setMajor(5); + myBeacon.setMinor(88); + myBeacon.setSignalPower(0xc5); + myBeacon.setProximityUUID(BLEUUID(BEACON_UUID_REV)); + + BLEAdvertisementData advertisementData; + advertisementData.setFlags(0x1A); + advertisementData.setManufacturerData(myBeacon.getData()); + pAdvertising->setAdvertisementData(advertisementData); + + pAdvertising->start(); +} + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + + BLEDevice::init(DEVICE_NAME); + pServer = BLEDevice::createServer(); + pServer->setCallbacks(new MyServerCallbacks()); + + init_service(); + init_beacon(); + + Serial.println("iBeacon + service defined and advertising!"); +} + +void loop() { + if (deviceConnected) { + Serial.printf("*** NOTIFY: %d ***\n", value); + pCharacteristic->setValue(&value, 1); + pCharacteristic->notify(); + value++; + } + delay(2000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/library.properties new file mode 100644 index 0000000..4f91de2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/library.properties @@ -0,0 +1,10 @@ +name=BLE +version=2.0.0 +author=Neil Kolban +maintainer=Dariusz Krempa +sentence=BLE functions for ESP32 +paragraph=This library provides an implementation Bluetooth Low Energy support for the ESP32 using the Arduino platform. +category=Communication +url=https://github.com/nkolban/ESP32_BLE_Arduino +architectures=esp32 +includes=BLEDevice.h, BLEUtils.h, BLEScan.h, BLEAdvertisedDevice.h diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2902.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2902.cpp new file mode 100644 index 0000000..6faa5d8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2902.cpp @@ -0,0 +1,68 @@ +/* + * BLE2902.cpp + * + * Created on: Jun 25, 2017 + * Author: kolban + */ + +/* + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLE2902.h" + +BLE2902::BLE2902() : BLEDescriptor(BLEUUID((uint16_t) 0x2902)) { + uint8_t data[2] = { 0, 0 }; + setValue(data, 2); +} // BLE2902 + + +/** + * @brief Get the notifications value. + * @return The notifications value. True if notifications are enabled and false if not. + */ +bool BLE2902::getNotifications() { + return (getValue()[0] & (1 << 0)) != 0; +} // getNotifications + + +/** + * @brief Get the indications value. + * @return The indications value. True if indications are enabled and false if not. + */ +bool BLE2902::getIndications() { + return (getValue()[0] & (1 << 1)) != 0; +} // getIndications + + +/** + * @brief Set the indications flag. + * @param [in] flag The indications flag. + */ +void BLE2902::setIndications(bool flag) { + uint8_t *pValue = getValue(); + if (flag) pValue[0] |= 1 << 1; + else pValue[0] &= ~(1 << 1); + setValue(pValue, 2); +} // setIndications + + +/** + * @brief Set the notifications flag. + * @param [in] flag The notifications flag. + */ +void BLE2902::setNotifications(bool flag) { + uint8_t *pValue = getValue(); + if (flag) pValue[0] |= 1 << 0; + else pValue[0] &= ~(1 << 0); + setValue(pValue, 2); +} // setNotifications + +#endif +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2902.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2902.h new file mode 100644 index 0000000..6218ed3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2902.h @@ -0,0 +1,38 @@ +/* + * BLE2902.h + * + * Created on: Jun 25, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLE2902_H_ +#define COMPONENTS_CPP_UTILS_BLE2902_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLEDescriptor.h" + +/** + * @brief Descriptor for Client Characteristic Configuration. + * + * This is a convenience descriptor for the Client Characteristic Configuration which has a UUID of 0x2902. + * + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml + */ +class BLE2902: public BLEDescriptor { +public: + BLE2902(); + bool getNotifications(); + bool getIndications(); + void setNotifications(bool flag); + void setIndications(bool flag); + +}; // BLE2902 + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLE2902_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2904.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2904.cpp new file mode 100644 index 0000000..5671021 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2904.cpp @@ -0,0 +1,78 @@ +/* + * BLE2904.cpp + * + * Created on: Dec 23, 2017 + * Author: kolban + */ + +/* + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLE2904.h" + + +BLE2904::BLE2904() : BLEDescriptor(BLEUUID((uint16_t) 0x2904)) { + m_data.m_format = 0; + m_data.m_exponent = 0; + m_data.m_namespace = 1; // 1 = Bluetooth SIG Assigned Numbers + m_data.m_unit = 0; + m_data.m_description = 0; + setValue((uint8_t*) &m_data, sizeof(m_data)); +} // BLE2902 + + +/** + * @brief Set the description. + */ +void BLE2904::setDescription(uint16_t description) { + m_data.m_description = description; + setValue((uint8_t*) &m_data, sizeof(m_data)); +} + + +/** + * @brief Set the exponent. + */ +void BLE2904::setExponent(int8_t exponent) { + m_data.m_exponent = exponent; + setValue((uint8_t*) &m_data, sizeof(m_data)); +} // setExponent + + +/** + * @brief Set the format. + */ +void BLE2904::setFormat(uint8_t format) { + m_data.m_format = format; + setValue((uint8_t*) &m_data, sizeof(m_data)); +} // setFormat + + +/** + * @brief Set the namespace. + */ +void BLE2904::setNamespace(uint8_t namespace_value) { + m_data.m_namespace = namespace_value; + setValue((uint8_t*) &m_data, sizeof(m_data)); +} // setNamespace + + +/** + * @brief Set the units for this value. It should be one of the encoded values defined here: + * https://www.bluetooth.com/specifications/assigned-numbers/units + * @param [in] unit The type of units of this characteristic as defined by assigned numbers. + */ +void BLE2904::setUnit(uint16_t unit) { + m_data.m_unit = unit; + setValue((uint8_t*) &m_data, sizeof(m_data)); +} // setUnit + +#endif +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2904.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2904.h new file mode 100644 index 0000000..c1b9e39 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLE2904.h @@ -0,0 +1,78 @@ +/* + * BLE2904.h + * + * Created on: Dec 23, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLE2904_H_ +#define COMPONENTS_CPP_UTILS_BLE2904_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLEDescriptor.h" + +struct BLE2904_Data { + uint8_t m_format; + int8_t m_exponent; + uint16_t m_unit; // See https://www.bluetooth.com/specifications/assigned-numbers/units + uint8_t m_namespace; + uint16_t m_description; + +} __attribute__((packed)); + +/** + * @brief Descriptor for Characteristic Presentation Format. + * + * This is a convenience descriptor for the Characteristic Presentation Format which has a UUID of 0x2904. + * + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml + */ +class BLE2904: public BLEDescriptor { +public: + BLE2904(); + static const uint8_t FORMAT_BOOLEAN = 1; + static const uint8_t FORMAT_UINT2 = 2; + static const uint8_t FORMAT_UINT4 = 3; + static const uint8_t FORMAT_UINT8 = 4; + static const uint8_t FORMAT_UINT12 = 5; + static const uint8_t FORMAT_UINT16 = 6; + static const uint8_t FORMAT_UINT24 = 7; + static const uint8_t FORMAT_UINT32 = 8; + static const uint8_t FORMAT_UINT48 = 9; + static const uint8_t FORMAT_UINT64 = 10; + static const uint8_t FORMAT_UINT128 = 11; + static const uint8_t FORMAT_SINT8 = 12; + static const uint8_t FORMAT_SINT12 = 13; + static const uint8_t FORMAT_SINT16 = 14; + static const uint8_t FORMAT_SINT24 = 15; + static const uint8_t FORMAT_SINT32 = 16; + static const uint8_t FORMAT_SINT48 = 17; + static const uint8_t FORMAT_SINT64 = 18; + static const uint8_t FORMAT_SINT128 = 19; + static const uint8_t FORMAT_FLOAT32 = 20; + static const uint8_t FORMAT_FLOAT64 = 21; + static const uint8_t FORMAT_SFLOAT16 = 22; + static const uint8_t FORMAT_SFLOAT32 = 23; + static const uint8_t FORMAT_IEEE20601 = 24; + static const uint8_t FORMAT_UTF8 = 25; + static const uint8_t FORMAT_UTF16 = 26; + static const uint8_t FORMAT_OPAQUE = 27; + + void setDescription(uint16_t); + void setExponent(int8_t exponent); + void setFormat(uint8_t format); + void setNamespace(uint8_t namespace_value); + void setUnit(uint16_t unit); + +private: + BLE2904_Data m_data; +}; // BLE2904 + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLE2904_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAddress.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAddress.cpp new file mode 100644 index 0000000..9bed351 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAddress.cpp @@ -0,0 +1,122 @@ +/* + * BLEAddress.cpp + * + * Created on: Jul 2, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLEAddress.h" +#include +#include +#include +#include +#include +#include +#ifdef ARDUINO_ARCH_ESP32 +#include "esp32-hal-log.h" +#endif + + +/** + * @brief Create an address from the native ESP32 representation. + * @param [in] address The native representation. + */ +BLEAddress::BLEAddress(esp_bd_addr_t address) { + memcpy(m_address, address, ESP_BD_ADDR_LEN); +} // BLEAddress + + +/** + * @brief Create an address from a hex string + * + * A hex string is of the format: + * ``` + * 00:00:00:00:00:00 + * ``` + * which is 17 characters in length. + * + * @param [in] stringAddress The hex representation of the address. + */ +BLEAddress::BLEAddress(String stringAddress) { + if (stringAddress.length() != 17) return; + + int data[6]; + sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); + m_address[0] = (uint8_t) data[0]; + m_address[1] = (uint8_t) data[1]; + m_address[2] = (uint8_t) data[2]; + m_address[3] = (uint8_t) data[3]; + m_address[4] = (uint8_t) data[4]; + m_address[5] = (uint8_t) data[5]; +} // BLEAddress + + +/** + * @brief Determine if this address equals another. + * @param [in] otherAddress The other address to compare against. + * @return True if the addresses are equal. + */ +bool BLEAddress::equals(BLEAddress otherAddress) { + return memcmp(otherAddress.getNative(), m_address, ESP_BD_ADDR_LEN) == 0; +} // equals + +bool BLEAddress::operator==(const BLEAddress& otherAddress) const { + return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) == 0; +} + +bool BLEAddress::operator!=(const BLEAddress& otherAddress) const { + return !(*this == otherAddress); +} + +bool BLEAddress::operator<(const BLEAddress& otherAddress) const { + return memcmp(m_address, otherAddress.m_address, ESP_BD_ADDR_LEN) < 0; +} + +bool BLEAddress::operator<=(const BLEAddress& otherAddress) const { + return !(*this > otherAddress); +} + +bool BLEAddress::operator>=(const BLEAddress& otherAddress) const { + return !(*this < otherAddress); +} + +bool BLEAddress::operator>(const BLEAddress& otherAddress) const { + return memcmp(m_address, otherAddress.m_address, ESP_BD_ADDR_LEN) > 0; +} + +/** + * @brief Return the native representation of the address. + * @return The native representation of the address. + */ +esp_bd_addr_t *BLEAddress::getNative() { + return &m_address; +} // getNative + + +/** + * @brief Convert a BLE address to a string. + * + * A string representation of an address is in the format: + * + * ``` + * xx:xx:xx:xx:xx:xx + * ``` + * + * @return The string representation of the address. + */ +String BLEAddress::toString() { + auto size = 18; + char *res = (char*)malloc(size); + snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]); + String ret(res); + free(res); + return ret; +} // toString + +#endif +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAddress.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAddress.h new file mode 100644 index 0000000..cca2c6c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAddress.h @@ -0,0 +1,45 @@ +/* + * BLEAddress.h + * + * Created on: Jul 2, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEADDRESS_H_ +#define COMPONENTS_CPP_UTILS_BLEADDRESS_H_ +#include "soc/soc_caps.h" +#include "WString.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include // ESP32 BLE +#include + + +/** + * @brief A %BLE device address. + * + * Every %BLE device has a unique address which can be used to identify it and form connections. + */ +class BLEAddress { +public: + BLEAddress(esp_bd_addr_t address); + BLEAddress(String stringAddress); + bool equals(BLEAddress otherAddress); + bool operator==(const BLEAddress& otherAddress) const; + bool operator!=(const BLEAddress& otherAddress) const; + bool operator<(const BLEAddress& otherAddress) const; + bool operator<=(const BLEAddress& otherAddress) const; + bool operator>(const BLEAddress& otherAddress) const; + bool operator>=(const BLEAddress& otherAddress) const; + esp_bd_addr_t* getNative(); + String toString(); + +private: + esp_bd_addr_t m_address; +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEADDRESS_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertisedDevice.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertisedDevice.cpp new file mode 100644 index 0000000..987d5c1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertisedDevice.cpp @@ -0,0 +1,612 @@ +/* + * BLEAdvertisedDevice.cpp + * + * During the scanning procedure, we will be finding advertised BLE devices. This class + * models a found device. + * + * + * See also: + * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile + * + * Created on: Jul 3, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include "BLEAdvertisedDevice.h" +#include "BLEUtils.h" +#include "esp32-hal-log.h" + +BLEAdvertisedDevice::BLEAdvertisedDevice() { + m_adFlag = 0; + m_appearance = 0; + m_deviceType = 0; + m_manufacturerData = ""; + m_name = ""; + m_rssi = -9999; + m_serviceUUIDs = {}; + m_serviceData = {}; + m_serviceDataUUIDs = {}; + m_txPower = 0; + m_pScan = nullptr; + + m_haveAppearance = false; + m_haveManufacturerData = false; + m_haveName = false; + m_haveRSSI = false; + m_haveTXPower = false; + +} // BLEAdvertisedDevice + + +/** + * @brief Get the address. + * + * Every %BLE device exposes an address that is used to identify it and subsequently connect to it. + * Call this function to obtain the address of the advertised device. + * + * @return The address of the advertised device. + */ +BLEAddress BLEAdvertisedDevice::getAddress() { + return m_address; +} // getAddress + + +/** + * @brief Get the appearance. + * + * A %BLE device can declare its own appearance. The appearance is how it would like to be shown to an end user + * typcially in the form of an icon. + * + * @return The appearance of the advertised device. + */ +uint16_t BLEAdvertisedDevice::getAppearance() { + return m_appearance; +} // getAppearance + + +/** + * @brief Get the manufacturer data. + * @return The manufacturer data of the advertised device. + */ +String BLEAdvertisedDevice::getManufacturerData() { + return m_manufacturerData; +} // getManufacturerData + + +/** + * @brief Get the name. + * @return The name of the advertised device. + */ +String BLEAdvertisedDevice::getName() { + return m_name; +} // getName + + +/** + * @brief Get the RSSI. + * @return The RSSI of the advertised device. + */ +int BLEAdvertisedDevice::getRSSI() { + return m_rssi; +} // getRSSI + + +/** + * @brief Get the scan object that created this advertisement. + * @return The scan object. + */ +BLEScan* BLEAdvertisedDevice::getScan() { + return m_pScan; +} // getScan + +/** + * @brief Get the number of service data. + * @return Number of service data discovered. + */ +int BLEAdvertisedDevice::getServiceDataCount() { + return m_serviceData.size(); +} //getServiceDataCount + +/** + * @brief Get the service data. + * @return The ServiceData of the advertised device. + */ +String BLEAdvertisedDevice::getServiceData() { + return m_serviceData.empty() ? String() : m_serviceData.front(); +} //getServiceData + +/** + * @brief Get the service data. + * @return The ServiceData of the advertised device. + */ +String BLEAdvertisedDevice::getServiceData(int i) { + return m_serviceData[i]; +} //getServiceData + +/** + * @brief Get the number of service data UUIDs. + * @return Number of service data UUIDs discovered. + */ +int BLEAdvertisedDevice::getServiceDataUUIDCount() { + return m_serviceDataUUIDs.size(); +} //getServiceDataUUIDCount + +/** + * @brief Get the service data UUID. + * @return The service data UUID. + */ +BLEUUID BLEAdvertisedDevice::getServiceDataUUID() { + return m_serviceDataUUIDs.empty() ? BLEUUID() : m_serviceDataUUIDs.front(); +} // getServiceDataUUID + +/** + * @brief Get the service data UUID. + * @return The service data UUID. + */ +BLEUUID BLEAdvertisedDevice::getServiceDataUUID(int i) { + return m_serviceDataUUIDs[i]; +} // getServiceDataUUID + +/** + * @brief Get the number of service UUIDs. + * @return Number of service UUIDs discovered. + */ +int BLEAdvertisedDevice::getServiceUUIDCount() { + return m_serviceUUIDs.size(); +} //getServiceUUIDCount + +/** + * @brief Get the Service UUID. + * @return The Service UUID of the advertised device. + */ +BLEUUID BLEAdvertisedDevice::getServiceUUID() { + return m_serviceUUIDs.empty() ? BLEUUID() : m_serviceUUIDs.front(); +} // getServiceUUID + +/** + * @brief Get the Service UUID. + * @return The Service UUID of the advertised device. + */ +BLEUUID BLEAdvertisedDevice::getServiceUUID(int i) { + return m_serviceUUIDs[i]; +} // getServiceUUID + +/** + * @brief Check advertised serviced for existence required UUID + * @return Return true if service is advertised + */ +bool BLEAdvertisedDevice::isAdvertisingService(BLEUUID uuid){ + for (int i = 0; i < getServiceUUIDCount(); i++) { + if (m_serviceUUIDs[i].equals(uuid)) return true; + } + return false; +} + +/** + * @brief Get the TX Power. + * @return The TX Power of the advertised device. + */ +int8_t BLEAdvertisedDevice::getTXPower() { + return m_txPower; +} // getTXPower + + + +/** + * @brief Does this advertisement have an appearance value? + * @return True if there is an appearance value present. + */ +bool BLEAdvertisedDevice::haveAppearance() { + return m_haveAppearance; +} // haveAppearance + + +/** + * @brief Does this advertisement have manufacturer data? + * @return True if there is manufacturer data present. + */ +bool BLEAdvertisedDevice::haveManufacturerData() { + return m_haveManufacturerData; +} // haveManufacturerData + + +/** + * @brief Does this advertisement have a name value? + * @return True if there is a name value present. + */ +bool BLEAdvertisedDevice::haveName() { + return m_haveName; +} // haveName + + +/** + * @brief Does this advertisement have a signal strength value? + * @return True if there is a signal strength value present. + */ +bool BLEAdvertisedDevice::haveRSSI() { + return m_haveRSSI; +} // haveRSSI + + +/** + * @brief Does this advertisement have a service data value? + * @return True if there is a service data value present. + */ +bool BLEAdvertisedDevice::haveServiceData() { + return !m_serviceData.empty(); +} // haveServiceData + + +/** + * @brief Does this advertisement have a service UUID value? + * @return True if there is a service UUID value present. + */ +bool BLEAdvertisedDevice::haveServiceUUID() { + return !m_serviceUUIDs.empty(); +} // haveServiceUUID + + +/** + * @brief Does this advertisement have a transmission power value? + * @return True if there is a transmission power value present. + */ +bool BLEAdvertisedDevice::haveTXPower() { + return m_haveTXPower; +} // haveTXPower + + +/** + * @brief Parse the advertising pay load. + * + * The pay load is a buffer of bytes that is either 31 bytes long or terminated by + * a 0 length value. Each entry in the buffer has the format: + * [length][type][data...] + * + * The length does not include itself but does include everything after it until the next record. A record + * with a length value of 0 indicates a terminator. + * + * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile + */ +void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len) { + uint8_t length; + uint8_t ad_type; + uint8_t sizeConsumed = 0; + bool finished = false; + m_payload = payload; + m_payloadLength = total_len; + + while(!finished) { + length = *payload; // Retrieve the length of the record. + payload++; // Skip to type + sizeConsumed += 1 + length; // increase the size consumed. + + if (length != 0) { // A length of 0 indicates that we have reached the end. + ad_type = *payload; + payload++; + length--; + + char* pHex = BLEUtils::buildHexData(nullptr, payload, length); + log_d("Type: 0x%.2x (%s), length: %d, data: %s", + ad_type, BLEUtils::advTypeToString(ad_type), length, pHex); + free(pHex); + + switch(ad_type) { + case ESP_BLE_AD_TYPE_NAME_CMPL: { // Adv Data Type: 0x09 + setName(String(reinterpret_cast(payload), length)); + break; + } // ESP_BLE_AD_TYPE_NAME_CMPL + + case ESP_BLE_AD_TYPE_TX_PWR: { // Adv Data Type: 0x0A + setTXPower(*payload); + break; + } // ESP_BLE_AD_TYPE_TX_PWR + + case ESP_BLE_AD_TYPE_APPEARANCE: { // Adv Data Type: 0x19 + setAppearance(*reinterpret_cast(payload)); + break; + } // ESP_BLE_AD_TYPE_APPEARANCE + + case ESP_BLE_AD_TYPE_FLAG: { // Adv Data Type: 0x01 + setAdFlag(*payload); + break; + } // ESP_BLE_AD_TYPE_FLAG + + 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))); + } + break; + } // ESP_BLE_AD_TYPE_16SRV_PART + + 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))); + } + break; + } // ESP_BLE_AD_TYPE_32SRV_PART + + case ESP_BLE_AD_TYPE_128SRV_CMPL: { // Adv Data Type: 0x07 + setServiceUUID(BLEUUID(payload, 16, false)); + break; + } // ESP_BLE_AD_TYPE_128SRV_CMPL + + case ESP_BLE_AD_TYPE_128SRV_PART: { // Adv Data Type: 0x06 + setServiceUUID(BLEUUID(payload, 16, false)); + break; + } // ESP_BLE_AD_TYPE_128SRV_PART + + // See CSS Part A 1.4 Manufacturer Specific Data + case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: { + setManufacturerData(String(reinterpret_cast(payload), length)); + break; + } // ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE + + case ESP_BLE_AD_TYPE_SERVICE_DATA: { // Adv Data Type: 0x16 (Service Data) - 2 byte UUID + if (length < 2) { + log_e("Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA"); + break; + } + uint16_t uuid = *(uint16_t*)payload; + setServiceDataUUID(BLEUUID(uuid)); + if (length > 2) { + setServiceData(String(reinterpret_cast(payload + 2), length - 2)); + } + break; + } //ESP_BLE_AD_TYPE_SERVICE_DATA + + case ESP_BLE_AD_TYPE_32SERVICE_DATA: { // Adv Data Type: 0x20 (Service Data) - 4 byte UUID + if (length < 4) { + log_e("Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA"); + break; + } + uint32_t uuid = *(uint32_t*) payload; + setServiceDataUUID(BLEUUID(uuid)); + if (length > 4) { + setServiceData(String(reinterpret_cast(payload + 4), length - 4)); + } + break; + } //ESP_BLE_AD_TYPE_32SERVICE_DATA + + case ESP_BLE_AD_TYPE_128SERVICE_DATA: { // Adv Data Type: 0x21 (Service Data) - 16 byte UUID + if (length < 16) { + log_e("Length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA"); + break; + } + + setServiceDataUUID(BLEUUID(payload, (size_t)16, false)); + if (length > 16) { + setServiceData(String(reinterpret_cast(payload + 16), length - 16)); + } + break; + } //ESP_BLE_AD_TYPE_32SERVICE_DATA + + default: { + log_d("Unhandled type: adType: %d - 0x%.2x", ad_type, ad_type); + break; + } + } // switch + payload += length; + } // Length <> 0 + + + if (sizeConsumed >= total_len) + finished = true; + + } // !finished +} // parseAdvertisement + +/** + * @brief Parse the advertising payload. + * @param [in] payload The payload of the advertised device. + * @param [in] total_len The length of payload + */ +void BLEAdvertisedDevice::setPayload(uint8_t* payload, size_t total_len) { + m_payload = payload; + m_payloadLength = total_len; +} // setPayload + +/** + * @brief Set the address of the advertised device. + * @param [in] address The address of the advertised device. + */ +void BLEAdvertisedDevice::setAddress(BLEAddress address) { + m_address = address; +} // setAddress + + +/** + * @brief Set the adFlag for this device. + * @param [in] The discovered adFlag. + */ +void BLEAdvertisedDevice::setAdFlag(uint8_t adFlag) { + m_adFlag = adFlag; +} // setAdFlag + + +/** + * @brief Set the appearance for this device. + * @param [in] The discovered appearance. + */ +void BLEAdvertisedDevice::setAppearance(uint16_t appearance) { + m_appearance = appearance; + m_haveAppearance = true; + log_d("- appearance: %d", m_appearance); +} // setAppearance + + +/** + * @brief Set the manufacturer data for this device. + * @param [in] The discovered manufacturer data. + */ +void BLEAdvertisedDevice::setManufacturerData(String manufacturerData) { + m_manufacturerData = manufacturerData; + m_haveManufacturerData = true; + char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*) m_manufacturerData.c_str(), (uint8_t) m_manufacturerData.length()); + log_d("- manufacturer data: %s", pHex); + free(pHex); +} // setManufacturerData + + +/** + * @brief Set the name for this device. + * @param [in] name The discovered name. + */ +void BLEAdvertisedDevice::setName(String name) { + m_name = name; + m_haveName = true; + log_d("- setName(): name: %s", m_name.c_str()); +} // setName + + +/** + * @brief Set the RSSI for this device. + * @param [in] rssi The discovered RSSI. + */ +void BLEAdvertisedDevice::setRSSI(int rssi) { + m_rssi = rssi; + m_haveRSSI = true; + log_d("- setRSSI(): rssi: %d", m_rssi); +} // setRSSI + + +/** + * @brief Set the Scan that created this advertised device. + * @param pScan The Scan that created this advertised device. + */ +void BLEAdvertisedDevice::setScan(BLEScan* pScan) { + m_pScan = pScan; +} // setScan + + +/** + * @brief Set the Service UUID for this device. + * @param [in] serviceUUID The discovered serviceUUID + */ +void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) { + return setServiceUUID(BLEUUID(serviceUUID)); +} // setServiceUUID + + +/** + * @brief Set the Service UUID for this device. + * @param [in] serviceUUID The discovered serviceUUID + */ +void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) { + m_serviceUUIDs.push_back(serviceUUID); + log_d("- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str()); +} // setServiceUUID + + +/** + * @brief Set the ServiceData value. + * @param [in] data ServiceData value. + */ +void BLEAdvertisedDevice::setServiceData(String serviceData) { + m_serviceData.push_back(serviceData); // Save the service data that we received. +} //setServiceData + + +/** + * @brief Set the ServiceDataUUID value. + * @param [in] data ServiceDataUUID value. + */ +void BLEAdvertisedDevice::setServiceDataUUID(BLEUUID uuid) { + m_serviceDataUUIDs.push_back(uuid); + log_d("- addServiceDataUUID(): serviceDataUUID: %s", uuid.toString().c_str()); +} // setServiceDataUUID + + +/** + * @brief Set the power level for this device. + * @param [in] txPower The discovered power level. + */ +void BLEAdvertisedDevice::setTXPower(int8_t txPower) { + m_txPower = txPower; + m_haveTXPower = true; + log_d("- txPower: %d", m_txPower); +} // setTXPower + + +/** + * @brief Create a string representation of this device. + * @return A string representation of this device. + */ +String BLEAdvertisedDevice::toString() { + String res = "Name: " + getName() + ", Address: " + getAddress().toString(); + if (haveAppearance()) { + char val[6]; + snprintf(val, sizeof(val), "%d", getAppearance()); + res += ", appearance: "; + res += val; + } + if (haveManufacturerData()) { + char *pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().c_str(), getManufacturerData().length()); + res += ", manufacturer data: "; + res += pHex; + free(pHex); + } + if (haveServiceUUID()) { + for (int i=0; i < getServiceUUIDCount(); i++) { + res += ", serviceUUID: " + getServiceUUID(i).toString(); + } + } + if (haveTXPower()) { + char val[6]; + snprintf(val, sizeof(val), "%d", getTXPower()); + res += ", txPower: "; + res += val; + } + if (haveRSSI()) { + char val[4]; + snprintf(val, sizeof(val), "%i", getRSSI()); + res += ", rssi: "; + res += val; + } + if (haveServiceData()) { + for (int i=0; i = i+3 && m_payload[i+1] == 0xAA && m_payload[i+2] == 0xFE && m_payload[i+3] == 0x00){ + return BLE_EDDYSTONE_UUID_FRAME; + } + if(m_payload[i] == 0x16 && m_payloadLength >= i+3 && m_payload[i+1] == 0xAA && m_payload[i+2] == 0xFE && m_payload[i+3] == 0x10){ + return BLE_EDDYSTONE_URL_FRAME; + } + if(m_payload[i] == 0x16 && m_payloadLength >= i+3 && m_payload[i+1] == 0xAA && m_payload[i+2] == 0xFE && m_payload[i+3] == 0x20){ + return BLE_EDDYSTONE_TLM_FRAME; + } + } + return BLE_UNKNOWN_FRAME; +} + +void BLEAdvertisedDevice::setAddressType(esp_ble_addr_type_t type) { + m_addressType = type; +} + +size_t BLEAdvertisedDevice::getPayloadLength() { + return m_payloadLength; +} + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertisedDevice.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertisedDevice.h new file mode 100644 index 0000000..e449a0c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertisedDevice.h @@ -0,0 +1,155 @@ +/* + * BLEAdvertisedDevice.h + * + * Created on: Jul 3, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ +#define COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include + +#include + +#include "BLEAddress.h" +#include "BLEScan.h" +#include "BLEUUID.h" + +typedef enum { + BLE_UNKNOWN_FRAME, + BLE_EDDYSTONE_UUID_FRAME, + BLE_EDDYSTONE_URL_FRAME, + BLE_EDDYSTONE_TLM_FRAME, + BLE_FRAME_MAX +} ble_frame_type_t; + +class BLEScan; +/** + * @brief A representation of a %BLE advertised device found by a scan. + * + * When we perform a %BLE scan, the result will be a set of devices that are advertising. This + * class provides a model of a detected device. + */ +class BLEAdvertisedDevice { +public: + BLEAdvertisedDevice(); + + BLEAddress getAddress(); + uint16_t getAppearance(); + String getManufacturerData(); + String getName(); + int getRSSI(); + BLEScan* getScan(); + String getServiceData(); + String getServiceData(int i); + BLEUUID getServiceDataUUID(); + BLEUUID getServiceDataUUID(int i); + BLEUUID getServiceUUID(); + BLEUUID getServiceUUID(int i); + int getServiceDataCount(); + int getServiceDataUUIDCount(); + int getServiceUUIDCount(); + int8_t getTXPower(); + uint8_t* getPayload(); + size_t getPayloadLength(); + esp_ble_addr_type_t getAddressType(); + ble_frame_type_t getFrameType(); + void setAddressType(esp_ble_addr_type_t type); + + + bool isAdvertisingService(BLEUUID uuid); + bool haveAppearance(); + bool haveManufacturerData(); + bool haveName(); + bool haveRSSI(); + bool haveServiceData(); + bool haveServiceUUID(); + bool haveTXPower(); + + String toString(); + +private: + friend class BLEScan; + + void parseAdvertisement(uint8_t* payload, size_t total_len=62); + void setPayload(uint8_t* payload, size_t total_len=62); + void setAddress(BLEAddress address); + void setAdFlag(uint8_t adFlag); + void setAdvertizementResult(uint8_t* payload); + void setAppearance(uint16_t appearance); + void setManufacturerData(String manufacturerData); + void setName(String name); + void setRSSI(int rssi); + void setScan(BLEScan* pScan); + void setServiceData(String data); + void setServiceDataUUID(BLEUUID uuid); + void setServiceUUID(const char* serviceUUID); + void setServiceUUID(BLEUUID serviceUUID); + void setTXPower(int8_t txPower); + + bool m_haveAppearance; + bool m_haveManufacturerData; + bool m_haveName; + bool m_haveRSSI; + bool m_haveTXPower; + + + BLEAddress m_address = BLEAddress((uint8_t*)"\0\0\0\0\0\0"); + uint8_t m_adFlag; + uint16_t m_appearance; + int m_deviceType; + String m_manufacturerData; + String m_name; + BLEScan* m_pScan; + int m_rssi; + std::vector m_serviceUUIDs; + int8_t m_txPower; + std::vector m_serviceData; + std::vector m_serviceDataUUIDs; + uint8_t* m_payload; + size_t m_payloadLength = 0; + esp_ble_addr_type_t m_addressType; +}; + +/** + * @brief A callback handler for callbacks associated device scanning. + * + * When we are performing a scan as a %BLE client, we may wish to know when a new device that is advertising + * has been found. This class can be sub-classed and registered such that when a scan is performed and + * a new advertised device has been found, we will be called back to be notified. + */ +class BLEAdvertisedDeviceCallbacks { +public: + virtual ~BLEAdvertisedDeviceCallbacks() {} + /** + * @brief Called when a new scan result is detected. + * + * 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; +}; + +#ifdef SOC_BLE_50_SUPPORTED +class BLEExtAdvertisingCallbacks { +public: + virtual ~BLEExtAdvertisingCallbacks() {} + /** + * @brief Called when a new scan result is detected. + * + * 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(esp_ble_gap_ext_adv_reprot_t report) = 0; +}; +#endif // SOC_BLE_50_SUPPORTED + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISEDDEVICE_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertising.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertising.cpp new file mode 100644 index 0000000..0c105cf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertising.cpp @@ -0,0 +1,772 @@ +/* + * BLEAdvertising.cpp + * + * This class encapsulates advertising a BLE Server. + * Created on: Jun 21, 2017 + * Author: kolban + * + * The ESP-IDF provides a framework for BLE advertising. It has determined that there are a common set + * of properties that are advertised and has built a data structure that can be populated by the programmer. + * This means that the programmer doesn't have to "mess with" the low level construction of a low level + * BLE advertising frame. Many of the fields are determined for us while others we can set before starting + * to advertise. + * + * Should we wish to construct our own payload, we can use the BLEAdvertisementData class and call the setters + * upon it. Once it is populated, we can then associate it with the advertising and what ever the programmer + * set in the data will be advertised. + * + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include "BLEAdvertising.h" +#include +#include "BLEUtils.h" +#include "GeneralUtils.h" +#include "esp32-hal-log.h" + +/** + * @brief Construct a default advertising object. + * + */ +BLEAdvertising::BLEAdvertising() +: m_scanRespData{} +{ + m_advData.set_scan_rsp = false; + m_advData.include_name = true; + m_advData.include_txpower = true; + m_advData.min_interval = 0x20; + m_advData.max_interval = 0x40; + m_advData.appearance = 0x00; + m_advData.manufacturer_len = 0; + m_advData.p_manufacturer_data = nullptr; + m_advData.service_data_len = 0; + m_advData.p_service_data = nullptr; + m_advData.service_uuid_len = 0; + m_advData.p_service_uuid = nullptr; + m_advData.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT); + + m_advParams.adv_int_min = 0x20; + m_advParams.adv_int_max = 0x40; + m_advParams.adv_type = ADV_TYPE_IND; + 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 +} // BLEAdvertising + + +/** + * @brief Add a service uuid to exposed list of services. + * @param [in] serviceUUID The UUID of the service to expose. + */ +void BLEAdvertising::addServiceUUID(BLEUUID serviceUUID) { + m_serviceUUIDs.push_back(serviceUUID); +} // addServiceUUID + + +/** + * @brief Add a service uuid to exposed list of services. + * @param [in] serviceUUID The string representation of the service to expose. + */ +void BLEAdvertising::addServiceUUID(const char* serviceUUID) { + addServiceUUID(BLEUUID(serviceUUID)); +} // addServiceUUID + + +/** + * @brief Set the device appearance in the advertising data. + * The appearance attribute is of type 0x19. The codes for distinct appearances can be found here: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml. + * @param [in] appearance The appearance of the device in the advertising data. + * @return N/A. + */ +void BLEAdvertising::setAppearance(uint16_t appearance) { + m_advData.appearance = appearance; +} // setAppearance + +void BLEAdvertising::setAdvertisementType(esp_ble_adv_type_t adv_type){ + m_advParams.adv_type = adv_type; +} // setAdvertisementType + +void BLEAdvertising::setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map) { + m_advParams.channel_map = channel_map; +} // setAdvertisementChannelMap + +void BLEAdvertising::setMinInterval(uint16_t mininterval) { + m_advParams.adv_int_min = mininterval; +} // setMinInterval + +void BLEAdvertising::setMaxInterval(uint16_t 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) { + log_v(">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly); + if (!scanRequestWhitelistOnly && !connectWhitelistOnly) { + m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY; + log_v("<< setScanFilter"); + return; + } + if (scanRequestWhitelistOnly && !connectWhitelistOnly) { + m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY; + log_v("<< setScanFilter"); + return; + } + if (!scanRequestWhitelistOnly && connectWhitelistOnly) { + m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST; + log_v("<< setScanFilter"); + return; + } + if (scanRequestWhitelistOnly && connectWhitelistOnly) { + m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST; + log_v("<< setScanFilter"); + return; + } +} // setScanFilter + + +/** + * @brief Set the advertisement data that is to be published in a regular advertisement. + * @param [in] advertisementData The data to be advertised. + */ +void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) { + log_v(">> setAdvertisementData"); + esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw( + (uint8_t*)advertisementData.getPayload().c_str(), + advertisementData.getPayload().length()); + if (errRc != ESP_OK) { + log_e("esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc)); + } + m_customAdvData = true; // Set the flag that indicates we are using custom advertising data. + log_v("<< setAdvertisementData"); +} // setAdvertisementData + + +/** + * @brief Set the advertisement data that is to be published in a scan response. + * @param [in] advertisementData The data to be advertised. + */ +void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) { + log_v(">> setScanResponseData"); + esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw( + (uint8_t*)advertisementData.getPayload().c_str(), + advertisementData.getPayload().length()); + if (errRc != ESP_OK) { + log_e("esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc)); + } + m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data. + log_v("<< setScanResponseData"); +} // setScanResponseData + +/** + * @brief Start advertising. + * Start advertising. + * @return N/A. + */ +void BLEAdvertising::start() { + log_v(">> 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]; + uint8_t* p = m_advData.p_service_uuid; + for (int i = 0; i < numServices; i++) { + log_d("- advertising service: %s", m_serviceUUIDs[i].toString().c_str()); + BLEUUID serviceUUID128 = m_serviceUUIDs[i].to128(); + memcpy(p, serviceUUID128.getNative()->uuid.uuid128, 16); + p += 16; + } + } else { + m_advData.service_uuid_len = 0; + log_d("- no services advertised"); + } + + esp_err_t errRc; + + 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) { + log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + } + + if (!m_customScanResponseData && m_scanResp) { + // Set the configuration for scan response. + memcpy(&m_scanRespData, &m_advData, sizeof(esp_ble_adv_data_t)); // Copy the content of m_advData. + m_scanRespData.set_scan_rsp = true; // Define this struct as scan response data + m_scanRespData.include_name = true; // Caution: This may lead to a crash if the device name has more than 29 characters + m_scanRespData.include_txpower = true; + m_scanRespData.appearance = 0; // If defined the 'Appearance' attribute is already included in the advertising data + m_scanRespData.flag = 0; // 'Flags' attribute should no be included in the scan response + + errRc = ::esp_ble_gap_config_adv_data(&m_scanRespData); + if (errRc != ESP_OK) { + log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + } + + // If we had services to advertise then we previously allocated some storage for them. + // Here we release that storage. + if (m_advData.service_uuid_len > 0) { + delete[] m_advData.p_service_uuid; + m_advData.p_service_uuid = nullptr; + } + + // Start advertising. + errRc = ::esp_ble_gap_start_advertising(&m_advParams); + if (errRc != ESP_OK) { + log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + log_v("<< start"); +} // start + + +/** + * @brief Stop advertising. + * Stop advertising. + * @return N/A. + */ +void BLEAdvertising::stop() { + log_v(">> stop"); + esp_err_t errRc = ::esp_ble_gap_stop_advertising(); + if (errRc != ESP_OK) { + log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + log_v("<< stop"); +} // stop + +/** + * @brief Set BLE address. + * @param [in] Bluetooth address. + * @param [in] Bluetooth address type. + * Set BLE address. + */ + +void BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type) +{ + log_v(">> setPrivateAddress"); + + m_advParams.own_addr_type = type; + esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t*)addr); + if (errRc != ESP_OK) + { + log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + log_v("<< setPrivateAddress"); +} // setPrivateAddress + +/** + * @brief Add data to the payload to be advertised. + * @param [in] data The data to be added to the payload. + */ +void BLEAdvertisementData::addData(String data) { + if ((m_payload.length() + data.length()) > ESP_BLE_ADV_DATA_LEN_MAX) { + return; + } + m_payload.concat(data); +} // addData + + +/** + * @brief Set the appearance. + * @param [in] appearance The appearance code value. + * + * See also: + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.gap.appearance.xml + */ +void BLEAdvertisementData::setAppearance(uint16_t appearance) { + char cdata[2]; + cdata[0] = 3; + cdata[1] = ESP_BLE_AD_TYPE_APPEARANCE; // 0x19 + addData(String(cdata, 2) + String((char*) &appearance, 2)); +} // setAppearance + + +/** + * @brief Set the complete services. + * @param [in] uuid The single service to advertise. + */ +void BLEAdvertisementData::setCompleteServices(BLEUUID uuid) { + char cdata[2]; + switch (uuid.bitSize()) { + case 16: { + // [Len] [0x02] [LL] [HH] + cdata[0] = 3; + cdata[1] = ESP_BLE_AD_TYPE_16SRV_CMPL; // 0x03 + addData(String(cdata, 2) + String((char*) &uuid.getNative()->uuid.uuid16, 2)); + break; + } + + case 32: { + // [Len] [0x04] [LL] [LL] [HH] [HH] + cdata[0] = 5; + cdata[1] = ESP_BLE_AD_TYPE_32SRV_CMPL; // 0x05 + addData(String(cdata, 2) + String((char*) &uuid.getNative()->uuid.uuid32, 4)); + break; + } + + case 128: { + // [Len] [0x04] [0] [1] ... [15] + cdata[0] = 17; + cdata[1] = ESP_BLE_AD_TYPE_128SRV_CMPL; // 0x07 + addData(String(cdata, 2) + String((char*) uuid.getNative()->uuid.uuid128, 16)); + break; + } + + default: + return; + } +} // setCompleteServices + + +/** + * @brief Set the advertisement flags. + * @param [in] The flags to be set in the advertisement. + * + * * ESP_BLE_ADV_FLAG_LIMIT_DISC + * * ESP_BLE_ADV_FLAG_GEN_DISC + * * ESP_BLE_ADV_FLAG_BREDR_NOT_SPT + * * ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT + * * ESP_BLE_ADV_FLAG_DMT_HOST_SPT + * * ESP_BLE_ADV_FLAG_NON_LIMIT_DISC + */ +void BLEAdvertisementData::setFlags(uint8_t flag) { + char cdata[3]; + cdata[0] = 2; + cdata[1] = ESP_BLE_AD_TYPE_FLAG; // 0x01 + cdata[2] = flag; + addData(String(cdata, 3)); +} // setFlag + + + +/** + * @brief Set manufacturer specific data. + * @param [in] data Manufacturer data. + */ +void BLEAdvertisementData::setManufacturerData(String data) { + log_d("BLEAdvertisementData", ">> setManufacturerData"); + char cdata[2]; + cdata[0] = data.length() + 1; + cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff + addData(String(cdata, 2) + data); + log_d("BLEAdvertisementData", "<< setManufacturerData"); +} // setManufacturerData + + +/** + * @brief Set the name. + * @param [in] The complete name of the device. + */ +void BLEAdvertisementData::setName(String name) { + log_d("BLEAdvertisementData", ">> setName: %s", name.c_str()); + char cdata[2]; + cdata[0] = name.length() + 1; + cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09 + addData(String(cdata, 2) + name); + log_d("BLEAdvertisementData", "<< setName"); +} // setName + + +/** + * @brief Set the partial services. + * @param [in] uuid The single service to advertise. + */ +void BLEAdvertisementData::setPartialServices(BLEUUID uuid) { + char cdata[2]; + switch (uuid.bitSize()) { + case 16: { + // [Len] [0x02] [LL] [HH] + cdata[0] = 3; + cdata[1] = ESP_BLE_AD_TYPE_16SRV_PART; // 0x02 + addData(String(cdata, 2) + String((char *) &uuid.getNative()->uuid.uuid16, 2)); + break; + } + + case 32: { + // [Len] [0x04] [LL] [LL] [HH] [HH] + cdata[0] = 5; + cdata[1] = ESP_BLE_AD_TYPE_32SRV_PART; // 0x04 + addData(String(cdata, 2) + String((char *) &uuid.getNative()->uuid.uuid32, 4)); + break; + } + + case 128: { + // [Len] [0x04] [0] [1] ... [15] + cdata[0] = 17; + cdata[1] = ESP_BLE_AD_TYPE_128SRV_PART; // 0x06 + addData(String(cdata, 2) + String((char *) &uuid.getNative()->uuid.uuid128, 16)); + break; + } + + default: + return; + } +} // setPartialServices + + +/** + * @brief Set the service data (UUID + data) + * @param [in] uuid The UUID to set with the service data. Size of UUID will be used. + * @param [in] data The data to be associated with the service data advert. + */ +void BLEAdvertisementData::setServiceData(BLEUUID uuid, String data) { + char cdata[2]; + switch (uuid.bitSize()) { + case 16: { + // [Len] [0x16] [UUID16] data + cdata[0] = data.length() + 3; + cdata[1] = ESP_BLE_AD_TYPE_SERVICE_DATA; // 0x16 + addData(String(cdata, 2) + String((char*) &uuid.getNative()->uuid.uuid16, 2) + data); + break; + } + + case 32: { + // [Len] [0x20] [UUID32] data + cdata[0] = data.length() + 5; + cdata[1] = ESP_BLE_AD_TYPE_32SERVICE_DATA; // 0x20 + addData(String(cdata, 2) + String((char*) &uuid.getNative()->uuid.uuid32, 4) + data); + break; + } + + case 128: { + // [Len] [0x21] [UUID128] data + cdata[0] = data.length() + 17; + cdata[1] = ESP_BLE_AD_TYPE_128SERVICE_DATA; // 0x21 + addData(String(cdata, 2) + String((char*) &uuid.getNative()->uuid.uuid128, 16) + data); + break; + } + + default: + return; + } +} // setServiceData + + +/** + * @brief Set the short name. + * @param [in] The short name of the device. + */ +void BLEAdvertisementData::setShortName(String name) { + log_d("BLEAdvertisementData", ">> setShortName: %s", name.c_str()); + char cdata[2]; + cdata[0] = name.length() + 1; + cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08 + addData(String(cdata, 2) + name); + log_d("BLEAdvertisementData", "<< setShortName"); +} // setShortName + + +/** + * @brief Retrieve the payload that is to be advertised. + * @return The payload that is to be advertised. + */ +String BLEAdvertisementData::getPayload() { + return m_payload; +} // getPayload + +void BLEAdvertising::handleGAPEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param) { + + log_d("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: { + log_i("STOP advertising"); + //start(); + break; + } + default: + break; + } +} + +#ifdef SOC_BLE_50_SUPPORTED + +/** +* @brief Creator +* +* @param[in] instance : number of multi advertising instances +* +* +*/ +BLEMultiAdvertising::BLEMultiAdvertising(uint8_t num) +{ + params_arrays = (esp_ble_gap_ext_adv_params_t*)calloc(num, sizeof(esp_ble_gap_ext_adv_params_t)); + ext_adv = (esp_ble_gap_ext_adv_t*)calloc(num, sizeof(esp_ble_gap_ext_adv_t)); + count = num; +} + +/** +* @brief This function is used by the Host to set the advertising parameters. +* +* @param[in] instance : identifies the advertising set whose parameters are being configured. +* @param[in] params : advertising parameters +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setAdvertisingParams(uint8_t instance, const esp_ble_gap_ext_adv_params_t* params) +{ + if (params->type == ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY_IND && params->primary_phy == ESP_BLE_GAP_PHY_2M) return false; + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_params(instance, params); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to set the data used in advertising PDUs that have a data field +* +* @param[in] instance : identifies the advertising set whose data are being configured +* @param[in] length : data length +* @param[in] data : data information +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data) +{ + esp_err_t rc; + rc = esp_ble_gap_config_ext_adv_data_raw(instance, length, data); + if (rc) log_e("set advertising data err: %d", rc); + + return ESP_OK == rc; +} + +bool BLEMultiAdvertising::setScanRspData(uint8_t instance, uint16_t length, const uint8_t* data) +{ + esp_err_t rc; + rc = esp_ble_gap_config_ext_scan_rsp_data_raw(instance, length, data); + if (rc) log_e("set scan resp data err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to request the Controller to enable one or more +* advertising sets using the advertising sets identified by the instance parameter. +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::start() +{ + return start(count, 0); +} + +/** +* @brief This function is used to request the Controller to enable one or more +* advertising sets using the advertising sets identified by the instance parameter. +* +* @param[in] num : Number of advertising sets to enable or disable +* @param[in] from : first sxt adv set to use +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::start(uint8_t num, uint8_t from) +{ + if (num > count || from >= count) return false; + + esp_err_t rc; + rc = esp_ble_gap_ext_adv_start(num, &ext_adv[from]); + if (rc) log_e("start extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to request the Controller to disable one or more +* advertising sets using the advertising sets identified by the instance parameter. +* +* @param[in] num_adv : Number of advertising sets to enable or disable +* @param[in] ext_adv_inst : ext adv instance +* +* @return - ESP_OK : success +* - other : failed +* +*/ +bool BLEMultiAdvertising::stop(uint8_t num_adv, const uint8_t* ext_adv_inst) +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_stop(num_adv, ext_adv_inst); + if (rc) log_e("stop extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to remove an advertising set from the Controller. +* +* @param[in] instance : Used to identify an advertising set +* +* @return - ESP_OK : success +* - other : failed +* +*/ +bool BLEMultiAdvertising::remove(uint8_t instance) +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_remove(instance); + if (rc) log_e("remove extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to remove all existing advertising sets from the Controller. +* +* +* @return - ESP_OK : success +* - other : failed +* +*/ +bool BLEMultiAdvertising::clear() +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_clear(); + if (rc) log_e("clear extended advertising err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used by the Host to set the random device address specified by the Random_Address parameter. +* +* @param[in] instance : Used to identify an advertising set +* @param[in] addr_legacy : Random Device Address +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setInstanceAddress(uint8_t instance, uint8_t* addr_legacy) +{ + esp_err_t rc; + rc = esp_ble_gap_ext_adv_set_rand_addr(instance, addr_legacy); + if (rc) log_e("set random address err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used by the Host to set the parameters for periodic advertising. +* +* @param[in] instance : identifies the advertising set whose periodic advertising parameters are being configured. +* @param[in] params : periodic adv parameters +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setPeriodicAdvertisingParams(uint8_t instance, const esp_ble_gap_periodic_adv_params_t* params) +{ + esp_err_t rc; + rc = esp_ble_gap_periodic_adv_set_params(instance, params); + if (rc) log_e("set periodic advertising params err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to set the data used in periodic advertising PDUs. +* +* @param[in] instance : identifies the advertising set whose periodic advertising parameters are being configured. +* @param[in] length : the length of periodic data +* @param[in] data : periodic data information +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::setPeriodicAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data) +{ + esp_err_t rc; + rc = esp_ble_gap_config_periodic_adv_data_raw(instance, length, data); + if (rc) log_e("set periodic advertising raw data err: %d", rc); + + return ESP_OK == rc; +} + +/** +* @brief This function is used to request the Controller to enable the periodic advertising for the advertising set specified +* +* @param[in] instance : Used to identify an advertising set +* +* @return - true : success +* - false : failed +* +*/ +bool BLEMultiAdvertising::startPeriodicAdvertising(uint8_t instance) +{ + esp_err_t rc; + rc = esp_ble_gap_periodic_adv_start(instance); + if (rc) log_e("start periodic advertising err: %d", rc); + + return ESP_OK == rc; +} + +void BLEMultiAdvertising::setDuration(uint8_t instance, int duration, int max_events) +{ + ext_adv[instance] = { instance, duration, max_events }; +} + +#endif // SOC_BLE_50_SUPPORTED + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertising.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertising.h new file mode 100644 index 0000000..775400f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEAdvertising.h @@ -0,0 +1,117 @@ +/* + * BLEAdvertising.h + * + * Created on: Jun 21, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ +#define COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include "BLEUUID.h" +#include +#include "RTOS.h" + +/** + * @brief Advertisement data set by the programmer to be published by the %BLE server. + */ +class BLEAdvertisementData { + // Only a subset of the possible BLE architected advertisement fields are currently exposed. Others will + // be exposed on demand/request or as time permits. + // +public: + void setAppearance(uint16_t appearance); + void setCompleteServices(BLEUUID uuid); + void setFlags(uint8_t); + void setManufacturerData(String data); + void setName(String name); + void setPartialServices(BLEUUID uuid); + void setServiceData(BLEUUID uuid, String data); + void setShortName(String name); + void addData(String data); // Add data to the payload. + String getPayload(); // Retrieve the current advert payload. + +private: + friend class BLEAdvertising; + String m_payload; // The payload of the advertisement. +}; // BLEAdvertisementData + + +/** + * @brief Perform and manage %BLE advertising. + * + * A %BLE server will want to perform advertising in order to make itself known to %BLE clients. + */ +class BLEAdvertising { +public: + BLEAdvertising(); + void addServiceUUID(BLEUUID serviceUUID); + void addServiceUUID(const char* serviceUUID); + void start(); + void stop(); + void setAppearance(uint16_t appearance); + void setAdvertisementType(esp_ble_adv_type_t adv_type); + void setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map); + void setMaxInterval(uint16_t maxinterval); + void setMinInterval(uint16_t mininterval); + 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 setDeviceAddress(esp_bd_addr_t addr, 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_data_t m_scanRespData; // Used for configuration of scan response data when m_scanResp is true + esp_ble_adv_params_t m_advParams; + std::vector m_serviceUUIDs; + 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; + +}; + +#ifdef SOC_BLE_50_SUPPORTED + +class BLEMultiAdvertising +{ +private: + esp_ble_gap_ext_adv_params_t* params_arrays; + esp_ble_gap_ext_adv_t* ext_adv; + uint8_t count; + +public: + BLEMultiAdvertising(uint8_t num = 1); + ~BLEMultiAdvertising() {} + + bool setAdvertisingParams(uint8_t instance, const esp_ble_gap_ext_adv_params_t* params); + bool setAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data); + bool setScanRspData(uint8_t instance, uint16_t length, const uint8_t* data); + bool start(); + bool start(uint8_t num, uint8_t from); + void setDuration(uint8_t instance, int duration = 0, int max_events = 0); + bool setInstanceAddress(uint8_t instance, esp_bd_addr_t rand_addr); + bool stop(uint8_t num_adv, const uint8_t* ext_adv_inst); + bool remove(uint8_t instance); + bool clear(); + bool setPeriodicAdvertisingParams(uint8_t instance, const esp_ble_gap_periodic_adv_params_t* params); + bool setPeriodicAdvertisingData(uint8_t instance, uint16_t length, const uint8_t* data); + bool startPeriodicAdvertising(uint8_t instance); +}; + +#endif // SOC_BLE_50_SUPPORTED + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEBeacon.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEBeacon.cpp new file mode 100644 index 0000000..641ac47 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEBeacon.cpp @@ -0,0 +1,86 @@ +/* + * BLEBeacon.cpp + * + * Created on: Jan 4, 2018 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include "BLEBeacon.h" +#include "esp32-hal-log.h" + +#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) + + +BLEBeacon::BLEBeacon() { + m_beaconData.manufacturerId = 0x4c00; + m_beaconData.subType = 0x02; + m_beaconData.subTypeLength = 0x15; + m_beaconData.major = 0; + m_beaconData.minor = 0; + m_beaconData.signalPower = 0; + memset(m_beaconData.proximityUUID, 0, sizeof(m_beaconData.proximityUUID)); +} // BLEBeacon + +String BLEBeacon::getData() { + return String((char*) &m_beaconData, sizeof(m_beaconData)); +} // getData + +uint16_t BLEBeacon::getMajor() { + return m_beaconData.major; +} + +uint16_t BLEBeacon::getManufacturerId() { + return m_beaconData.manufacturerId; +} + +uint16_t BLEBeacon::getMinor() { + return m_beaconData.minor; +} + +BLEUUID BLEBeacon::getProximityUUID() { + return BLEUUID(m_beaconData.proximityUUID, 16, true); +} + +int8_t BLEBeacon::getSignalPower() { + return m_beaconData.signalPower; +} + +/** + * Set the raw data for the beacon record. + */ +void BLEBeacon::setData(String data) { + if (data.length() != sizeof(m_beaconData)) { + log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData)); + return; + } + memcpy(&m_beaconData, data.c_str(), sizeof(m_beaconData)); +} // setData + +void BLEBeacon::setMajor(uint16_t major) { + m_beaconData.major = ENDIAN_CHANGE_U16(major); +} // setMajor + +void BLEBeacon::setManufacturerId(uint16_t manufacturerId) { + m_beaconData.manufacturerId = ENDIAN_CHANGE_U16(manufacturerId); +} // setManufacturerId + +void BLEBeacon::setMinor(uint16_t minor) { + m_beaconData.minor = ENDIAN_CHANGE_U16(minor); +} // setMinior + +void BLEBeacon::setProximityUUID(BLEUUID uuid) { + uuid = uuid.to128(); + memcpy(m_beaconData.proximityUUID, uuid.getNative()->uuid.uuid128, 16); +} // setProximityUUID + +void BLEBeacon::setSignalPower(int8_t signalPower) { + m_beaconData.signalPower = signalPower; +} // setSignalPower + + +#endif +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEBeacon.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEBeacon.h new file mode 100644 index 0000000..2adcda6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEBeacon.h @@ -0,0 +1,47 @@ +/* + * BLEBeacon2.h + * + * Created on: Jan 4, 2018 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEBEACON_H_ +#define COMPONENTS_CPP_UTILS_BLEBEACON_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "BLEUUID.h" +/** + * @brief Representation of a beacon. + * See: + * * https://en.wikipedia.org/wiki/IBeacon + */ +class BLEBeacon { +private: + struct { + uint16_t manufacturerId; + uint8_t subType; + uint8_t subTypeLength; + uint8_t proximityUUID[16]; + uint16_t major; + uint16_t minor; + int8_t signalPower; + } __attribute__((packed)) m_beaconData; +public: + BLEBeacon(); + String getData(); + uint16_t getMajor(); + uint16_t getMinor(); + uint16_t getManufacturerId(); + BLEUUID getProximityUUID(); + int8_t getSignalPower(); + void setData(String data); + void setMajor(uint16_t major); + void setMinor(uint16_t minor); + void setManufacturerId(uint16_t manufacturerId); + void setProximityUUID(BLEUUID uuid); + void setSignalPower(int8_t signalPower); +}; // BLEBeacon + +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEBEACON_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristic.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristic.cpp new file mode 100644 index 0000000..d4ac6a7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristic.cpp @@ -0,0 +1,805 @@ +/* + * BLECharacteristic.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include +#include +#include "sdkconfig.h" +#include +#include "BLECharacteristic.h" +#include "BLEService.h" +#include "BLEDevice.h" +#include "BLEUtils.h" +#include "BLE2902.h" +#include "GeneralUtils.h" +#include "esp32-hal-log.h" + +#define NULL_HANDLE (0xffff) + +static BLECharacteristicCallbacks defaultCallback; //null-object-pattern + +/** + * @brief Construct a characteristic + * @param [in] uuid - UUID (const char*) for the characteristic. + * @param [in] properties - Properties for the characteristic. + */ +BLECharacteristic::BLECharacteristic(const char* uuid, uint32_t properties) : BLECharacteristic(BLEUUID(uuid), properties) { +} + +/** + * @brief Construct a characteristic + * @param [in] uuid - UUID for the characteristic. + * @param [in] properties - Properties for the characteristic. + */ +BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) { + m_bleUUID = uuid; + m_handle = NULL_HANDLE; + m_properties = (esp_gatt_char_prop_t)0; + m_pCallbacks = &defaultCallback; + + 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 + +/** + * @brief Destructor. + */ +BLECharacteristic::~BLECharacteristic() { + //free(m_value.attr_value); // Release the storage for the value. +} // ~BLECharacteristic + + +/** + * @brief Associate a descriptor with this characteristic. + * @param [in] pDescriptor + * @return N/A. + */ +void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) { + log_v(">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str()); + m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor); + log_v("<< addDescriptor()"); +} // addDescriptor + + +/** + * @brief Register a new characteristic with the ESP runtime. + * @param [in] pService The service with which to associate this characteristic. + */ +void BLECharacteristic::executeCreate(BLEService* pService) { + log_v(">> executeCreate()"); + + if (m_handle != NULL_HANDLE) { + log_e("Characteristic already has a handle."); + return; + } + + m_pService = pService; // Save the service to which this characteristic belongs. + + log_d("Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s", + getUUID().toString().c_str(), + m_pService->toString().c_str()); + + esp_attr_control_t control; + control.auto_rsp = ESP_GATT_RSP_BY_APP; + + m_semaphoreCreateEvt.take("executeCreate"); + esp_err_t errRc = ::esp_ble_gatts_add_char( + m_pService->getHandle(), + getUUID().getNative(), + static_cast(m_permissions), + getProperties(), + nullptr, + &control); // Whether to auto respond or not. + + if (errRc != ESP_OK) { + log_e("<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + m_semaphoreCreateEvt.wait("executeCreate"); + + BLEDescriptor* pDescriptor = m_descriptorMap.getFirst(); + while (pDescriptor != nullptr) { + pDescriptor->executeCreate(this); + pDescriptor = m_descriptorMap.getNext(); + } // End while + + log_v("<< executeCreate"); +} // executeCreate + + +/** + * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. + * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. + * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + */ +BLEDescriptor* BLECharacteristic::getDescriptorByUUID(const char* descriptorUUID) { + return m_descriptorMap.getByUUID(BLEUUID(descriptorUUID)); +} // getDescriptorByUUID + + +/** + * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic. + * @param [in] descriptorUUID The UUID of the descriptor that we wish to retrieve. + * @return The BLE Descriptor. If no such descriptor is associated with the characteristic, nullptr is returned. + */ +BLEDescriptor* BLECharacteristic::getDescriptorByUUID(BLEUUID descriptorUUID) { + return m_descriptorMap.getByUUID(descriptorUUID); +} // getDescriptorByUUID + + +/** + * @brief Get the handle of the characteristic. + * @return The handle of the characteristic. + */ +uint16_t BLECharacteristic::getHandle() { + return m_handle; +} // getHandle + +void BLECharacteristic::setAccessPermissions(esp_gatt_perm_t perm) { + m_permissions = perm; +} + +esp_gatt_char_prop_t BLECharacteristic::getProperties() { + return m_properties; +} // getProperties + + +/** + * @brief Get the service associated with this characteristic. + */ +BLEService* BLECharacteristic::getService() { + return m_pService; +} // getService + + +/** + * @brief Get the UUID of the characteristic. + * @return The UUID of the characteristic. + */ +BLEUUID BLECharacteristic::getUUID() { + return m_bleUUID; +} // getUUID + + +/** + * @brief Retrieve the current value of the characteristic. + * @return A pointer to storage containing the current characteristic value. + */ +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 + +/** + * @brief Retrieve the current length of the data of the characteristic. + * @return Amount of databytes of the characteristic. + */ +size_t BLECharacteristic::getLength() { + return m_value.getLength(); +} // getLength + +/** + * Handle a GATT server event. + */ +void BLECharacteristic::handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param) { + log_v(">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); + + switch(event) { + // Events handled: + // + // ESP_GATTS_ADD_CHAR_EVT + // ESP_GATTS_CONF_EVT + // ESP_GATTS_CONNECT_EVT + // ESP_GATTS_DISCONNECT_EVT + // ESP_GATTS_EXEC_WRITE_EVT + // ESP_GATTS_READ_EVT + // ESP_GATTS_WRITE_EVT + + // + // ESP_GATTS_EXEC_WRITE_EVT + // When we receive this event it is an indication that a previous write long needs to be committed. + // + // exec_write: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint8_t exec_write_flag - Either ESP_GATT_PREP_WRITE_EXEC or ESP_GATT_PREP_WRITE_CANCEL + // + case ESP_GATTS_EXEC_WRITE_EVT: { + if(m_writeEvt){ + m_writeEvt = false; + if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) { + m_value.commit(); + // Invoke the onWrite callback handler. + m_pCallbacks->onWrite(this, param); + } 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) { + log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } + break; + } // ESP_GATTS_EXEC_WRITE_EVT + + + // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. + // add_char: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + case ESP_GATTS_ADD_CHAR_EVT: { + 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; + } // ESP_GATTS_ADD_CHAR_EVT + + + // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. + // + // write: + // - uint16_t conn_id + // - uint16_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool need_rsp + // - bool is_prep + // - uint16_t len + // - uint8_t *value + // + case ESP_GATTS_WRITE_EVT: { +// We check if this write request is for us by comparing the handles in the event. If it is for us +// we save the new value. Next we look at the need_rsp flag which indicates whether or not we need +// to send a response. If we do, then we formulate a response and send it. + 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); + } + + log_d(" - Response to write event: New value: handle: %.2x, uuid: %s", + getHandle(), getUUID().toString().c_str()); + + char* pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len); + log_d(" - Data: length: %d, data: %s", param->write.len, pHexData); + free(pHexData); + + if (param->write.need_rsp) { + esp_gatt_rsp_t rsp; + + rsp.attr_value.len = param->write.len; + rsp.attr_value.handle = m_handle; + rsp.attr_value.offset = param->write.offset; + rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + memcpy(rsp.attr_value.value, param->write.value, param->write.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) { + log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } // Response needed + + if (param->write.is_prep != true) { + // Invoke the onWrite callback handler. + m_pCallbacks->onWrite(this, param); + } + } // Match on handles. + break; + } // ESP_GATTS_WRITE_EVT + + + // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. + // + // read: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool is_long + // - bool need_rsp + // + case ESP_GATTS_READ_EVT: { + if (param->read.handle == m_handle) { + + + +// Here's an interesting thing. The read request has the option of saying whether we need a response +// or not. What would it "mean" to receive a read request and NOT send a response back? That feels like +// a very strange read. +// +// We have to handle the case where the data we wish to send back to the client is greater than the maximum +// packet size of 22 bytes. In this case, we become responsible for chunking the data into units of 22 bytes. +// The apparent algorithm is as follows: +// +// If the is_long flag is set then this is a follow on from an original read and we will already have sent at least 22 bytes. +// If the is_long flag is not set then we need to check how much data we are going to send. If we are sending LESS than +// 22 bytes, then we "just" send it and thats the end of the story. +// If we are sending 22 bytes exactly, we just send it BUT we will get a follow on request. +// If we are sending more than 22 bytes, we send the first 22 bytes and we will get a follow on request. +// Because of follow on request processing, we need to maintain an offset of how much data we have already sent +// so that when a follow on request arrives, we know where to start in the data to send the next sequence. +// Note that the indication that the client will send a follow on request is that we sent exactly 22 bytes as a response. +// If our payload is divisible by 22 then the last response will be a response of 0 bytes in length. +// +// The following code has deliberately not been factored to make it fewer statements because this would cloud the +// the logic flow comprehension. +// + + // get mtu for peer device that we are sending read request to + uint16_t maxOffset = getService()->getServer()->getPeerMTU(param->read.conn_id) - 1; + log_d("mtu value: %d", maxOffset); + if (param->read.need_rsp) { + log_d("Sending a response (esp_ble_gatts_send_response)"); + esp_gatt_rsp_t rsp; + + if (param->read.is_long) { + String value = m_value.getValue(); + + if (value.length() - m_value.getReadOffset() < maxOffset) { + // This is the last in the chain + rsp.attr_value.len = value.length() - m_value.getReadOffset(); + rsp.attr_value.offset = m_value.getReadOffset(); + memcpy(rsp.attr_value.value, value.c_str() + rsp.attr_value.offset, rsp.attr_value.len); + m_value.setReadOffset(0); + } else { + // There will be more to come. + rsp.attr_value.len = maxOffset; + rsp.attr_value.offset = m_value.getReadOffset(); + memcpy(rsp.attr_value.value, value.c_str() + rsp.attr_value.offset, rsp.attr_value.len); + m_value.setReadOffset(rsp.attr_value.offset + maxOffset); + } + } else { // read.is_long == false + + // If is.long is false then this is the first (or only) request to read data, so invoke the callback + // Invoke the read callback. + m_pCallbacks->onRead(this, param); + + String value = m_value.getValue(); + + if (value.length() + 1 > maxOffset) { + // Too big for a single shot entry. + m_value.setReadOffset(maxOffset); + rsp.attr_value.len = maxOffset; + rsp.attr_value.offset = 0; + memcpy(rsp.attr_value.value, value.c_str(), rsp.attr_value.len); + } else { + // Will fit in a single packet with no callbacks required. + rsp.attr_value.len = value.length(); + rsp.attr_value.offset = 0; + memcpy(rsp.attr_value.value, value.c_str(), rsp.attr_value.len); + } + } + rsp.attr_value.handle = param->read.handle; + rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE; + + char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len); + log_d(" - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset); + free(pHexData); + + 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) { + log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + } // Response needed + } // Handle matches this characteristic. + break; + } // ESP_GATTS_READ_EVT + + + // ESP_GATTS_CONF_EVT + // + // conf: + // - esp_gatt_status_t status – The status code. + // - uint16_t conn_id – The connection used. + // + case ESP_GATTS_CONF_EVT: { + // log_d("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: { + break; + } + + case ESP_GATTS_DISCONNECT_EVT: { + m_semaphoreConfEvt.give(); + break; + } + + default: { + break; + } // default + + } // switch event + + // Give each of the descriptors associated with this characteristic the opportunity to handle the + // event. + + m_descriptorMap.handleGATTServerEvent(event, gatts_if, param); + log_v("<< handleGATTServerEvent"); +} // handleGATTServerEvent + + +/** + * @brief Send an indication. + * An indication is a transmission of up to the first 20 bytes of the characteristic value. An indication + * will block waiting a positive confirmation from the client. + * @return N/A + */ +void BLECharacteristic::indicate() { + + log_v(">> indicate: length: %d", m_value.getValue().length()); + notify(false); + log_v("<< indicate"); +} // indicate + + +/** + * @brief Send a notify. + * A notification is a transmission of up to the first 20 bytes of the characteristic value. An notification + * will not block; it is a fire and forget. + * @return N/A. + */ +void BLECharacteristic::notify(bool is_notification) { + log_v(">> notify: length: %d", m_value.getValue().length()); + + assert(getService() != nullptr); + assert(getService()->getServer() != nullptr); + + m_pCallbacks->onNotify(this); // Invoke the notify callback. + + GeneralUtils::hexDump((uint8_t*)m_value.getValue().c_str(), m_value.getValue().length()); + + if (getService()->getServer()->getConnectedCount() == 0) { + log_v("<< notify: No connected clients."); + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NO_CLIENT, 0); + return; + } + + // 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(is_notification) { + if (p2902 != nullptr && !p2902->getNotifications()) { + log_v("<< notifications disabled; ignoring"); + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NOTIFY_DISABLED, 0); // Invoke the notify callback. + return; + } + } + else{ + if (p2902 != nullptr && !p2902->getIndications()) { + log_v("<< indications disabled; ignoring"); + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED, 0); // Invoke the notify callback. + return; + } + } + for (auto &myPair : getService()->getServer()->getPeerDevices(false)) { + uint16_t _mtu = (myPair.second.mtu); + if (m_value.getValue().length() > _mtu - 3) { + log_w("- Truncating to %d bytes (maximum notify size)", _mtu - 3); + } + + size_t length = m_value.getValue().length(); + if(!is_notification) // is indication + 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().c_str(), !is_notification); // The need_confirm = false makes this a notify. + if (errRc != ESP_OK) { + log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc)); + m_semaphoreConfEvt.give(); + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_GATT, errRc); // Invoke the notify callback. + return; + } + if(!is_notification){ // is indication + if(!m_semaphoreConfEvt.timedWait("indicate", indicationTimeout)){ + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, 0); // Invoke the notify callback. + } else { + auto code = (esp_gatt_status_t) m_semaphoreConfEvt.value(); + if(code == ESP_GATT_OK) { + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_INDICATE, code); // Invoke the notify callback. + } else { + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, code); + } + } + } else { + m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0); // Invoke the notify callback. + } + } + log_v("<< notify"); +} // Notify + + +/** + * @brief Set the permission to broadcast. + * A characteristics has properties associated with it which define what it is capable of doing. + * One of these is the broadcast flag. + * @param [in] value The flag value of the property. + * @return N/A + */ +void BLECharacteristic::setBroadcastProperty(bool value) { + //log_d("setBroadcastProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_BROADCAST); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); + } +} // setBroadcastProperty + + +/** + * @brief Set the callback handlers for this characteristic. + * @param [in] pCallbacks An instance of a callbacks structure used to define any callbacks for the characteristic. + */ +void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) { + log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks); + if (pCallbacks != nullptr){ + m_pCallbacks = pCallbacks; + } else { + m_pCallbacks = &defaultCallback; + } + log_v("<< setCallbacks"); +} // setCallbacks + + +/** + * @brief Set the BLE handle associated with this characteristic. + * A user program will request that a characteristic be created against a service. When the characteristic has been + * registered, the service will be given a "handle" that it knows the characteristic as. This handle is unique to the + * server/service but it is told to the service, not the characteristic associated with the service. This internally + * exposed function can be invoked by the service against this model of the characteristic to allow the characteristic + * to learn its own handle. Once the characteristic knows its own handle, it will be able to see incoming GATT events + * that will be propagated down to it which contain a handle value and now know that the event is destined for it. + * @param [in] handle The handle associated with this characteristic. + */ +void BLECharacteristic::setHandle(uint16_t handle) { + log_v(">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str()); + m_handle = handle; + log_v("<< setHandle"); +} // setHandle + + +/** + * @brief Set the Indicate property value. + * @param [in] value Set to true if we are to allow indicate messages. + */ +void BLECharacteristic::setIndicateProperty(bool value) { + //log_d("setIndicateProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_INDICATE); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); + } +} // setIndicateProperty + + +/** + * @brief Set the Notify property value. + * @param [in] value Set to true if we are to allow notification messages. + */ +void BLECharacteristic::setNotifyProperty(bool value) { + //log_d("setNotifyProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_NOTIFY); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); + } +} // setNotifyProperty + + +/** + * @brief Set the Read property value. + * @param [in] value Set to true if we are to allow reads. + */ +void BLECharacteristic::setReadProperty(bool value) { + //log_d("setReadProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_READ); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_READ); + } +} // setReadProperty + + +/** + * @brief Set the value of the characteristic. + * @param [in] data The data to set for the characteristic. + * @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); + log_v(">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str()); + free(pHex); + if (length > ESP_GATT_MAX_ATTR_LEN) { + log_e("Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); + return; + } + m_semaphoreSetValue.take(); + m_value.setValue(data, length); + m_semaphoreSetValue.give(); + log_v("<< setValue"); +} // setValue + + +/** + * @brief Set the value of the characteristic from string data. + * We set the value of the characteristic from the bytes contained in the + * string. + * @param [in] Set the value of the characteristic. + * @return N/A. + */ +void BLECharacteristic::setValue(String value) { + setValue((uint8_t*)(value.c_str()), value.length()); +} // setValue + +void BLECharacteristic::setValue(uint16_t& data16) { + uint8_t temp[2]; + 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; + 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; + setValue(temp, 4); +} // setValue + +void BLECharacteristic::setValue(float& data32) { + float temp = data32; + setValue((uint8_t*)&temp, 4); +} // setValue + +void BLECharacteristic::setValue(double& data64) { + double temp = data64; + setValue((uint8_t*)&temp, 8); +} // setValue + + +/** + * @brief Set the Write No Response property value. + * @param [in] value Set to true if we are to allow writes with no response. + */ +void BLECharacteristic::setWriteNoResponseProperty(bool value) { + //log_d("setWriteNoResponseProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + } +} // setWriteNoResponseProperty + + +/** + * @brief Set the Write property value. + * @param [in] value Set to true if we are to allow writes. + */ +void BLECharacteristic::setWriteProperty(bool value) { + //log_d("setWriteProperty(%d)", value); + if (value) { + m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE); + } else { + m_properties = (esp_gatt_char_prop_t)(m_properties & ~ESP_GATT_CHAR_PROP_BIT_WRITE); + } +} // setWriteProperty + + +/** + * @brief Return a string representation of the characteristic. + * @return A string representation of the characteristic. + */ +String BLECharacteristic::toString() { + String res = "UUID: " + m_bleUUID.toString() + ", handle : 0x"; + char hex[5]; + snprintf(hex, sizeof(hex), "%04x", m_handle); + res += hex; + res += " "; + if (m_properties & ESP_GATT_CHAR_PROP_BIT_READ) res += "Read "; + if (m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE) res += "Write "; + if (m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) res += "WriteNoResponse "; + if (m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST) res += "Broadcast "; + if (m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) res += "Notify "; + if (m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE) res += "Indicate "; + return res; +} // toString + + +BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {} + +void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param) { + onRead(pCharacteristic); +} // onRead + +void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic) { + log_d(">> onRead: default"); + log_d("<< onRead"); +} // onRead + + +void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param) { + onWrite(pCharacteristic); +} // onWrite + +void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) { + log_d(">> onWrite: default"); + log_d("<< onWrite"); +} // onWrite + + +void BLECharacteristicCallbacks::onNotify(BLECharacteristic* pCharacteristic) { + log_d(">> onNotify: default"); + log_d("<< onNotify"); +} // onNotify + + +void BLECharacteristicCallbacks::onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) { + log_d(">> onStatus: default"); + log_d("<< onStatus"); +} // onStatus + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristic.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristic.h new file mode 100644 index 0000000..3ff9397 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristic.h @@ -0,0 +1,194 @@ +/* + * BLECharacteristic.h + * + * Created on: Jun 22, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ +#define COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "BLEUUID.h" +#include +#include +#include "BLEDescriptor.h" +#include "BLEValue.h" +#include "RTOS.h" + +class BLEService; +class BLEDescriptor; +class BLECharacteristicCallbacks; + +/** + * @brief A management structure for %BLE descriptors. + */ +class BLEDescriptorMap { +public: + 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); + 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; +}; + + +/** + * @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 + * can be read and written to by a %BLE client. + */ +class BLECharacteristic { +public: + BLECharacteristic(const char* uuid, uint32_t properties = 0); + BLECharacteristic(BLEUUID uuid, uint32_t properties = 0); + virtual ~BLECharacteristic(); + + void addDescriptor(BLEDescriptor* pDescriptor); + BLEDescriptor* getDescriptorByUUID(const char* descriptorUUID); + BLEDescriptor* getDescriptorByUUID(BLEUUID descriptorUUID); + BLEUUID getUUID(); + String getValue(); + uint8_t* getData(); + size_t getLength(); + + void indicate(); + void notify(bool is_notification = true); + void setBroadcastProperty(bool value); + void setCallbacks(BLECharacteristicCallbacks* pCallbacks); + void setIndicateProperty(bool value); + void setNotifyProperty(bool value); + void setReadProperty(bool value); + void setValue(uint8_t* data, size_t size); + void setValue(String value); + void setValue(uint16_t& data16); + void setValue(uint32_t& data32); + void setValue(int& data32); + void setValue(float& data32); + void setValue(double& data64); + void setWriteProperty(bool value); + void setWriteNoResponseProperty(bool value); + String toString(); + uint16_t getHandle(); + void setAccessPermissions(esp_gatt_perm_t perm); + + static const uint32_t PROPERTY_READ = 1<<0; + static const uint32_t PROPERTY_WRITE = 1<<1; + static const uint32_t PROPERTY_NOTIFY = 1<<2; + static const uint32_t PROPERTY_BROADCAST = 1<<3; + static const uint32_t PROPERTY_INDICATE = 1<<4; + static const uint32_t PROPERTY_WRITE_NR = 1<<5; + + static const uint32_t indicationTimeout = 1000; + +private: + + friend class BLEServer; + friend class BLEService; + friend class BLEDescriptor; + friend class BLECharacteristicMap; + + BLEUUID m_bleUUID; + BLEDescriptorMap m_descriptorMap; + uint16_t m_handle; + esp_gatt_char_prop_t m_properties; + BLECharacteristicCallbacks* m_pCallbacks; + BLEService* m_pService; + BLEValue m_value; + esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; + bool m_writeEvt = false; // If we have started a long write, this tells the commit code that we were the target + + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + + void executeCreate(BLEService* pService); + esp_gatt_char_prop_t getProperties(); + BLEService* getService(); + void setHandle(uint16_t handle); + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt"); + FreeRTOS::Semaphore m_semaphoreSetValue = FreeRTOS::Semaphore("SetValue"); +}; // 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 + * sub-classed instance of this class and will be notified when such an event happens. + */ +class BLECharacteristicCallbacks { +public: + typedef enum { + SUCCESS_INDICATE, + SUCCESS_NOTIFY, + ERROR_INDICATE_DISABLED, + ERROR_NOTIFY_DISABLED, + ERROR_GATT, + ERROR_NO_CLIENT, + ERROR_INDICATE_TIMEOUT, + ERROR_INDICATE_FAILURE + }Status; + + virtual ~BLECharacteristicCallbacks(); + + /** + * @brief Callback function to support a read request. + * @param [in] pCharacteristic The characteristic that is the source of the event. + * @param [in] param The BLE GATTS param. Use param->read. + */ + virtual void onRead(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param); + /** + * @brief DEPRECATED! Callback function to support a read request. Called only if onRead(,) not overrided. + * @param [in] pCharacteristic The characteristic that is the source of the event. + */ + virtual void onRead(BLECharacteristic* pCharacteristic); + + /** + * @brief Callback function to support a write request. + * @param [in] pCharacteristic The characteristic that is the source of the event. + * @param [in] param The BLE GATTS param. Use param->write. + */ + virtual void onWrite(BLECharacteristic* pCharacteristic, esp_ble_gatts_cb_param_t* param); + /** + * @brief DEPRECATED! Callback function to support a write request. Called only if onWrite(,) not overrided. + * @param [in] pCharacteristic The characteristic that is the source of the event. + */ + virtual void onWrite(BLECharacteristic* pCharacteristic); + + /** + * @brief Callback function to support a Notify request. + * @param [in] pCharacteristic The characteristic that is the source of the event. + */ + virtual void onNotify(BLECharacteristic* pCharacteristic); + + /** + * @brief Callback function to support a Notify/Indicate Status report. + * @param [in] pCharacteristic The characteristic that is the source of the event. + * @param [in] s Status of the notification/indication + * @param [in] code Additional code of underlying errors + */ + virtual void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code); +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristicMap.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristicMap.cpp new file mode 100644 index 0000000..c574b53 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLECharacteristicMap.cpp @@ -0,0 +1,138 @@ +/* + * BLECharacteristicMap.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "BLEService.h" +#ifdef ARDUINO_ARCH_ESP32 +#include "esp32-hal-log.h" +#endif + + +/** + * @brief Return the characteristic by handle. + * @param [in] handle The handle to look up the characteristic. + * @return The characteristic. + */ +BLECharacteristic* BLECharacteristicMap::getByHandle(uint16_t handle) { + return m_handleMap.at(handle); +} // getByHandle + + +/** + * @brief Return the characteristic by UUID. + * @param [in] UUID The UUID to look up the characteristic. + * @return The characteristic. + */ +BLECharacteristic* BLECharacteristicMap::getByUUID(const char* uuid) { + return getByUUID(BLEUUID(uuid)); +} + + +/** + * @brief Return the characteristic by UUID. + * @param [in] UUID The UUID to look up the characteristic. + * @return The characteristic. + */ +BLECharacteristic* BLECharacteristicMap::getByUUID(BLEUUID uuid) { + for (auto &myPair : m_uuidMap) { + if (myPair.first->getUUID().equals(uuid)) { + return myPair.first; + } + } + //return m_uuidMap.at(uuid.toString()); + return nullptr; +} // getByUUID + + +/** + * @brief Get the first characteristic in the map. + * @return The first characteristic in the map. + */ +BLECharacteristic* BLECharacteristicMap::getFirst() { + m_iterator = m_uuidMap.begin(); + if (m_iterator == m_uuidMap.end()) return nullptr; + BLECharacteristic* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getFirst + + +/** + * @brief Get the next characteristic in the map. + * @return The next characteristic in the map. + */ +BLECharacteristic* BLECharacteristicMap::getNext() { + if (m_iterator == m_uuidMap.end()) return nullptr; + BLECharacteristic* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getNext + + +/** + * @brief Pass the GATT server event onwards to each of the characteristics found in the mapping + * @param [in] event + * @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) { + // Invoke the handler for every Service we have. + for (auto& myPair : m_uuidMap) { + myPair.first->handleGATTServerEvent(event, gatts_if, param); + } +} // handleGATTServerEvent + + +/** + * @brief Set the characteristic by handle. + * @param [in] handle The handle of the characteristic. + * @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)); +} // setByHandle + + +/** + * @brief Set the characteristic by UUID. + * @param [in] uuid The uuid of the characteristic. + * @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())); +} // setByUUID + + +/** + * @brief Return a string representation of the characteristic map. + * @return A string representation of the characteristic map. + */ +String BLECharacteristicMap::toString() { + String res; + int count = 0; + char hex[5]; + for (auto &myPair: m_uuidMap) { + if (count > 0) {res += "\n";} + snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle()); + count++; + res += "handle: 0x"; + res += hex; + res += ", uuid: " + myPair.first->getUUID().toString(); + } + return res; +} // toString + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEClient.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEClient.cpp new file mode 100644 index 0000000..ae82c24 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEClient.cpp @@ -0,0 +1,600 @@ +/* + * BLEDevice.cpp + * + * Created on: Mar 22, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include +#include +#include // ESP32 BLE +#include "BLEClient.h" +#include "BLEUtils.h" +#include "BLEService.h" +#include "GeneralUtils.h" +#include +#include +#include +#include "BLEDevice.h" +#include "esp32-hal-log.h" + +/* + * Design + * ------ + * When we perform a searchService() requests, we are asking the BLE server to return each of the services + * that it exposes. For each service, we received an ESP_GATTC_SEARCH_RES_EVT event which contains details + * of the exposed service including its UUID. + * + * The objects we will invent for a BLEClient will be as follows: + * * BLERemoteService - A model of a remote service. + * * BLERemoteCharacteristic - A model of a remote characteristic + * * BLERemoteDescriptor - A model of a remote descriptor. + * + * Since there is a hierarchical relationship here, we will have the idea that from a BLERemoteService will own + * zero or more remote characteristics and a BLERemoteCharacteristic will own zero or more remote BLEDescriptors. + * + * We will assume that a BLERemoteService contains a map that maps BLEUUIDs to the set of owned characteristics + * and that a BLECharacteristic contains a map that maps BLEUUIDs to the set of owned descriptors. + * + * + */ + +BLEClient::BLEClient() { + m_pClientCallbacks = nullptr; + 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. +} // BLEClient + + +/** + * @brief Destructor. + */ +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(); + m_servicesMapByInstID.clear(); +} // ~BLEClient + + +/** + * @brief Clear any existing services. + * + */ +void BLEClient::clearServices() { + log_v(">> clearServices"); + // Delete all the services. + for (auto &myPair : m_servicesMap) { + delete myPair.second; + } + m_servicesMap.clear(); + m_haveServices = false; + log_v("<< 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, esp_ble_addr_type_t type) { + log_v(">> 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_appId = BLEDevice::m_appId++; + BLEDevice::addPeerDevice(this, true, m_appId); + m_semaphoreRegEvt.take("connect"); + + // clearServices(); // we dont need to delete services since every client is unique? + esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId); + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + BLEDevice::removePeerDevice(m_appId, true); + return false; + } + + uint32_t rc = m_semaphoreRegEvt.wait("connect"); + + if (rc != ESP_GATT_OK) { + // fixes ESP_GATT_NO_RESOURCES error mostly + log_e("esp_ble_gattc_app_register_error: rc=%d", rc); + BLEDevice::removePeerDevice(m_appId, true); + // not sure if this is needed here + // esp_ble_gattc_app_unregister(m_gattc_if); + // m_gattc_if = ESP_GATT_IF_NONE; + return false; + } + + m_peerAddress = address; + + // Perform the open connection request against the target BLE Server. + m_semaphoreOpenEvt.take("connect"); + errRc = ::esp_ble_gattc_open( + m_gattc_if, + *getPeerAddress().getNative(), // address + 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) { + log_e("esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + BLEDevice::removePeerDevice(m_appId, true); + return false; + } + + rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete. + // check the status of the connection and cleanup in case of failure + if (rc != ESP_GATT_OK) { + BLEDevice::removePeerDevice(m_appId, true); + esp_ble_gattc_app_unregister(m_gattc_if); + m_gattc_if = ESP_GATT_IF_NONE; + } + log_v("<< connect(), rc=%d", rc==ESP_GATT_OK); + return rc == ESP_GATT_OK; +} // connect + + +/** + * @brief Disconnect from the peer. + * @return N/A. + */ +void BLEClient::disconnect() { + log_v(">> disconnect()"); + esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId()); + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + log_v("<< disconnect()"); +} // disconnect + + +/** + * @brief Handle GATT Client events + */ +void BLEClient::gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam) { + + log_d("gattClientEventHandler [esp_gatt_if: %d] ... %s", + gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); + + // it is possible to receive events from other connections while waiting for registration + if (m_gattc_if == ESP_GATT_IF_NONE && event != ESP_GATTC_REG_EVT) { + return; + } + + // Execute handler code based on the type of event received. + switch(event) { + + case ESP_GATTC_SRVC_CHG_EVT: + log_i("SERVICE CHANGED"); + break; + + case ESP_GATTC_CLOSE_EVT: { + // esp_ble_gattc_app_unregister(m_appId); + // BLEDevice::removePeerDevice(m_gattc_if, true); + break; + } + + // + // ESP_GATTC_DISCONNECT_EVT + // + // disconnect: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + case ESP_GATTC_DISCONNECT_EVT: { + if (evtParam->disconnect.conn_id != getConnId()) break; + // If we receive a disconnect event, set the class flag that indicates that we are + // no longer connected. + bool m_wasConnected = m_isConnected; + m_isConnected = false; + esp_ble_gattc_app_unregister(m_gattc_if); + m_gattc_if = ESP_GATT_IF_NONE; + m_semaphoreOpenEvt.give(ESP_GATT_IF_NONE); + m_semaphoreRssiCmplEvt.give(); + m_semaphoreSearchCmplEvt.give(1); + BLEDevice::removePeerDevice(m_appId, true); + if (m_wasConnected && m_pClientCallbacks != nullptr) { + m_pClientCallbacks->onDisconnect(this); + } + break; + } // ESP_GATTC_DISCONNECT_EVT + + // + // ESP_GATTC_OPEN_EVT + // + // open: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // + case ESP_GATTC_OPEN_EVT: { + m_conn_id = evtParam->open.conn_id; + if (evtParam->open.status == ESP_GATT_OK) { + m_isConnected = true; // Flag us as connected. + if (m_pClientCallbacks != nullptr) { + m_pClientCallbacks->onConnect(this); + } + } else { + log_e("Failed to connect, status=%s", GeneralUtils::errorToString(evtParam->open.status)); + } + m_semaphoreOpenEvt.give(evtParam->open.status); + break; + } // ESP_GATTC_OPEN_EVT + + + // + // ESP_GATTC_REG_EVT + // + // reg: + // esp_gatt_status_t status + // uint16_t app_id + // + case ESP_GATTC_REG_EVT: { + m_gattc_if = gattc_if; + // pass on the registration status result, in case of failure + m_semaphoreRegEvt.give(evtParam->reg.status); + break; + } // ESP_GATTC_REG_EVT + + case ESP_GATTC_CFG_MTU_EVT: + if (evtParam->cfg_mtu.conn_id != getConnId()) break; + if(evtParam->cfg_mtu.status != ESP_GATT_OK) { + log_e("Config mtu failed"); + } + m_mtu = evtParam->cfg_mtu.mtu; + break; + + case ESP_GATTC_CONNECT_EVT: { + if (evtParam->connect.conn_id != getConnId()) break; + BLEDevice::updatePeerDevice(this, true, m_appId); + esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->connect.conn_id); + if (errRc != ESP_OK) { + log_e("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 + // + // search_cmpl: + // - esp_gatt_status_t status + // - uint16_t conn_id + // + case ESP_GATTC_SEARCH_CMPL_EVT: { + if (evtParam->search_cmpl.conn_id != getConnId()) break; + esp_ble_gattc_cb_param_t* p_data = (esp_ble_gattc_cb_param_t*)evtParam; + if (p_data->search_cmpl.status != ESP_GATT_OK){ + log_e("search service failed, error status = %x", p_data->search_cmpl.status); + break; + } +#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) { + // log_i("Get service information from remote device"); + // } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) { + // log_i("Get service information from flash"); + // } else { + // log_i("unknown service source"); + // } +#endif + m_semaphoreSearchCmplEvt.give(0); + break; + } // ESP_GATTC_SEARCH_CMPL_EVT + + + // + // ESP_GATTC_SEARCH_RES_EVT + // + // search_res: + // - uint16_t conn_id + // - uint16_t start_handle + // - uint16_t end_handle + // - esp_gatt_id_t srvc_id + // + case ESP_GATTC_SEARCH_RES_EVT: { + if (evtParam->search_res.conn_id != getConnId()) break; + BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id); + BLERemoteService* pRemoteService = new BLERemoteService( + evtParam->search_res.srvc_id, + this, + evtParam->search_res.start_handle, + evtParam->search_res.end_handle + ); + 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 + + + default: { + break; + } + } // Switch + + // Pass the request on to all services. + for (auto &myPair : m_servicesMap) { + myPair.second->gattClientEventHandler(event, gattc_if, evtParam); + } + +} // gattClientEventHandler + + +uint16_t BLEClient::getConnId() { + return m_conn_id; +} // getConnId + + + +esp_gatt_if_t BLEClient::getGattcIf() { + return m_gattc_if; +} // getGattcIf + + +/** + * @brief Retrieve the address of the peer. + * + * Returns the Bluetooth device address of the %BLE peer to which this client is connected. + */ +BLEAddress BLEClient::getPeerAddress() { + return m_peerAddress; +} // getAddress + + +/** + * @brief Ask the BLE server for the RSSI value. + * @return The RSSI value. + */ +int BLEClient::getRssi() { + log_v(">> getRssi()"); + if (!isConnected()) { + log_v("<< getRssi(): Not connected"); + return 0; + } + // We make the API call to read the RSSI value which is an asynchronous operation. We expect to receive + // an ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT to indicate completion. + // + m_semaphoreRssiCmplEvt.take("getRssi"); + esp_err_t rc = ::esp_ble_gap_read_rssi(*getPeerAddress().getNative()); + if (rc != ESP_OK) { + log_e("<< getRssi: esp_ble_gap_read_rssi: rc=%d %s", rc, GeneralUtils::errorToString(rc)); + return 0; + } + int rssiValue = m_semaphoreRssiCmplEvt.wait("getRssi"); + log_v("<< getRssi(): %d", rssiValue); + return rssiValue; +} // getRssi + + +/** + * @brief Get the service BLE Remote Service instance corresponding to the uuid. + * @param [in] uuid The UUID of the service being sought. + * @return A reference to the Service or nullptr if don't know about it. + */ +BLERemoteService* BLEClient::getService(const char* uuid) { + return getService(BLEUUID(uuid)); +} // getService + + +/** + * @brief Get the service object corresponding to the uuid. + * @param [in] uuid The UUID of the service being sought. + * @return A reference to the Service or nullptr if don't know about it. + * @throws BLEUuidNotFound + */ +BLERemoteService* BLEClient::getService(BLEUUID uuid) { + log_v(">> getService: uuid: %s", uuid.toString().c_str()); +// Design +// ------ +// We wish to retrieve the service given its UUID. It is possible that we have not yet asked the +// device what services it has in which case we have nothing to match against. If we have not +// asked the device about its services, then we do that now. Once we get the results we can then +// examine the services map to see if it has the service we are looking for. + if (!m_haveServices) { + getServices(); + } + String uuidStr = uuid.toString(); + for (auto &myPair : m_servicesMap) { + if (myPair.first == uuidStr) { + log_v("<< getService: found the service with uuid: %s", uuid.toString().c_str()); + return myPair.second; + } + } // End of each of the services. + log_v("<< getService: not found"); + return nullptr; +} // getService + + +/** + * @brief Ask the remote %BLE server for its services. + * A %BLE Server exposes a set of services for its partners. Here we ask the server for its set of + * services and wait until we have received them all. + * @return N/A + */ +std::map* BLEClient::getServices() { +/* + * Design + * ------ + * We invoke esp_ble_gattc_search_service. This will request a list of the service exposed by the + * peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT + * and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received. + */ + log_v(">> 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(), + NULL // Filter UUID + ); + + m_semaphoreSearchCmplEvt.take("getServices"); + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return &m_servicesMap; + } + // If sucessfull, remember that we now have services. + m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0); + log_v("<< getServices"); + return &m_servicesMap; +} // getServices + + +/** + * @brief Get the value of a specific characteristic associated with a specific service. + * @param [in] serviceUUID The service that owns the characteristic. + * @param [in] characteristicUUID The characteristic whose value we wish to read. + * @throws BLEUuidNotFound + */ +String BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) { + log_v(">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); + String ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue(); + log_v("<read_rssi_cmpl.rssi); + break; + } // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT + + default: + break; + } +} // handleGAPEvent + + +/** + * @brief Are we connected to a partner? + * @return True if we are connected and false if we are not connected. + */ +bool BLEClient::isConnected() { + return m_isConnected; +} // isConnected + + + + +/** + * @brief Set the callbacks that will be invoked. + */ +void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) { + m_pClientCallbacks = pClientCallbacks; +} // setClientCallbacks + + +/** + * @brief Set the value of a specific characteristic associated with a specific service. + * @param [in] serviceUUID The service that owns the characteristic. + * @param [in] characteristicUUID The characteristic whose value we wish to write. + * @throws BLEUuidNotFound + */ +void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, String value) { + log_v(">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); + getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value); + log_v("<< setValue"); +} // setValue + +uint16_t BLEClient::getMTU() { + return m_mtu; +} + + +/** + @brief Set the local and remote MTU size. + Should be called once after client connects if MTU size needs to be changed. + @return bool indicating if MTU was successfully set locally and on remote. +*/ +bool BLEClient::setMTU(uint16_t mtu) +{ + esp_err_t err = esp_ble_gatt_set_local_mtu(mtu); //First must set local MTU value. + if (err == ESP_OK) + { + err = esp_ble_gattc_send_mtu_req(m_gattc_if,m_conn_id); //Once local is set successfully set remote size + if (err!=ESP_OK) + { + log_e("Error setting send MTU request MTU: %d err=%d", mtu,err); + return false; + } + } + else + { + log_e("can't set local mtu value: %d", mtu); + return false; + } + log_v("<< setLocalMTU"); + + m_mtu = mtu; //successfully changed + + return true; +} + + + + +/** + * @brief Return a string representation of this client. + * @return A string representation of this client. + */ +String BLEClient::toString() { + String res = "peer address: " + m_peerAddress.toString(); + res += "\nServices:\n"; + for (auto &myPair : m_servicesMap) { + res += myPair.second->toString() + "\n"; + // myPair.second is the value + } + return res; +} // toString + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEClient.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEClient.h new file mode 100644 index 0000000..0207a21 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEClient.h @@ -0,0 +1,107 @@ +/* + * BLEDevice.h + * + * Created on: Mar 22, 2017 + * Author: kolban + */ + +#ifndef MAIN_BLEDEVICE_H_ +#define MAIN_BLEDEVICE_H_ + +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include +#include +#include +#include +//#include "BLEExceptions.h" +#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. + */ +class BLEClient { +public: + BLEClient(); + ~BLEClient(); + + 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 + std::map* getServices(); // Get a map of the services offered by the remote BLE Server + BLERemoteService* getService(const char* uuid); // Get a reference to a specified service offered by the remote BLE server. + BLERemoteService* getService(BLEUUID uuid); // Get a reference to a specified service offered by the remote BLE server. + String getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a given characteristic at a given service. + + void handleGAPEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param); + + bool isConnected(); // Return true if we are connected. + + void setClientCallbacks(BLEClientCallbacks *pClientCallbacks); + void setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, String value); // Set the value of a given characteristic at a given service. + + String toString(); // Return a string representation of this client. + uint16_t getConnId(); + esp_gatt_if_t getGattcIf(); + uint16_t getMTU(); + bool setMTU(uint16_t mtu); + +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); + + 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 = false; // Have we previously obtain the set of services from the remote server. + bool m_isConnected = false; // Are we currently connected. + + BLEClientCallbacks* m_pClientCallbacks; + 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 + + +/** + * @brief Callbacks associated with a %BLE client. + */ +class BLEClientCallbacks { +public: + virtual ~BLEClientCallbacks() {}; + virtual void onConnect(BLEClient *pClient) = 0; + virtual void onDisconnect(BLEClient *pClient) = 0; +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* MAIN_BLEDEVICE_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptor.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptor.cpp new file mode 100644 index 0000000..d39c3b4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptor.cpp @@ -0,0 +1,295 @@ +/* + * BLEDescriptor.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include +#include +#include "sdkconfig.h" +#include +#include "BLEService.h" +#include "BLEDescriptor.h" +#include "GeneralUtils.h" +#include "esp32-hal-log.h" + +#define NULL_HANDLE (0xffff) + + +/** + * @brief BLEDescriptor constructor. + */ +BLEDescriptor::BLEDescriptor(const char* uuid, uint16_t len) : BLEDescriptor(BLEUUID(uuid), len) { +} + +/** + * @brief BLEDescriptor constructor. + */ +BLEDescriptor::BLEDescriptor(BLEUUID uuid, uint16_t max_len) { + m_bleUUID = uuid; + m_value.attr_len = 0; // Initial length is 0. + 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 + + +/** + * @brief BLEDescriptor destructor. + */ +BLEDescriptor::~BLEDescriptor() { + free(m_value.attr_value); // Release the storage we created in the constructor. +} // ~BLEDescriptor + + +/** + * @brief Execute the creation of the descriptor with the BLE runtime in ESP. + * @param [in] pCharacteristic The characteristic to which to register this descriptor. + */ +void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) { + log_v(">> executeCreate(): %s", toString().c_str()); + + if (m_handle != NULL_HANDLE) { + log_e("Descriptor already has a handle."); + return; + } + + m_pCharacteristic = pCharacteristic; // Save the characteristic associated with this service. + + esp_attr_control_t control; + 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)m_permissions, + &m_value, + &control); + if (errRc != ESP_OK) { + log_e("<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreCreateEvt.wait("executeCreate"); + log_v("<< executeCreate"); +} // executeCreate + + +/** + * @brief Get the BLE handle for this descriptor. + * @return The handle for this descriptor. + */ +uint16_t BLEDescriptor::getHandle() { + return m_handle; +} // getHandle + + +/** + * @brief Get the length of the value of this descriptor. + * @return The length (in bytes) of the value of this descriptor. + */ +size_t BLEDescriptor::getLength() { + return m_value.attr_len; +} // getLength + + +/** + * @brief Get the UUID of the descriptor. + */ +BLEUUID BLEDescriptor::getUUID() { + return m_bleUUID; +} // getUUID + + + +/** + * @brief Get the value of this descriptor. + * @return A pointer to the value of this descriptor. + */ +uint8_t* BLEDescriptor::getValue() { + return m_value.attr_value; +} // getValue + + +/** + * @brief Handle GATT server events for the descripttor. + * @param [in] event + * @param [in] gatts_if + * @param [in] param + */ +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_GATTS_ADD_CHAR_DESCR_EVT + // + // add_char_descr: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + case ESP_GATTS_ADD_CHAR_DESCR_EVT: { + if (m_pCharacteristic != nullptr && + m_bleUUID.equals(BLEUUID(param->add_char_descr.descr_uuid)) && + m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle && + m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) { + setHandle(param->add_char_descr.attr_handle); + m_semaphoreCreateEvt.give(); + } + break; + } // ESP_GATTS_ADD_CHAR_DESCR_EVT + + // ESP_GATTS_WRITE_EVT - A request to write the value of a descriptor has arrived. + // + // write: + // - uint16_t conn_id + // - uint16_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool need_rsp + // - bool is_prep + // - uint16_t len + // - uint8_t *value + case ESP_GATTS_WRITE_EVT: { + if (param->write.handle == m_handle) { + setValue(param->write.value, param->write.len); // Set the value of the descriptor. + + 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. + } + } // End of ... this is our handle. + + break; + } // ESP_GATTS_WRITE_EVT + + // ESP_GATTS_READ_EVT - A request to read the value of a descriptor has arrived. + // + // read: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool is_long + // - bool need_rsp + // + case ESP_GATTS_READ_EVT: { + if (param->read.handle == m_handle) { // If this event is for this descriptor ... process it + + if (m_pCallback != nullptr) { // If we have a user supplied callback, invoke it now. + m_pCallback->onRead(this); // Invoke the onRead callback method in the callback handler. + } + + } // End of this is our handle + break; + } // ESP_GATTS_READ_EVT + + default: + break; + } // switch event +} // handleGATTServerEvent + + +/** + * @brief Set the callback handlers for this descriptor. + * @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor. + */ +void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks* pCallback) { + log_v(">> setCallbacks: 0x%x", (uint32_t) pCallback); + m_pCallback = pCallback; + log_v("<< setCallbacks"); +} // setCallbacks + + +/** + * @brief Set the handle of this descriptor. + * Set the handle of this descriptor to be the supplied value. + * @param [in] handle The handle to be associated with this descriptor. + * @return N/A. + */ +void BLEDescriptor::setHandle(uint16_t handle) { + log_v(">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle); + m_handle = handle; + log_v("<< setHandle()"); +} // setHandle + + +/** + * @brief Set the value of the descriptor. + * @param [in] data The data to set for the descriptor. + * @param [in] length The length of the data in bytes. + */ +void BLEDescriptor::setValue(uint8_t* data, size_t length) { + if (length > ESP_GATT_MAX_ATTR_LEN) { + log_e("Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN); + return; + } + m_value.attr_len = length; + memcpy(m_value.attr_value, data, length); + if (m_handle != NULL_HANDLE) { + esp_ble_gatts_set_attr_value(m_handle, length, (const uint8_t *)data); + log_d("Set the value in the GATTS database using handle 0x%x", m_handle); + } +} // setValue + + +/** + * @brief Set the value of the descriptor. + * @param [in] value The value of the descriptor in string form. + */ +void BLEDescriptor::setValue(String value) { + setValue((uint8_t*) value.c_str(), value.length()); +} // setValue + +void BLEDescriptor::setAccessPermissions(esp_gatt_perm_t perm) { + m_permissions = perm; +} + +/** + * @brief Return a string representation of the descriptor. + * @return A string representation of the descriptor. + */ +String BLEDescriptor::toString() { + char hex[5]; + snprintf(hex, sizeof(hex), "%04x", m_handle); + String res = "UUID: " + m_bleUUID.toString() + ", handle: 0x" + hex; + return res; +} // toString + + +BLEDescriptorCallbacks::~BLEDescriptorCallbacks() {} + +/** + * @brief Callback function to support a read request. + * @param [in] pDescriptor The descriptor that is the source of the event. + */ +void BLEDescriptorCallbacks::onRead(BLEDescriptor* pDescriptor) { + log_d("BLEDescriptorCallbacks", ">> onRead: default"); + log_d("BLEDescriptorCallbacks", "<< onRead"); +} // onRead + + +/** + * @brief Callback function to support a write request. + * @param [in] pDescriptor The descriptor that is the source of the event. + */ +void BLEDescriptorCallbacks::onWrite(BLEDescriptor* pDescriptor) { + log_d("BLEDescriptorCallbacks", ">> onWrite: default"); + log_d("BLEDescriptorCallbacks", "<< onWrite"); +} // onWrite + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptor.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptor.h new file mode 100644 index 0000000..2e83407 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptor.h @@ -0,0 +1,82 @@ +/* + * BLEDescriptor.h + * + * Created on: Jun 22, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ +#define COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include "BLEUUID.h" +#include "BLECharacteristic.h" +#include +#include "RTOS.h" + +class BLEService; +class BLECharacteristic; +class BLEDescriptorCallbacks; + +/** + * @brief A model of a %BLE descriptor. + */ +class BLEDescriptor { +public: + 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. + size_t getLength(); // Get the length of the value of the descriptor. + BLEUUID getUUID(); // Get the UUID of the descriptor. + uint8_t* getValue(); // Get a pointer to the value of the descriptor. + void handleGATTServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + + void setAccessPermissions(esp_gatt_perm_t perm); // Set the permissions of the descriptor. + void setCallbacks(BLEDescriptorCallbacks* pCallbacks); // Set callbacks to be invoked for the descriptor. + void setValue(uint8_t* data, size_t size); // Set the value of the descriptor as a pointer to data. + void setValue(String value); // Set the value of the descriptor as a data buffer. + + String toString(); // Convert the descriptor to a string representation. + +private: + friend class BLEDescriptorMap; + friend class BLECharacteristic; + BLEUUID m_bleUUID; + uint16_t m_handle; + BLEDescriptorCallbacks* m_pCallback; + BLECharacteristic* m_pCharacteristic; + esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + esp_attr_value_t m_value; + + void executeCreate(BLECharacteristic* pCharacteristic); + void setHandle(uint16_t handle); +}; // BLEDescriptor + + +/** + * @brief Callbacks that can be associated with a %BLE descriptors to inform of events. + * + * When a server application creates a %BLE descriptor, we may wish to be informed when there is either + * a read or write request to the descriptors value. An application can register a + * sub-classed instance of this class and will be notified when such an event happens. + */ +class BLEDescriptorCallbacks { +public: + virtual ~BLEDescriptorCallbacks(); + virtual void onRead(BLEDescriptor* pDescriptor); + virtual void onWrite(BLEDescriptor* pDescriptor); +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEDESCRIPTOR_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptorMap.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptorMap.cpp new file mode 100644 index 0000000..50f23d7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDescriptorMap.cpp @@ -0,0 +1,153 @@ +/* + * BLEDescriptorMap.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "BLECharacteristic.h" +#include "BLEDescriptor.h" +#include // ESP32 BLE +#ifdef ARDUINO_ARCH_ESP32 +#include "esp32-hal-log.h" +#endif + +/** + * @brief Return the descriptor by UUID. + * @param [in] UUID The UUID to look up the descriptor. + * @return The descriptor. If not present, then nullptr is returned. + */ +BLEDescriptor* BLEDescriptorMap::getByUUID(const char* uuid) { + return getByUUID(BLEUUID(uuid)); +} + + +/** + * @brief Return the descriptor by UUID. + * @param [in] UUID The UUID to look up the descriptor. + * @return The descriptor. If not present, then nullptr is returned. + */ +BLEDescriptor* BLEDescriptorMap::getByUUID(BLEUUID uuid) { + for (auto &myPair : m_uuidMap) { + if (myPair.first->getUUID().equals(uuid)) { + return myPair.first; + } + } + //return m_uuidMap.at(uuid.toString()); + return nullptr; +} // getByUUID + + +/** + * @brief Return the descriptor by handle. + * @param [in] handle The handle to look up the descriptor. + * @return The descriptor. + */ +BLEDescriptor* BLEDescriptorMap::getByHandle(uint16_t handle) { + return m_handleMap.at(handle); +} // getByHandle + + +/** + * @brief Set the descriptor by UUID. + * @param [in] uuid The uuid of the descriptor. + * @param [in] characteristic The descriptor to cache. + * @return N/A. + */ +void BLEDescriptorMap::setByUUID(const char* uuid, BLEDescriptor* pDescriptor){ + m_uuidMap.insert(std::pair(pDescriptor, uuid)); +} // setByUUID + + + +/** + * @brief Set the descriptor by UUID. + * @param [in] uuid The uuid of the descriptor. + * @param [in] characteristic The descriptor to cache. + * @return N/A. + */ +void BLEDescriptorMap::setByUUID(BLEUUID uuid, BLEDescriptor* pDescriptor) { + m_uuidMap.insert(std::pair(pDescriptor, uuid.toString())); +} // setByUUID + + +/** + * @brief Set the descriptor by handle. + * @param [in] handle The handle of the descriptor. + * @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)); +} // setByHandle + + +/** + * @brief Return a string representation of the descriptor map. + * @return A string representation of the descriptor map. + */ +String BLEDescriptorMap::toString() { + String res; + char hex[5]; + int count = 0; + for (auto &myPair : m_uuidMap) { + if (count > 0) {res += "\n";} + snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle()); + count++; + res += "handle: 0x"; + res += hex; + res += ", uuid: " + myPair.first->getUUID().toString(); + } + return res; +} // toString + + +/** + * @breif Pass the GATT server event onwards to each of the descriptors found in the mapping + * @param [in] event + * @param [in] gatts_if + * @param [in] param + */ +void BLEDescriptorMap::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 descriptor we have. + for (auto &myPair : m_uuidMap) { + myPair.first->handleGATTServerEvent(event, gatts_if, param); + } +} // handleGATTServerEvent + + +/** + * @brief Get the first descriptor in the map. + * @return The first descriptor in the map. + */ +BLEDescriptor* BLEDescriptorMap::getFirst() { + m_iterator = m_uuidMap.begin(); + if (m_iterator == m_uuidMap.end()) return nullptr; + BLEDescriptor* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getFirst + + +/** + * @brief Get the next descriptor in the map. + * @return The next descriptor in the map. + */ +BLEDescriptor* BLEDescriptorMap::getNext() { + if (m_iterator == m_uuidMap.end()) return nullptr; + BLEDescriptor* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getNext + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDevice.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDevice.cpp new file mode 100644 index 0000000..141e8eb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDevice.cpp @@ -0,0 +1,681 @@ +/* + * BLE.cpp + * + * Created on: Mar 16, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include +#include +#include +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 ESP-IDF +#include // Part of C++ Standard library +#include // Part of C++ Standard library +#include // Part of C++ Standard library + +#include "BLEDevice.h" +#include "BLEClient.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" + +#if defined(ARDUINO_ARCH_ESP32) +#include "esp32-hal-bt.h" +#endif + +#include "esp32-hal-log.h" + + +/** + * Singletons for the BLEDevice. + */ +BLEServer* BLEDevice::m_pServer = nullptr; +BLEScan* BLEDevice::m_pScan = nullptr; +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; // 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. + * @return A new instance of the client. + */ +/* STATIC */ BLEClient* BLEDevice::createClient() { + log_v(">> createClient"); +#ifndef CONFIG_GATTC_ENABLE // Check that BLE GATTC is enabled in make menuconfig + log_e("BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined"); + abort(); +#endif // CONFIG_GATTC_ENABLE + m_pClient = new BLEClient(); + log_v("<< createClient"); + return m_pClient; +} // createClient + + +/** + * @brief Create a new instance of a server. + * @return A new instance of the server. + */ +/* STATIC */ BLEServer* BLEDevice::createServer() { + log_v(">> createServer"); +#ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig + log_e("BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined"); + abort(); +#endif // CONFIG_GATTS_ENABLE + m_pServer = new BLEServer(); + m_pServer->createApp(m_appId++); + log_v("<< createServer"); + return m_pServer; +} // createServer + + +/** + * @brief Handle GATT server events. + * + * @param [in] event The event that has been newly received. + * @param [in] gatts_if The connection to the GATT interface. + * @param [in] param Parameters for the event. + */ +/* STATIC */ void BLEDevice::gattServerEventHandler( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param +) { + log_d("gattServerEventHandler [esp_gatt_if: %d] ... %s", + gatts_if, + BLEUtils::gattServerEventTypeToString(event).c_str()); + + BLEUtils::dumpGattServerEvent(event, gatts_if, param); + + switch (event) { + case ESP_GATTS_CONNECT_EVT: { +#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_GATTS_CONNECT_EVT + + default: { + break; + } + } // switch + + + if (BLEDevice::m_pServer != nullptr) { + BLEDevice::m_pServer->handleGATTServerEvent(event, gatts_if, param); + } + + if(m_customGattsHandler != nullptr) { + m_customGattsHandler(event, gatts_if, param); + } + +} // gattServerEventHandler + + +/** + * @brief Handle GATT client events. + * + * Handler for the GATT client events. + * + * @param [in] event + * @param [in] gattc_if + * @param [in] param + */ +/* STATIC */ void BLEDevice::gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* param) { + + log_d("gattClientEventHandler [esp_gatt_if: %d] ... %s", + gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str()); + BLEUtils::dumpGattClientEvent(event, gattc_if, param); + + switch(event) { + case ESP_GATTC_CONNECT_EVT: { +#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_GATTS_CONNECT_EVT + + 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(m_customGattcHandler != nullptr) { + m_customGattcHandler(event, gattc_if, param); + } + + +} // gattClientEventHandler + + +/** + * @brief Handle GAP events. + */ +/* STATIC */ void BLEDevice::gapEventHandler( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t *param) { + + BLEUtils::dumpGapEvent(event, param); + + switch(event) { + + case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ + log_i("ESP_GAP_BLE_OOB_REQ_EVT"); + break; + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + log_i("ESP_GAP_BLE_LOCAL_IR_EVT"); + break; + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + log_i("ESP_GAP_BLE_LOCAL_ER_EVT"); + break; + case ESP_GAP_BLE_NC_REQ_EVT: /* NUMERIC CONFIRMATION */ + log_i("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){ + 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 + break; + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + log_i("ESP_GAP_BLE_PASSKEY_REQ_EVT: "); + // esp_log_buffer_hex(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){ + esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest()); + } +#endif // CONFIG_BLE_SMP_ENABLE + break; + /* + * TODO should we add white/black list comparison? + */ + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should sent the security response with negative(false) accept value*/ + log_i("ESP_GAP_BLE_SEC_REQ_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig + if(BLEDevice::m_securityCallbacks!=nullptr){ + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest()); + } + else{ + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + } +#endif // CONFIG_BLE_SMP_ENABLE + break; + /* + * + */ + 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 + log_i("ESP_GAP_BLE_PASSKEY_NOTIF_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig + log_i("passKey = %d", param->ble_security.key_notif.passkey); + if(BLEDevice::m_securityCallbacks!=nullptr){ + 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. + log_d("ESP_GAP_BLE_KEY_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig + log_i("key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); +#endif // CONFIG_BLE_SMP_ENABLE + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: + log_i("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){ + BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); + } +#endif // CONFIG_BLE_SMP_ENABLE + break; + default: { + break; + } + } // switch + + if (BLEDevice::m_pClient != nullptr) { + BLEDevice::m_pClient->handleGAPEvent(event, param); + } + + if (BLEDevice::m_pScan != nullptr) { + BLEDevice::getScan()->handleGAPEvent(event, param); + } + + if(m_bleAdvertising != nullptr) { + BLEDevice::getAdvertising()->handleGAPEvent(event, param); + } + + if(m_customGapHandler != nullptr) { + BLEDevice::m_customGapHandler(event, param); + } + +} // gapEventHandler + + +/** + * @brief Get the BLE device address. + * @return The BLE device address. + */ +/* STATIC*/ BLEAddress BLEDevice::getAddress() { + const uint8_t* bdAddr = esp_bt_dev_get_address(); + esp_bd_addr_t addr; + memcpy(addr, bdAddr, sizeof(addr)); + return BLEAddress(addr); +} // getAddress + + +/** + * @brief Retrieve the Scan object that we use for scanning. + * @return The scanning object reference. This is a singleton object. The caller should not + * try and release/delete it. + */ +/* STATIC */ BLEScan* BLEDevice::getScan() { + //log_v(">> getScan"); + if (m_pScan == nullptr) { + m_pScan = new BLEScan(); + //log_d(" - creating a new scan object"); + } + //log_v("<< getScan: Returning object at 0x%x", (uint32_t)m_pScan); + return m_pScan; +} // getScan + + +/** + * @brief Get the value of a characteristic of a service on a remote device. + * @param [in] bdAddress + * @param [in] serviceUUID + * @param [in] characteristicUUID + */ +/* STATIC */ String BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) { + log_v(">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); + BLEClient* pClient = createClient(); + pClient->connect(bdAddress); + String ret = pClient->getValue(serviceUUID, characteristicUUID); + pClient->disconnect(); + log_v("<< getValue"); + return ret; +} // getValue + + +/** + * @brief Initialize the %BLE environment. + * @param deviceName The device name of the device. + */ +/* STATIC */ void BLEDevice::init(String deviceName) { + if(!initialized){ + initialized = true; // Set the initialization flag to ensure we are only initialized once. + + esp_err_t errRc = ESP_OK; +#ifdef ARDUINO_ARCH_ESP32 + if (!btStart()) { + errRc = ESP_FAIL; + return; + } +#else + errRc = ::nvs_flash_init(); + if (errRc != ESP_OK) { + log_e("nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + +#ifndef CONFIG_BT_CLASSIC_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) { + log_e("esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + +#ifndef CONFIG_BT_CLASSIC_ENABLED + errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (errRc != ESP_OK) { + log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } +#else + errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM); + if (errRc != ESP_OK) { + log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } +#endif +#endif + + esp_bluedroid_status_t bt_state = esp_bluedroid_get_status(); + if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED) { + errRc = esp_bluedroid_init(); + if (errRc != ESP_OK) { + log_e("esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + } + + if (bt_state != ESP_BLUEDROID_STATUS_ENABLED) { + errRc = esp_bluedroid_enable(); + if (errRc != ESP_OK) { + log_e("esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + } + + errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler); + if (errRc != ESP_OK) { + log_e("esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + +#ifdef CONFIG_GATTC_ENABLE // Check that BLE client is configured in make menuconfig + errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler); + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } +#endif // CONFIG_GATTC_ENABLE + +#ifdef CONFIG_GATTS_ENABLE // Check that BLE server is configured in make menuconfig + errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler); + if (errRc != ESP_OK) { + log_e("esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } +#endif // CONFIG_GATTS_ENABLE + + errRc = ::esp_ble_gap_set_device_name(deviceName.c_str()); + if (errRc != ESP_OK) { + log_e("esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + }; + +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig + esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; + errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + if (errRc != ESP_OK) { + log_e("esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + }; +#endif // CONFIG_BLE_SMP_ENABLE + } + vTaskDelay(200 / portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. +} // init + + +/** + * @brief Set the transmission power. + * The power level can be one of: + * * ESP_PWR_LVL_N14 + * * ESP_PWR_LVL_N11 + * * ESP_PWR_LVL_N8 + * * ESP_PWR_LVL_N5 + * * ESP_PWR_LVL_N2 + * * ESP_PWR_LVL_P1 + * * ESP_PWR_LVL_P4 + * * ESP_PWR_LVL_P7 + * + * The power types can be one of: + * * ESP_BLE_PWR_TYPE_CONN_HDL0 + * * ESP_BLE_PWR_TYPE_CONN_HDL1 + * * ESP_BLE_PWR_TYPE_CONN_HDL2 + * * ESP_BLE_PWR_TYPE_CONN_HDL3 + * * ESP_BLE_PWR_TYPE_CONN_HDL4 + * * ESP_BLE_PWR_TYPE_CONN_HDL5 + * * ESP_BLE_PWR_TYPE_CONN_HDL6 + * * ESP_BLE_PWR_TYPE_CONN_HDL7 + * * ESP_BLE_PWR_TYPE_CONN_HDL8 + * * ESP_BLE_PWR_TYPE_ADV + * * ESP_BLE_PWR_TYPE_SCAN + * * ESP_BLE_PWR_TYPE_DEFAULT + * @param [in] powerType. + * @param [in] powerLevel. + */ +/* STATIC */ void BLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) { + log_v(">> setPower: %d (type: %d)", powerLevel, powerType); + esp_err_t errRc = ::esp_ble_tx_power_set(powerType, powerLevel); + if (errRc != ESP_OK) { + log_e("esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + }; + log_v("<< setPower"); +} // setPower + + +/** + * @brief Set the value of a characteristic of a service on a remote device. + * @param [in] bdAddress + * @param [in] serviceUUID + * @param [in] characteristicUUID + */ +/* STATIC */ void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, String value) { + log_v(">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str()); + BLEClient* pClient = createClient(); + pClient->connect(bdAddress); + pClient->setValue(serviceUUID, characteristicUUID, value); + pClient->disconnect(); +} // setValue + + +/** + * @brief Return a string representation of the nature of this device. + * @return A string representation of the nature of this device. + */ +/* STATIC */ String BLEDevice::toString() { + String res = "BD Address: " + getAddress().toString(); + return res; +} // toString + + +/** + * @brief Add an entry to the BLE white list. + * @param [in] address The address to add to the white list. + */ +void BLEDevice::whiteListAdd(BLEAddress address) { + log_v(">> whiteListAdd: %s", address.toString().c_str()); +#ifdef ESP_IDF_VERSION_MAJOR + esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative(), BLE_WL_ADDR_TYPE_PUBLIC); // HACK!!! True to add an entry. +#else + esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative()); // True to add an entry. +#endif + if (errRc != ESP_OK) { + log_e("esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + log_v("<< whiteListAdd"); +} // whiteListAdd + + +/** + * @brief Remove an entry from the BLE white list. + * @param [in] address The address to remove from the white list. + */ +void BLEDevice::whiteListRemove(BLEAddress address) { + log_v(">> whiteListRemove: %s", address.toString().c_str()); +#ifdef ESP_IDF_VERSION_MAJOR + esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative(), BLE_WL_ADDR_TYPE_PUBLIC); // HACK!!! False to remove an entry. +#else + esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative()); // False to remove an entry. +#endif + if (errRc != ESP_OK) { + log_e("esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + } + log_v("<< whiteListRemove"); +} // whiteListRemove + +/* + * @brief Set encryption level that will be negotiated with peer device durng connection + * @param [in] level Requested encryption level + */ +void BLEDevice::setEncryptionLevel(esp_ble_sec_act_t level) { + BLEDevice::m_securityLevel = level; +} + +/* + * @brief Set callbacks that will be used to handle encryption negotiation events and authentication events + * @param [in] cllbacks Pointer to BLESecurityCallbacks class callback + */ +void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) { + BLEDevice::m_securityCallbacks = callbacks; +} + +/* + * @brief Setup local mtu that will be used to negotiate mtu during request from client peer + * @param [in] mtu Value to set local mtu, should be larger than 23 and lower or equal to 517 + */ +esp_err_t BLEDevice::setMTU(uint16_t mtu) { + log_v(">> setLocalMTU: %d", mtu); + esp_err_t err = esp_ble_gatt_set_local_mtu(mtu); + if (err == ESP_OK) { + m_localMTU = mtu; + } else { + log_e("can't set local mtu value: %d", mtu); + } + log_v("<< setLocalMTU"); + return err; +} + +/* + * @brief Get local MTU value set during mtu request or default value + */ +uint16_t BLEDevice::getMTU() { + return m_localMTU; +} + +bool BLEDevice::getInitialized() { + return initialized; +} + +BLEAdvertising* BLEDevice::getAdvertising() { + if(m_bleAdvertising == nullptr) { + m_bleAdvertising = new BLEAdvertising(); + log_i("create advertising"); + } + log_d("get advertising"); + return m_bleAdvertising; +} + +void BLEDevice::startAdvertising() { + log_v(">> startAdvertising"); + getAdvertising()->start(); + log_v("<< startAdvertising"); +} // startAdvertising + +void BLEDevice::stopAdvertising() { + log_v(">> stopAdvertising"); + getAdvertising()->stop(); + log_v("<< stopAdvertising"); +} // stopAdvertising + +/* 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) { + log_d("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) { + log_i("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)); +} + +//there may have some situation that invoking this function simultaneously, that will cause CORRUPT HEAP +//let this function serializable +portMUX_TYPE BLEDevice::mux = portMUX_INITIALIZER_UNLOCKED; +void BLEDevice::removePeerDevice(uint16_t conn_id, bool _client) { + portENTER_CRITICAL(&mux); + log_i("remove: %d, GATT role %s", conn_id, _client?"client":"server"); + if(m_connectedClientsMap.find(conn_id) != m_connectedClientsMap.end()) + m_connectedClientsMap.erase(conn_id); + portEXIT_CRITICAL(&mux); +} + +/* 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(); +#ifdef 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_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDevice.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDevice.h new file mode 100644 index 0000000..805517c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEDevice.h @@ -0,0 +1,105 @@ +/* + * BLEDevice.h + * + * Created on: Mar 16, 2017 + * Author: kolban + */ + +#ifndef MAIN_BLEDevice_H_ +#define MAIN_BLEDevice_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include // ESP32 BLE +#include // ESP32 BLE +#include // Part of C++ STL +#include +#include + +#include "BLEServer.h" +#include "BLEClient.h" +#include "BLEUtils.h" +#include "BLEScan.h" +#include "BLEAddress.h" + +/** + * @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: + + static BLEClient* createClient(); // Create a new BLE client. + static BLEServer* createServer(); // Cretae a new BLE server. + static BLEAddress getAddress(); // Retrieve our own local BD address. + static BLEScan* getScan(); // Get the scan object + static String getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a characteristic of a service on a server. + static void init(String deviceName); // Initialize the local BLE environment. + static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); // Set our power level. + static void setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, String value); // Set the value of a characteristic on a service on a server. + static String toString(); // Return a string representation of our device. + static void whiteListAdd(BLEAddress address); // Add an entry to the BLE white list. + static void whiteListRemove(BLEAddress address); // Remove an entry from the BLE white list. + static void setEncryptionLevel(esp_ble_sec_act_t level); + static void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks); + 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 void stopAdvertising(); + 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 BLESecurityCallbacks* m_securityCallbacks; + static BLEAdvertising* m_bleAdvertising; + static esp_gatt_if_t getGattcIF(); + static std::map m_connectedClientsMap; + static portMUX_TYPE mux; + + static void gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* param); + + static void gattServerEventHandler( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param); + + static void gapEventHandler( + 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_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* MAIN_BLEDevice_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.cpp new file mode 100644 index 0000000..4e6bdfe --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.cpp @@ -0,0 +1,179 @@ +/* + * BLEEddystoneTLM.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + * Edited on: Mar 20, 2020 by beegee-tokyo + * Fix temperature value (8.8 fixed format) + * Fix time stamp (0.1 second resolution) + * Fixes based on EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md + * + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "esp32-hal-log.h" +#include "BLEEddystoneTLM.h" + +static const char LOG_TAG[] = "BLEEddystoneTLM"; + +BLEEddystoneTLM::BLEEddystoneTLM() { + 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)/256; + m_eddystoneData.advCount = 0; + m_eddystoneData.tmil = 0; +} // BLEEddystoneTLM + +BLEEddystoneTLM::BLEEddystoneTLM(BLEAdvertisedDevice *advertisedDevice){ + char* payload = (char*)advertisedDevice->getPayload(); + for(int i = 0; i < advertisedDevice->getPayloadLength(); ++i){ + if(payload[i] == 0x16 && advertisedDevice->getPayloadLength() >= i+2+sizeof(m_eddystoneData) && payload[i+1] == 0xAA && payload[i+2] == 0xFE && payload[i+3] == 0x20){ + log_d("Eddystone TLM data frame starting at byte [%d]", i+3); + setData(String(payload+i+3, sizeof(m_eddystoneData))); + break; + } + } +} + +String BLEEddystoneTLM::getData() { + return String((char*) &m_eddystoneData, sizeof(m_eddystoneData)); +} // getData + +BLEUUID BLEEddystoneTLM::getUUID() { + return beaconUUID; +} // getUUID + +uint8_t BLEEddystoneTLM::getVersion() { + return m_eddystoneData.version; +} // getVersion + +uint16_t BLEEddystoneTLM::getVolt() { + return ENDIAN_CHANGE_U16(m_eddystoneData.volt); +} // getVolt + +float BLEEddystoneTLM::getTemp() { + return EDDYSTONE_TEMP_U16_TO_FLOAT(m_eddystoneData.temp); +} // getTemp + +uint16_t BLEEddystoneTLM::getRawTemp() { + return ENDIAN_CHANGE_U16(m_eddystoneData.temp); +} // getRawTemp + +uint32_t BLEEddystoneTLM::getCount() { + return ENDIAN_CHANGE_U32(m_eddystoneData.advCount); +} // getCount + +uint32_t BLEEddystoneTLM::getTime() { + return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10; +} // getTime + +String BLEEddystoneTLM::toString() { + String out = ""; + uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil); + char val[12]; + + out += "Version " + String(m_eddystoneData.version); + //snprintf(val, sizeof(val), "%d", m_eddystoneData.version); + //out += val; + out += "\n"; + out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt); + snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt)); + out += val; + out += " mV\n"; + + out += "Temperature "; + snprintf(val, sizeof(val), "%.2f", ((int16_t)ENDIAN_CHANGE_U16(m_eddystoneData.temp)) / 256.0f); + out += val; + out += " C\n"; + + out += "Adv. Count "; + snprintf(val, sizeof(val), "%ld", ENDIAN_CHANGE_U32(m_eddystoneData.advCount)); + out += val; + out += "\n"; + + out += "Time in seconds "; + snprintf(val, sizeof(val), "%ld", rawsec/10); + out += val; + out += "\n"; + + out += "Time "; + + snprintf(val, sizeof(val), "%04ld", rawsec / 864000); + out += val; + out += "."; + + snprintf(val, sizeof(val), "%02ld", (rawsec / 36000) % 24); + out += val; + out += ":"; + + snprintf(val, sizeof(val), "%02ld", (rawsec / 600) % 60); + out += val; + out += ":"; + + snprintf(val, sizeof(val), "%02ld", (rawsec / 10) % 60); + out += val; + out += "\n"; + + return out; +} // toString + +/** + * Set the raw data for the beacon record. + * Example: + * uint8_t *payload = advertisedDevice.getPayload(); + * eddystoneTLM.setData(String((char*)payload+22, advertisedDevice.getPayloadLength() - 22)); + * Note: the offset 22 works for current implementation of example BLE_EddystoneTLM Beacon.ino, however + * the position is not static and it is programmers responsibility to align the data. + * Data frame: + * | Field || Len | Type | UUID | EddyStone TLM | + * | Offset || 0 | 1 | 2 | 4 | + * | Len || 1 B | 1 B | 2 B | 14 B | + * | Data || ?? | ?? | 0xAA | 0xFE | ??? | + * + * EddyStone TLM frame: + * | Field || Type | Version | Batt mV | Beacon temp | Cnt since boot | Time since boot | + * | Offset || 0 | 1 | 2 | 4 | 6 | 10 | + * | Len || 1 B | 1 B | 2 B | 2 B | 4 B | 4 B | + * | Data || 0x20 | ?? | ?? | ?? | ?? | ?? | | | | | | | | | + */ +void BLEEddystoneTLM::setData(String data) { + if (data.length() != sizeof(m_eddystoneData)) { + log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_eddystoneData)); + return; + } + memcpy(&m_eddystoneData, data.c_str(), data.length()); +} // setData + +void BLEEddystoneTLM::setUUID(BLEUUID l_uuid) { + beaconUUID = l_uuid; +} // setUUID + +void BLEEddystoneTLM::setVersion(uint8_t version) { + m_eddystoneData.version = version; +} // setVersion + +// Set voltage in ESP32 native Big endian and convert it to little endian used for BLE Frame +void BLEEddystoneTLM::setVolt(uint16_t volt) { + m_eddystoneData.volt = ENDIAN_CHANGE_U16(volt); +} // setVolt + +void BLEEddystoneTLM::setTemp(float temp) { + m_eddystoneData.temp = EDDYSTONE_TEMP_FLOAT_TO_U16(temp); +} // setTemp + +void BLEEddystoneTLM::setCount(uint32_t advCount) { + m_eddystoneData.advCount = advCount; +} // setCount + +void BLEEddystoneTLM::setTime(uint32_t tmil) { + m_eddystoneData.tmil = tmil; +} // setTime + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.cppwithheadder b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.cppwithheadder new file mode 100644 index 0000000..fe37015 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.cppwithheadder @@ -0,0 +1,202 @@ +/* + * BLEEddystoneTLM.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + * Edited on: Mar 20, 2020 by beegee-tokyo + * Fix temperature value (8.8 fixed format) + * Fix time stamp (0.1 second resolution) + * Fixes based on EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md + * + */ +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "esp32-hal-log.h" +#include "BLEEddystoneTLM.h" + +static const char LOG_TAG[] = "BLEEddystoneTLM"; + +BLEEddystoneTLM::BLEEddystoneTLM() { + 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)/256; + m_eddystoneData.advCount = 0; + m_eddystoneData.tmil = 0; + _initHeadder(); +} // BLEEddystoneTLM + +BLEEddystoneTLM::BLEEddystoneTLM(BLEAdvertisedDevice *advertisedDevice){ + char* payload = (char*)advertisedDevice->getPayload(); + for(int i = 0; i < advertisedDevice->getPayloadLength(); ++i){ + if(payload[i] == 0x16 && advertisedDevice->getPayloadLength() >= i+2+sizeof(m_eddystoneData) && payload[i+1] == 0xAA && payload[i+2] == 0xFE && payload[i+3] == 0x20){ + log_d("Eddystone TLM data frame starting at byte [%d]", i+3); + setData(std::string(payload+i+3, sizeof(m_eddystoneData))); + break; + } + } + _initHeadder(); +} + +String BLEEddystoneTLM::getData() { + return String((char*) &m_eddystoneData, sizeof(m_eddystoneData)); +} // getData + +BLEUUID BLEEddystoneTLM::getUUID() { + return beaconUUID; +} // getUUID + +uint8_t BLEEddystoneTLM::getVersion() { + return m_eddystoneData.version; +} // getVersion + +uint16_t BLEEddystoneTLM::getVolt() { + return ENDIAN_CHANGE_U16(m_eddystoneData.volt); +} // getVolt + +float BLEEddystoneTLM::getTemp() { + return EDDYSTONE_TEMP_U16_TO_FLOAT(m_eddystoneData.temp); +} // getTemp + +uint16_t BLEEddystoneTLM::getRawTemp() { + return ENDIAN_CHANGE_U16(m_eddystoneData.temp); +} // getRawTemp + +uint32_t BLEEddystoneTLM::getCount() { + return ENDIAN_CHANGE_U32(m_eddystoneData.advCount); +} // getCount + +uint32_t BLEEddystoneTLM::getTime() { + return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10; +} // getTime + +String BLEEddystoneTLM::getFrame(){ + String frame(BLEHeadder); + frame += String((char*) &m_eddystoneData, sizeof(m_eddystoneData)); + log_d("Compiled frame of length %d Bytes", frame.length()); + for(int i = 0; i < frame.length(); ++i){ + log_d("[%d]=0x%02X",i, frame[i]); + } + return frame; +} // getServiceData + +String BLEEddystoneTLM::toString() { + String out = ""; + uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil); + char val[12]; + + out += "Version "; // + std::string(m_eddystoneData.version); + snprintf(val, sizeof(val), "%d", m_eddystoneData.version); + out += val; + out += "\n"; + out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt); + snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt)); + out += val; + out += " mV\n"; + + out += "Temperature "; + snprintf(val, sizeof(val), "%.2f", ((int16_t)ENDIAN_CHANGE_U16(m_eddystoneData.temp)) / 256.0f); + out += val; + out += " C\n"; + + out += "Adv. Count "; + snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount)); + out += val; + out += "\n"; + + out += "Time in seconds "; + snprintf(val, sizeof(val), "%d", rawsec/10); + out += val; + out += "\n"; + + out += "Time "; + + snprintf(val, sizeof(val), "%04d", rawsec / 864000); + out += val; + out += "."; + + snprintf(val, sizeof(val), "%02d", (rawsec / 36000) % 24); + out += val; + out += ":"; + + snprintf(val, sizeof(val), "%02d", (rawsec / 600) % 60); + out += val; + out += ":"; + + snprintf(val, sizeof(val), "%02d", (rawsec / 10) % 60); + out += val; + out += "\n"; + + return out; +} // toString + +/** + * Set the raw data for the beacon record. + * Example: + * uint8_t *payload = advertisedDevice.getPayload(); + * eddystoneTLM.setData(std::string((char*)payload+22, advertisedDevice.getPayloadLength() - 22)); + * Note: the offset 22 works for current implementation of example BLE_EddystoneTLM Beacon.ino, however + * the position is not static and it is programmers responsibility to align the data. + * Data frame: + * | Field || Len | Type | UUID | EddyStone TLM | + * | Offset || 0 | 1 | 2 | 4 | + * | Len || 1 B | 1 B | 2 B | 14 B | + * | Data || ?? | ?? | 0xAA | 0xFE | ??? | + * + * EddyStone TLM frame: + * | Field || Type | Version | Batt mV | Beacon temp | Cnt since boot | Time since boot | + * | Offset || 0 | 1 | 2 | 4 | 6 | 10 | + * | Len || 1 B | 1 B | 2 B | 2 B | 4 B | 4 B | + * | Data || 0x20 | ?? | ?? | ?? | ?? | ?? | | | | | | | | | + */ +void BLEEddystoneTLM::setData(std::string data) { + if (data.length() != sizeof(m_eddystoneData)) { + log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_eddystoneData)); + return; + } + memcpy(&m_eddystoneData, data.data(), data.length()); +} // setData + +void BLEEddystoneTLM::setUUID(BLEUUID l_uuid) { + beaconUUID = l_uuid; +} // setUUID + +void BLEEddystoneTLM::setVersion(uint8_t version) { + m_eddystoneData.version = version; +} // setVersion + +// Set voltage in ESP32 native Big endian and convert it to little endian used for BLE Frame +void BLEEddystoneTLM::setVolt(uint16_t volt) { + m_eddystoneData.volt = ENDIAN_CHANGE_U16(volt); +} // setVolt + +void BLEEddystoneTLM::setTemp(float temp) { + m_eddystoneData.temp = EDDYSTONE_TEMP_FLOAT_TO_U16(temp); +} // setTemp + +void BLEEddystoneTLM::setCount(uint32_t advCount) { + m_eddystoneData.advCount = advCount; +} // setCount + +void BLEEddystoneTLM::setTime(uint32_t tmil) { + m_eddystoneData.tmil = tmil; +} // setTime + +void BLEEddystoneTLM::_initHeadder(){ + BLEHeadder[0] = 0x02; // Len + BLEHeadder[1] = 0x01; // Type Flags + BLEHeadder[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04 + BLEHeadder[3] = 0x03; // Len + BLEHeadder[4] = 0x03; // Type 16-Bit UUID + BLEHeadder[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB + BLEHeadder[6] = 0xFE; // Eddystone UUID 1 MSB + BLEHeadder[7] = 0x11; // Length of TLM Beacon Data is constant 17 B (not counting the length field itself) + BLEHeadder[8] = 0x16; // Type Service Data + BLEHeadder[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB + BLEHeadder[10] = 0xFE; // Eddystone UUID 1 MSB + BLEHeadder[11] = 0x20; // Eddystone Frame Type - TLM +} + +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.h new file mode 100644 index 0000000..dab28c7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneTLM.h @@ -0,0 +1,61 @@ +/* + * BLEEddystoneTLM.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + */ + +#ifndef _BLEEddystoneTLM_H_ +#define _BLEEddystoneTLM_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "BLEUUID.h" +#include + +#define EDDYSTONE_TLM_FRAME_TYPE 0x20 +#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8)) +#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24)) +#define EDDYSTONE_TEMP_U16_TO_FLOAT(tempU16) (((int16_t)ENDIAN_CHANGE_U16(tempU16)) / 256.0f) +#define EDDYSTONE_TEMP_FLOAT_TO_U16(tempFloat) (ENDIAN_CHANGE_U16(((int)((tempFloat) * 256)))) + +/** + * @brief Representation of a beacon. + * See: + * * https://github.com/google/eddystone + */ +class BLEEddystoneTLM { +public: + BLEEddystoneTLM(); + BLEEddystoneTLM(BLEAdvertisedDevice *advertisedDevice); + String getData(); + BLEUUID getUUID(); + uint8_t getVersion(); + uint16_t getVolt(); + float getTemp(); + uint16_t getRawTemp(); + uint32_t getCount(); + uint32_t getTime(); + String toString(); + void setData(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: + BLEUUID beaconUUID; + struct { + uint8_t frameType; + uint8_t version; + uint16_t volt; + uint16_t temp; + uint32_t advCount; + uint32_t tmil; + } __attribute__((packed)) m_eddystoneData; +}; // BLEEddystoneTLM + +#endif /* SOC_BLE_SUPPORTED */ +#endif /* _BLEEddystoneTLM_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.cpp new file mode 100644 index 0000000..c10e00c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.cpp @@ -0,0 +1,290 @@ +/* + * BLEEddystoneURL.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + * Upgraded on: Feb 20, 2023 + * By: Tomas Pilny + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include "esp32-hal-log.h" +#include "BLEEddystoneURL.h" + +String EDDYSTONE_URL_PREFIX[] = { + "http://www.", // 0x00 + "https://www.", // 0x01 + "http://", // 0x02 + "https://", // 0x03 + "" // Any other code number results in empty string +}; + +String EDDYSTONE_URL_SUFFIX[] = { + ".com/", // 0x00 + ".org/", // 0x01 + ".edu/", // 0x02 + ".net/", // 0x03 + ".info/", // 0x04 + ".biz/", // 0x05 + ".gov/", // 0x06 + ".com", // 0x07 + ".org", // 0x08 + ".edu", // 0x09 + ".net", // 0x0A + ".info", // 0x0B + ".biz", // 0x0C + ".gov", // 0x0D + "" // Any other code number results in empty string +}; + +BLEEddystoneURL::BLEEddystoneURL() { + lengthURL = 0; + m_eddystoneData.advertisedTxPower = 0; + memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); + _initHeadder(); +} // BLEEddystoneURL + +BLEEddystoneURL::BLEEddystoneURL(BLEAdvertisedDevice *advertisedDevice){ + const char *payload = (char*)advertisedDevice->getPayload(); + memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url)); + lengthURL = 0; + m_eddystoneData.advertisedTxPower = 0; + for(int i = 0; i < advertisedDevice->getPayloadLength(); ++i){ + if(payload[i] == 0x16 && advertisedDevice->getPayloadLength() >= i+2+sizeof(m_eddystoneData) && payload[i+1] == 0xAA && payload[i+2] == 0xFE && payload[i+3] == 0x10){ + lengthURL = payload[i-1] - 5; // Subtracting 5 Bytes containing header and other data which are not actual URL data + m_eddystoneData.advertisedTxPower = payload[i+1]; + if(lengthURL <= 18){ + setData(String(payload+i+4, lengthURL+1)); + }else{ + log_e("Too long URL %d", lengthURL); + } + } + } + _initHeadder(); +} + +String BLEEddystoneURL::getData() { + return String((char*) &m_eddystoneData, sizeof(m_eddystoneData)); +} // getData + +String BLEEddystoneURL::getFrame() { + BLEHeadder[7] = lengthURL + 5; // Fill in real: Type + 2B UUID + Frame Type + Tx power + URL (note: the Byte holding the length does not count itself) + String frame(BLEHeadder, sizeof(BLEHeadder)); + frame += String((char*) &m_eddystoneData, lengthURL+1); // + 1 for TX power + + return frame; +} // getFrame + +BLEUUID BLEEddystoneURL::getUUID() { + uint16_t uuid = (((uint16_t)BLEHeadder[10]) << 8) | BLEHeadder[9]; + return BLEUUID(uuid); +} // getUUID + +int8_t BLEEddystoneURL::getPower() { + return m_eddystoneData.advertisedTxPower; +} // getPower + +String BLEEddystoneURL::getURL() { + return String((char*) &m_eddystoneData.url, lengthURL); +} // getURL + +String BLEEddystoneURL::getPrefix(){ + if(m_eddystoneData.url[0] <= 0x03){ + return EDDYSTONE_URL_PREFIX[m_eddystoneData.url[0]]; + }else{ + return ""; + } +} + +String BLEEddystoneURL::getSuffix(){ + if(m_eddystoneData.url[lengthURL-1] <= 0x0D){ + return EDDYSTONE_URL_SUFFIX[m_eddystoneData.url[lengthURL-1]]; + }else{ + return ""; + } +} + +String BLEEddystoneURL::getDecodedURL() { + std::string decodedURL = ""; + decodedURL += getPrefix().c_str(); + if(decodedURL.length() == 0){ // No prefix extracted - interpret byte [0] as character + decodedURL += (char)m_eddystoneData.url[0]; + } + for(int i = 1; i < lengthURL; i++) { + if (m_eddystoneData.url[i] >= 33 && m_eddystoneData.url[i] < 127) { + decodedURL += (char)m_eddystoneData.url[i]; + }else{ + if(i != lengthURL-1 || m_eddystoneData.url[i] > 0x0D){ // Ignore last Byte and values used for suffix + log_e("Unexpected unprintable char in URL 0x%02X: m_eddystoneData.url[%d]", m_eddystoneData.url[i], i); + } + } + } + decodedURL += getSuffix().c_str(); + return String(decodedURL.c_str()); +} // getDecodedURL + +/** + * Set the raw data for the beacon record. + * Example: + * uint8_t *payload = advertisedDevice.getPayload(); + * eddystoneTLM.setData(String((char*)payload+11, advertisedDevice.getPayloadLength() - 11)); + * Note: the offset 11 works for current implementation of example BLE_EddystoneTLM Beacon.ino, however + * the position is not static and it is programmers responsibility to align the data. + * Data frame: + * | Field || Len | Type | UUID | EddyStone URL | + * | Offset || 0 | 1 | 2 | 4 | + * | Len || 1 B | 1 B | 2 B | up to 20 B | + * | Data || ?? | ?? | 0xAA | 0xFE | ??? | + * + * EddyStone TLM frame: + * | Field || Type | TX Power | URL prefix | URL | + * | Offset || 0 | 1 | 2 | 3 | + * | Len || 1 B | 1 B | 1 B | 0-17 B | + * | Data || 0x10 | ?? | ?? | ?? | + */ +void BLEEddystoneURL::setData(String data) { + if (data.length() > sizeof(m_eddystoneData)) { + log_e("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.c_str(), data.length()); + lengthURL = data.length() - (sizeof(m_eddystoneData) - sizeof(m_eddystoneData.url)); +} // setData + +void BLEEddystoneURL::setUUID(BLEUUID l_uuid) { + uint16_t beaconUUID = l_uuid.getNative()->uuid.uuid16; + BLEHeadder[10] = beaconUUID >> 8; + BLEHeadder[9] = beaconUUID & 0x00FF; +} // setUUID + + +void BLEEddystoneURL::setPower(esp_power_level_t advertisedTxPower) { + int tx_power; + switch(advertisedTxPower){ + case ESP_PWR_LVL_N12: // 12dbm + tx_power = -12; + break; + case ESP_PWR_LVL_N9: // -9dbm + tx_power = -9; + break; + case ESP_PWR_LVL_N6: // -6dbm + tx_power = -6; + break; + case ESP_PWR_LVL_N3: // -3dbm + tx_power = -3; + break; + case ESP_PWR_LVL_N0: // 0dbm + tx_power = 0; + break; + case ESP_PWR_LVL_P3: // +3dbm + tx_power = +3; + break; + case ESP_PWR_LVL_P6: // +6dbm + tx_power = +6; + break; + case ESP_PWR_LVL_P9: // +9dbm + tx_power = +9; + break; + default: tx_power = 0; + } + m_eddystoneData.advertisedTxPower = int8_t((tx_power - -100) / 2); +} // setPower + + +void BLEEddystoneURL::setPower(int8_t advertisedTxPower) { + m_eddystoneData.advertisedTxPower = advertisedTxPower; +} // setPower + +// Set URL bytes including prefix and optional suffix +// | Field | Prefix | URL + optional Suffix | +// | Offset | 0 | 1 | +// | Length | 1 B | 0 - 17 B | +// | Example | 0x02 | 0x676F6F676C65 0x07 | +// | Decoded | http:// | g o o g l e .com | +void BLEEddystoneURL::setURL(String url) { + if (url.length() > sizeof(m_eddystoneData.url)) { + log_e("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.c_str(), url.length()); + lengthURL = url.length(); +} // setURL + +int BLEEddystoneURL::setSmartURL(String url) { + if(url.length() == 0){ + log_e("URL String has 0 length"); + return 0; // ERROR + } + for(auto character : url){ + if(!isPrintable(character)){ + log_e("URL contains unprintable character(s)"); + return 0; // ERROR + } + } + bool hasPrefix = false; + bool hasSuffix = false; + m_eddystoneData.url[0] = 0x00; // Init with default prefix "http://www." + uint8_t suffix = 0x0E; // Init with empty string + log_d("Encode url \"%s\" with length %d", url.c_str(), url.length()); + for(uint8_t i = 0; i < 4; ++i){ + if(url.substring(0, EDDYSTONE_URL_PREFIX[i].length()) == EDDYSTONE_URL_PREFIX[i]){ + m_eddystoneData.url[0] = i; + hasPrefix = true; + break; + } + } + + if(hasPrefix == false){ + log_w("Prefix not found - using default prefix \"http://www.\" = 0x00\n\tNote: URL must contain one of the prefixes: \"http://www.\", \"https://www.\", \"http://\", \"https://\""); + } + + for(uint8_t i = 0; i < 0x0E; ++i){ + std::string std_url(url.c_str()); + std::string std_suffix(EDDYSTONE_URL_SUFFIX[i].c_str()); + size_t found_pos = std_url.find(std_suffix); + if(found_pos != std::string::npos){ + hasSuffix = true; + suffix = i; + break; + } + } + + size_t baseUrlLen = url.length() - (hasPrefix ? EDDYSTONE_URL_PREFIX[m_eddystoneData.url[0]].length() : 0) - EDDYSTONE_URL_SUFFIX[suffix].length(); + lengthURL = baseUrlLen + 1 + (hasSuffix ? 1 : 0); + if(lengthURL > 18){ + log_e("Encoded URL is too long %d B - max 18 B", lengthURL); + return 0; // ERROR + } + String baseUrl = url.substring((hasPrefix ? EDDYSTONE_URL_PREFIX[m_eddystoneData.url[0]].length() : 0), baseUrlLen+(hasPrefix ? EDDYSTONE_URL_PREFIX[m_eddystoneData.url[0]].length() : 0)); + memcpy((void*)(m_eddystoneData.url+1), (void*)baseUrl.c_str(), baseUrl.length()); // substr for Arduino String + + if(hasSuffix){ + m_eddystoneData.url[1+baseUrlLen] = suffix; + } + + return 1; // OK +} // setSmartURL + +void BLEEddystoneURL::_initHeadder(){ + BLEHeadder[0] = 0x02; // Len + BLEHeadder[1] = 0x01; // Type Flags + BLEHeadder[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04 + BLEHeadder[3] = 0x03; // Len + BLEHeadder[4] = 0x03; // Type 16-Bit UUID + BLEHeadder[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB + BLEHeadder[6] = 0xFE; // Eddystone UUID 1 MSB + BLEHeadder[7] = 0x00; // Length of Beacon Data shall be calculated later + BLEHeadder[8] = 0x16; // Type Service Data + BLEHeadder[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB + BLEHeadder[10] = 0xFE; // Eddystone UUID 1 MSB + BLEHeadder[11] = 0x10; // Eddystone Frame Type - URL +} + +#endif +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.h new file mode 100644 index 0000000..7f6e114 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.h @@ -0,0 +1,60 @@ +/* + * BLEEddystoneURL.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + * Upgraded on: Feb 20, 2023 + * By: Tomas Pilny + * + */ + +#ifndef _BLEEddystoneURL_H_ +#define _BLEEddystoneURL_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "BLEUUID.h" +#include +#include "esp_bt.h" + +#define EDDYSTONE_URL_FRAME_TYPE 0x10 + +extern String EDDYSTONE_URL_PREFIX[]; +extern String EDDYSTONE_URL_SUFFIX[]; + +/** + * @brief Representation of a beacon. + * See: + * * https://github.com/google/eddystone + */ +class BLEEddystoneURL { +public: + BLEEddystoneURL(); + BLEEddystoneURL(BLEAdvertisedDevice *advertisedDevice); + String getData(); + String getFrame(); + BLEUUID getUUID(); + int8_t getPower(); + String getURL(); + String getPrefix(); + String getSuffix(); + String getDecodedURL(); + void setData(String data); + void setUUID(BLEUUID l_uuid); + void setPower(int8_t advertisedTxPower); + void setPower(esp_power_level_t advertisedTxPower); + void setURL(String url); + int setSmartURL(String url); + +private: + uint8_t lengthURL; // Describes the length of the URL part including prefix and optional suffix - max 18 B (excluding TX power, frame type and preceding header) + struct { + int8_t advertisedTxPower; + uint8_t url[18]; // Byte [0] is for prefix. Last valid byte **can** contain suffix - i.e. the next byte after the URL + } __attribute__((packed)) m_eddystoneData; + void _initHeadder(); + char BLEHeadder[12]; +}; // BLEEddystoneURL + +#endif /* SOC_BLE_SUPPORTED */ +#endif /* _BLEEddystoneURL_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.h.orig b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.h.orig new file mode 100644 index 0000000..57722d0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEEddystoneURL.h.orig @@ -0,0 +1,66 @@ +/* + * BLEEddystoneURL.cpp + * + * Created on: Mar 12, 2018 + * Author: pcbreflux + * Upgraded on: Feb 17, 2023 + * By: Tomas Pilny + * + */ + +#ifndef _BLEEddystoneURL_H_ +#define _BLEEddystoneURL_H_ +#include "BLEUUID.h" +#include +#include + +#define EDDYSTONE_URL_FRAME_TYPE 0x10 + +extern String EDDYSTONE_URL_PREFIX[]; +extern String EDDYSTONE_URL_SUFFIX[]; + +/** + * @brief Representation of a beacon. + * See: + * * https://github.com/google/eddystone + */ +class BLEEddystoneURL { +public: + BLEEddystoneURL(); + BLEEddystoneURL(BLEAdvertisedDevice *advertisedDevice); + std::string getData(); + String getFrame(); + BLEUUID getUUID(); + int8_t getPower(); + std::string getURL(); + String getPrefix(); + String getSuffix(); + std::string getDecodedURL(); + void setData(std::string data); + void setUUID(BLEUUID l_uuid); + void setPower(int8_t advertisedTxPower); + void setURL(std::string url); + int setSmartURL(String url); + +private: +<<<<<<< Updated upstream + uint16_t beaconUUID; + uint8_t lengthURL; + struct { + uint8_t frameType; + int8_t advertisedTxPower; + uint8_t url[18]; // 18 bytes: 1 byte for URL scheme + up to 17 bytes of URL + } __attribute__((packed)) m_eddystoneData; + +======= + uint8_t lengthURL; // Describes length of URL part including prefix and suffix - max 18 B (excluding TX power, frame type and preceding header) + struct { + int8_t advertisedTxPower; + uint8_t url[18]; // Byte [0] is for prefix. Last byte **can** contain suffix + } __attribute__((packed)) m_eddystoneData; + void _initHeadder(); + char BLEHeadder[12]; +>>>>>>> Stashed changes +}; // BLEEddystoneURL + +#endif /* _BLEEddystoneURL_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEExceptions.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEExceptions.cpp new file mode 100644 index 0000000..549e442 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEExceptions.cpp @@ -0,0 +1,9 @@ +/* + * BLExceptions.cpp + * + * Created on: Nov 27, 2017 + * Author: kolban + */ + +//#include "BLEExceptions.h" + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEExceptions.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEExceptions.h new file mode 100644 index 0000000..1fa1004 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEExceptions.h @@ -0,0 +1,35 @@ +/* + * BLExceptions.h + * + * Created on: Nov 27, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ +#define COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" + +#if CONFIG_CXX_EXCEPTIONS != 1 +#error "C++ exception handling must be enabled within make menuconfig. See Compiler Options > Enable C++ Exceptions." +#endif + +#include + + +class BLEDisconnectedException : public std::exception { + const char* what() const throw () { + return "BLE Disconnected"; + } +}; + +class BLEUuidNotFoundException : public std::exception { + const char* what() const throw () { + return "No such UUID"; + } +}; + +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEEXCEPTIONS_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEHIDDevice.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEHIDDevice.cpp new file mode 100644 index 0000000..27d8804 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEHIDDevice.cpp @@ -0,0 +1,250 @@ +/* + * BLEHIDDevice.cpp + * + * Created on: Jan 03, 2018 + * Author: chegewara + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLEHIDDevice.h" +#include "BLE2904.h" + + +BLEHIDDevice::BLEHIDDevice(BLEServer* server) { + /* + * Here we create mandatory services described in bluetooth specification + */ + m_deviceInfoService = server->createService(BLEUUID((uint16_t) 0x180a)); + m_hidService = server->createService(BLEUUID((uint16_t) 0x1812), 40); + m_batteryService = server->createService(BLEUUID((uint16_t) 0x180f)); + + /* + * Mandatory characteristic for device info service + */ + 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); + + /* + * Mandatory battery level characteristic with notification and presence descriptor + */ + BLE2904* batteryLevelDescriptor = new BLE2904(); + batteryLevelDescriptor->setFormat(BLE2904::FORMAT_UINT8); + batteryLevelDescriptor->setNamespace(1); + batteryLevelDescriptor->setUnit(0x27ad); + + m_batteryLevelCharacteristic = m_batteryService->createCharacteristic((uint16_t) 0x2a19, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY); + m_batteryLevelCharacteristic->addDescriptor(batteryLevelDescriptor); + BLE2902 *batLevelIndicator = new BLE2902(); + // Battery Level Notification is ON by default, making it work always on BLE Pairing and Bonding + batLevelIndicator->setNotifications(true); + m_batteryLevelCharacteristic->addDescriptor(batLevelIndicator); + + /* + * 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); +} + +BLEHIDDevice::~BLEHIDDevice() { +} + +/* + * @brief + */ +void BLEHIDDevice::reportMap(uint8_t* map, uint16_t size) { + m_reportMapCharacteristic->setValue(map, size); +} + +/* + * @brief This function suppose to be called at the end, when we have created all characteristics we need to build HID service + */ +void BLEHIDDevice::startServices() { + m_deviceInfoService->start(); + m_hidService->start(); + m_batteryService->start(); +} + +/* + * @brief Create manufacturer characteristic (this characteristic is optional) + */ +BLECharacteristic* BLEHIDDevice::manufacturer() { + m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ); + return m_manufacturerCharacteristic; +} + +/* + * @brief Set manufacturer name + * @param [in] name manufacturer name + */ +void BLEHIDDevice::manufacturer(String name) { + m_manufacturerCharacteristic->setValue(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 }; + m_pnpCharacteristic->setValue(pnp, sizeof(pnp)); +} + +/* + * @brief + */ +void BLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) { + uint8_t info[] = { 0x11, 0x1, country, flags }; + m_hidInfoCharacteristic->setValue(info, sizeof(info)); +} + +/* + * @brief Create input report characteristic that need to be saved as new characteristic object so can be further used + * @param [in] reportID input report ID, the same as in report map for input object related to created characteristic + * @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)); + 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; +} + +/* + * @brief Create output report characteristic that need to be saved as new characteristic object so can be further used + * @param [in] reportID Output report ID, the same as in report map for output object related to created characteristic + * @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)); + 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); + outputReportCharacteristic->addDescriptor(outputReportDescriptor); + + return outputReportCharacteristic; +} + +/* + * @brief Create feature report characteristic that need to be saved as new characteristic object so can be further used + * @param [in] reportID Feature report ID, the same as in report map for feature object related to created characteristic + * @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)); + + 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); + featureReportCharacteristic->addDescriptor(featureReportDescriptor); + + return featureReportCharacteristic; +} + +/* + * @brief + */ +BLECharacteristic* BLEHIDDevice::bootInput() { + BLECharacteristic* bootInputCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a22, BLECharacteristic::PROPERTY_NOTIFY); + bootInputCharacteristic->addDescriptor(new BLE2902()); + + return bootInputCharacteristic; +} + +/* + * @brief + */ +BLECharacteristic* BLEHIDDevice::bootOutput() { + return m_hidService->createCharacteristic((uint16_t) 0x2a32, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR); +} + +/* + * @brief + */ +BLECharacteristic* BLEHIDDevice::hidControl() { + return m_hidControlCharacteristic; +} + +/* + * @brief + */ +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 + * @ return battery level characteristic + *//* +BLECharacteristic* BLEHIDDevice::batteryLevel() { + return m_batteryLevelCharacteristic; +} + + + +BLECharacteristic* BLEHIDDevice::reportMap() { + return m_reportMapCharacteristic; +} + +BLECharacteristic* BLEHIDDevice::pnp() { + return m_pnpCharacteristic; +} + + +BLECharacteristic* BLEHIDDevice::hidInfo() { + return m_hidInfoCharacteristic; +} +*/ +/* + * @brief + */ +BLEService* BLEHIDDevice::deviceInfo() { + return m_deviceInfoService; +} + +/* + * @brief + */ +BLEService* BLEHIDDevice::hidService() { + return m_hidService; +} + +/* + * @brief + */ +BLEService* BLEHIDDevice::batteryService() { + return m_batteryService; +} + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEHIDDevice.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEHIDDevice.h new file mode 100644 index 0000000..956dbad --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEHIDDevice.h @@ -0,0 +1,81 @@ +/* + * BLEHIDDevice.h + * + * Created on: Jan 03, 2018 + * Author: chegewara + */ + +#ifndef _BLEHIDDEVICE_H_ +#define _BLEHIDDEVICE_H_ + +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include "BLECharacteristic.h" +#include "BLEService.h" +#include "BLEDescriptor.h" +#include "BLE2902.h" +#include "HIDTypes.h" + +#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 +#define HID_BRAILLE_DISPLAY 0x03C9 + +class BLEHIDDevice { +public: + BLEHIDDevice(BLEServer*); + virtual ~BLEHIDDevice(); + + void reportMap(uint8_t* map, uint16_t); + void startServices(); + + BLEService* deviceInfo(); + BLEService* hidService(); + BLEService* batteryService(); + + BLECharacteristic* manufacturer(); + void manufacturer(String name); + //BLECharacteristic* pnp(); + void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version); + //BLECharacteristic* hidInfo(); + void hidInfo(uint8_t country, uint8_t flags); + //BLECharacteristic* batteryLevel(); + void setBatteryLevel(uint8_t level); + + + //BLECharacteristic* reportMap(); + BLECharacteristic* hidControl(); + BLECharacteristic* inputReport(uint8_t reportID); + BLECharacteristic* outputReport(uint8_t reportID); + BLECharacteristic* featureReport(uint8_t reportID); + BLECharacteristic* protocolMode(); + BLECharacteristic* bootInput(); + BLECharacteristic* bootOutput(); + +private: + BLEService* m_deviceInfoService; //0x180a + BLEService* m_hidService; //0x1812 + BLEService* m_batteryService = 0; //0x180f + + BLECharacteristic* m_manufacturerCharacteristic; //0x2a29 + BLECharacteristic* m_pnpCharacteristic; //0x2a50 + BLECharacteristic* m_hidInfoCharacteristic; //0x2a4a + BLECharacteristic* m_reportMapCharacteristic; //0x2a4b + BLECharacteristic* m_hidControlCharacteristic; //0x2a4c + BLECharacteristic* m_protocolModeCharacteristic; //0x2a4e + BLECharacteristic* m_batteryLevelCharacteristic; //0x2a19 +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* _BLEHIDDEVICE_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteCharacteristic.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteCharacteristic.cpp new file mode 100644 index 0000000..9854984 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteCharacteristic.cpp @@ -0,0 +1,627 @@ +/* + * BLERemoteCharacteristic.cpp + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#include "BLERemoteCharacteristic.h" + +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include +#include + +#include +//#include "BLEExceptions.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" +#include "BLERemoteDescriptor.h" +#include "esp32-hal-log.h" + + +/** + * @brief Constructor. + * @param [in] handle The BLE server side handle of this characteristic. + * @param [in] uuid The UUID of this characteristic. + * @param [in] charProp The properties of this characteristic. + * @param [in] pRemoteService A reference to the remote service to which this remote characteristic pertains. + */ +BLERemoteCharacteristic::BLERemoteCharacteristic( + uint16_t handle, + BLEUUID uuid, + esp_gatt_char_prop_t charProp, + BLERemoteService* pRemoteService) { + log_v(">> BLERemoteCharacteristic: handle: %d 0x%d, uuid: %s", handle, handle, uuid.toString().c_str()); + m_handle = handle; + m_uuid = uuid; + m_charProp = charProp; + m_pRemoteService = pRemoteService; + m_notifyCallback = nullptr; + m_rawData = nullptr; + m_auth = ESP_GATT_AUTH_REQ_NONE; + + retrieveDescriptors(); // Get the descriptors for this characteristic + log_v("<< BLERemoteCharacteristic"); +} // BLERemoteCharacteristic + + +/** + *@brief Destructor. + */ +BLERemoteCharacteristic::~BLERemoteCharacteristic() { + removeDescriptors(); // Release resources for any descriptor information we may have allocated. + free(m_rawData); +} // ~BLERemoteCharacteristic + + +/** + * @brief Does the characteristic support broadcasting? + * @return True if the characteristic supports broadcasting. + */ +bool BLERemoteCharacteristic::canBroadcast() { + return (m_charProp & ESP_GATT_CHAR_PROP_BIT_BROADCAST) != 0; +} // canBroadcast + + +/** + * @brief Does the characteristic support indications? + * @return True if the characteristic supports indications. + */ +bool BLERemoteCharacteristic::canIndicate() { + return (m_charProp & ESP_GATT_CHAR_PROP_BIT_INDICATE) != 0; +} // canIndicate + + +/** + * @brief Does the characteristic support notifications? + * @return True if the characteristic supports notifications. + */ +bool BLERemoteCharacteristic::canNotify() { + return (m_charProp & ESP_GATT_CHAR_PROP_BIT_NOTIFY) != 0; +} // canNotify + + +/** + * @brief Does the characteristic support reading? + * @return True if the characteristic supports reading. + */ +bool BLERemoteCharacteristic::canRead() { + return (m_charProp & ESP_GATT_CHAR_PROP_BIT_READ) != 0; +} // canRead + + +/** + * @brief Does the characteristic support writing? + * @return True if the characteristic supports writing. + */ +bool BLERemoteCharacteristic::canWrite() { + return (m_charProp & ESP_GATT_CHAR_PROP_BIT_WRITE) != 0; +} // canWrite + + +/** + * @brief Does the characteristic support writing with no response? + * @return True if the characteristic supports writing with no response. + */ +bool BLERemoteCharacteristic::canWriteNoResponse() { + return (m_charProp & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) != 0; +} // canWriteNoResponse + + +/* +static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { + if (id1.id.inst_id != id2.id.inst_id) { + return false; + } + if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) { + return false; + } + return true; +} // compareSrvcId +*/ + +/* +static bool compareGattId(esp_gatt_id_t id1, esp_gatt_id_t id2) { + if (id1.inst_id != id2.inst_id) { + return false; + } + if (!BLEUUID(id1.uuid).equals(BLEUUID(id2.uuid))) { + return false; + } + return true; +} // compareCharId +*/ + + +/** + * @brief Handle GATT Client events. + * When an event arrives for a GATT client we give this characteristic the opportunity to + * take a look at it to see if there is interest in it. + * @param [in] event The type of event. + * @param [in] gattc_if The interface on which the event was received. + * @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) { + switch(event) { + // ESP_GATTC_NOTIFY_EVT + // + // notify + // - uint16_t conn_id - The connection identifier of the server. + // - esp_bd_addr_t remote_bda - The device address of the BLE server. + // - uint16_t handle - The handle of the characteristic for which the event is being received. + // - uint16_t value_len - The length of the received data. + // - uint8_t* value - The received data. + // - bool is_notify - True if this is a notify, false if it is an indicate. + // + // 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 (m_notifyCallback != nullptr) { + log_d("Invoking callback for notification on characteristic %s", toString().c_str()); + 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. + // + // read: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - 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; + + // 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 = 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 = ""; + } + + m_semaphoreReadCharEvt.give(); + 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; + + // 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; + // 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; + + // 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. + m_semaphoreWriteCharEvt.give(); + break; + } // ESP_GATTC_WRITE_CHAR_EVT + + case ESP_GATTC_READ_DESCR_EVT: + case ESP_GATTC_WRITE_DESCR_EVT: + for (auto &myPair : m_descriptorMap) { + myPair.second->gattClientEventHandler( + event, gattc_if, evtParam); + } + break; + + case ESP_GATTC_DISCONNECT_EVT: + // Cleanup semaphores to avoid deadlocks. + m_semaphoreReadCharEvt.give(1); + m_semaphoreWriteCharEvt.give(1); + break; + + default: + break; + } // End switch +}; // gattClientEventHandler + + +/** + * @brief Populate the descriptors (if any) for this characteristic. + */ +void BLERemoteCharacteristic::retrieveDescriptors() { + log_v(">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str()); + + removeDescriptors(); // Remove any existing descriptors. + + // Loop over each of the descriptors within the service associated with this characteristic. + // For each descriptor we find, create a BLERemoteDescriptor instance. + uint16_t offset = 0; + esp_gattc_descr_elem_t result; + while(true) { + uint16_t count = 10; + esp_gatt_status_t status = ::esp_ble_gattc_get_all_descr( + getRemoteService()->getClient()->getGattcIf(), + getRemoteService()->getClient()->getConnId(), + getHandle(), + &result, + &count, + offset + ); + + if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries. + break; + } + + if (status != ESP_GATT_OK) { + log_e("esp_ble_gattc_get_all_descr: %s", BLEUtils::gattStatusToString(status).c_str()); + break; + } + + if (count == 0) break; + + log_d("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( + result.handle, + BLEUUID(result.uuid), + this + ); + + m_descriptorMap.insert(std::pair(pNewRemoteDescriptor->getUUID().toString(), pNewRemoteDescriptor)); + + offset++; + } // while true + //m_haveCharacteristics = true; // Remember that we have received the characteristics. + log_v("<< retrieveDescriptors(): Found %d descriptors.", offset); +} // getDescriptors + + +/** + * @brief Retrieve the map of descriptors keyed by UUID. + */ +std::map* BLERemoteCharacteristic::getDescriptors() { + return &m_descriptorMap; +} // getDescriptors + + +/** + * @brief Get the handle for this characteristic. + * @return The handle for this characteristic. + */ +uint16_t BLERemoteCharacteristic::getHandle() { + //log_v(">> getHandle: Characteristic: %s", getUUID().toString().c_str()); + //log_v("<< getHandle: %d 0x%.2x", m_handle, m_handle); + return m_handle; +} // getHandle + + +/** + * @brief Get the descriptor instance with the given UUID that belongs to this characteristic. + * @param [in] uuid The UUID of the descriptor to find. + * @return The Remote descriptor (if present) or null if not present. + */ +BLERemoteDescriptor* BLERemoteCharacteristic::getDescriptor(BLEUUID uuid) { + log_v(">> getDescriptor: uuid: %s", uuid.toString().c_str()); + String v = uuid.toString(); + for (auto &myPair : m_descriptorMap) { + if (myPair.first == v) { + log_v("<< getDescriptor: found"); + return myPair.second; + } + } + log_v("<< getDescriptor: Not found"); + return nullptr; +} // getDescriptor + + +/** + * @brief Get the remote service associated with this characteristic. + * @return The remote service associated with this characteristic. + */ +BLERemoteService* BLERemoteCharacteristic::getRemoteService() { + return m_pRemoteService; +} // getRemoteService + + +/** + * @brief Get the UUID for this characteristic. + * @return The UUID for this characteristic. + */ +BLEUUID BLERemoteCharacteristic::getUUID() { + return m_uuid; +} // getUUID + + +/** + * @brief Read an unsigned 16 bit value + * @return The unsigned 16 bit value. + */ +uint16_t BLERemoteCharacteristic::readUInt16() { + String value = readValue(); + if (value.length() >= 2) { + return *(uint16_t*)(value.c_str()); + } + return 0; +} // readUInt16 + + +/** + * @brief Read an unsigned 32 bit value. + * @return the unsigned 32 bit value. + */ +uint32_t BLERemoteCharacteristic::readUInt32() { + String value = readValue(); + if (value.length() >= 4) { + return *(uint32_t*)(value.c_str()); + } + return 0; +} // readUInt32 + + +/** + * @brief Read a byte value + * @return The value as a byte + */ +uint8_t BLERemoteCharacteristic::readUInt8() { + String value = readValue(); + if (value.length() >= 1) { + return (uint8_t)value[0]; + } + return 0; +} // readUInt8 + +/** + * @brief Read a float value. + * @return the float value. + */ +float BLERemoteCharacteristic::readFloat() { + String value = readValue(); + if (value.length() >= 4) { + return *(float*)(value.c_str()); + } + return 0.0; +} // readFloat + +/** + * @brief Read the value of the remote characteristic. + * @return The value of the remote characteristic. + */ +String BLERemoteCharacteristic::readValue() { + log_v(">> readValue(): uuid: %s, handle: %d 0x%.2x", getUUID().toString().c_str(), getHandle(), getHandle()); + + // Check to see that we are connected. + if (!getRemoteService()->getClient()->isConnected()) { + log_e("Disconnected"); + return String(); + } + + m_semaphoreReadCharEvt.take("readValue"); + + // Ask the BLE subsystem to retrieve the value for the remote hosted characteristic. + // This is an asynchronous request which means that we must block waiting for the response + // to become available. + esp_err_t errRc = ::esp_ble_gattc_read_char( + m_pRemoteService->getClient()->getGattcIf(), + m_pRemoteService->getClient()->getConnId(), // The connection ID to the BLE server + getHandle(), // The handle of this characteristic + m_auth); // Security + + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return ""; + } + + // Block waiting for the event that indicates that the read has completed. When it has, the String found + // in m_value will contain our data. + m_semaphoreReadCharEvt.wait("readValue"); + + log_v("<< readValue(): length: %d", m_value.length()); + return m_value; +} // readValue + + +/** + * @brief Register for notifications. + * @param [in] notifyCallback A callback to be invoked for a notification. If NULL is provided then we are + * unregistering a notification. + * @return N/A. + */ +void BLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback, bool notifications, bool descriptorRequiresRegistration) { + log_v(">> registerForNotify(): %s", toString().c_str()); + + m_notifyCallback = notifyCallback; // Save the notification callback. + + m_semaphoreRegForNotifyEvt.take("registerForNotify"); + + if (notifyCallback != nullptr) { // If we have a callback function, then this is a registration. + esp_err_t errRc = ::esp_ble_gattc_register_for_notify( + m_pRemoteService->getClient()->getGattcIf(), + *m_pRemoteService->getClient()->getPeerAddress().getNative(), + getHandle() + ); + + if (errRc != ESP_OK) { + log_e("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 && descriptorRequiresRegistration) + desc->writeValue(val, 2, true); + } // 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( + m_pRemoteService->getClient()->getGattcIf(), + *m_pRemoteService->getClient()->getPeerAddress().getNative(), + getHandle() + ); + + if (errRc != ESP_OK) { + log_e("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 && descriptorRequiresRegistration) + desc->writeValue(val, 2, true); + } // End Unregister + + m_semaphoreRegForNotifyEvt.wait("registerForNotify"); + + log_v("<< registerForNotify()"); +} // registerForNotify + + +/** + * @brief Delete the descriptors in the descriptor map. + * We maintain a map called m_descriptorMap that contains pointers to BLERemoteDescriptors + * object references. Since we allocated these in this class, we are also responsible for deleteing + * them. This method does just that. + * @return N/A. + */ +void BLERemoteCharacteristic::removeDescriptors() { + // Iterate through all the descriptors releasing their storage and erasing them from the map. + for (auto &myPair : m_descriptorMap) { + m_descriptorMap.erase(myPair.first); + delete myPair.second; + } + m_descriptorMap.clear(); // Technically not neeeded, but just to be sure. +} // removeCharacteristics + + +/** + * @brief Convert a BLERemoteCharacteristic to a string representation; + * @return a String representation. + */ +String BLERemoteCharacteristic::toString() { + String res = "Characteristic: uuid: " + m_uuid.toString(); + char val[6]; + res += ", handle: "; + snprintf(val, sizeof(val), "%d", getHandle()); + res += val; + res += " 0x"; + snprintf(val, sizeof(val), "%04x", getHandle()); + res += val; + res += ", props: " + BLEUtils::characteristicPropertiesToString(m_charProp); + return res; +} // 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. + */ +void BLERemoteCharacteristic::writeValue(String newValue, bool response) { + writeValue((uint8_t*)newValue.c_str(), newValue.length(), 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 N/A. + */ +void BLERemoteCharacteristic::writeValue(uint8_t newValue, bool response) { + 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. + */ +void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool response) { + // writeValue(String((char*)data, length), response); + log_v(">> writeValue(), length: %d", length); + + // Check to see that we are connected. + if (!getRemoteService()->getClient()->isConnected()) { + log_e("Disconnected"); + return; + } + + 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(), + length, + data, + response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP, + m_auth + ); + + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_write_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreWriteCharEvt.wait("writeValue"); + + log_v("<< writeValue"); +} // writeValue + +/** + * @brief Read raw data from remote characteristic as hex bytes + * @return return pointer data read + */ +uint8_t* BLERemoteCharacteristic::readRawData() { + return m_rawData; +} + +/** + * @brief Set authentication request type for characteristic + * @param [in] auth Authentication request type. + */ +void BLERemoteCharacteristic::setAuth(esp_gatt_auth_req_t auth) { + m_auth = auth; +} + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteCharacteristic.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteCharacteristic.h new file mode 100644 index 0000000..1ba4ec3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteCharacteristic.h @@ -0,0 +1,90 @@ +/* + * BLERemoteCharacteristic.h + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ +#define COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include + +#include + +#include "BLERemoteService.h" +#include "BLERemoteDescriptor.h" +#include "BLEUUID.h" +#include "RTOS.h" + +class BLERemoteService; +class BLERemoteDescriptor; +typedef std::function notify_callback; +/** + * @brief A model of a remote %BLE characteristic. + */ +class BLERemoteCharacteristic { +public: + ~BLERemoteCharacteristic(); + + // Public member functions + bool canBroadcast(); + bool canIndicate(); + bool canNotify(); + bool canRead(); + bool canWrite(); + bool canWriteNoResponse(); + BLERemoteDescriptor* getDescriptor(BLEUUID uuid); + std::map* getDescriptors(); + BLERemoteService* getRemoteService(); + uint16_t getHandle(); + BLEUUID getUUID(); + String readValue(); + uint8_t readUInt8(); + uint16_t readUInt16(); + uint32_t readUInt32(); + float readFloat(); + void registerForNotify(notify_callback _callback, bool notifications = true, bool descriptorRequiresRegistration = true); + void writeValue(uint8_t* data, size_t length, bool response = false); + void writeValue(String newValue, bool response = false); + void writeValue(uint8_t newValue, bool response = false); + String toString(); + uint8_t* readRawData(); + void setAuth(esp_gatt_auth_req_t auth); + +private: + BLERemoteCharacteristic(uint16_t handle, BLEUUID uuid, esp_gatt_char_prop_t charProp, BLERemoteService* pRemoteService); + friend class BLEClient; + friend class BLERemoteService; + 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 removeDescriptors(); + void retrieveDescriptors(); + + // Private properties + BLEUUID m_uuid; + esp_gatt_char_prop_t m_charProp; + esp_gatt_auth_req_t m_auth; + uint16_t m_handle; + BLERemoteService* m_pRemoteService; + FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt"); + FreeRTOS::Semaphore m_semaphoreRegForNotifyEvt = FreeRTOS::Semaphore("RegForNotifyEvt"); + FreeRTOS::Semaphore m_semaphoreWriteCharEvt = FreeRTOS::Semaphore("WriteCharEvt"); + String m_value; + uint8_t *m_rawData; + notify_callback m_notifyCallback; + + // We maintain a map of descriptors owned by this characteristic keyed by a string representation of the UUID. + std::map m_descriptorMap; +}; // BLERemoteCharacteristic + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEREMOTECHARACTERISTIC_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.cpp new file mode 100644 index 0000000..92554e3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.cpp @@ -0,0 +1,225 @@ +/* + * BLERemoteDescriptor.cpp + * + * Created on: Jul 8, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include "BLERemoteDescriptor.h" +#include "GeneralUtils.h" +#include "esp32-hal-log.h" + +BLERemoteDescriptor::BLERemoteDescriptor( + uint16_t handle, + BLEUUID uuid, + BLERemoteCharacteristic* pRemoteCharacteristic) { + + m_handle = handle; + m_uuid = uuid; + m_pRemoteCharacteristic = pRemoteCharacteristic; + m_auth = ESP_GATT_AUTH_REQ_NONE; +} + + +/** + * @brief Retrieve the handle associated with this remote descriptor. + * @return The handle associated with this remote descriptor. + */ +uint16_t BLERemoteDescriptor::getHandle() { + return m_handle; +} // getHandle + + +/** + * @brief Get the characteristic that owns this descriptor. + * @return The characteristic that owns this descriptor. + */ +BLERemoteCharacteristic* BLERemoteDescriptor::getRemoteCharacteristic() { + return m_pRemoteCharacteristic; +} // getRemoteCharacteristic + + +/** + * @brief Retrieve the UUID associated this remote descriptor. + * @return The UUID associated this remote descriptor. + */ +BLEUUID BLERemoteDescriptor::getUUID() { + return m_uuid; +} // getUUID + +void BLERemoteDescriptor::gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) { + switch(event) { + // ESP_GATTC_READ_DESCR_EVT + // This event indicates that the server has responded to the read request. + // + // read: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - uint16_t handle + // - uint8_t* value + // - uint16_t value_len + case ESP_GATTC_READ_DESCR_EVT: + // If this event is not for us, then nothing further to do. + if (evtParam->read.handle != getHandle()) break; + // At this point, we have determined that the event is for us, so now we save the value + if (evtParam->read.status == ESP_GATT_OK) { + // it will read the cached value of the descriptor + m_value = String((char*) evtParam->read.value, evtParam->read.value_len); + } else { + m_value = ""; + } + // Unlock the semaphore to ensure that the requestor of the data can continue. + m_semaphoreReadDescrEvt.give(); + break; + + case ESP_GATTC_WRITE_DESCR_EVT: + if (evtParam->write.handle != getHandle()) + break; + m_semaphoreWriteDescrEvt.give(); + break; + default: + break; + } +} + +String BLERemoteDescriptor::readValue() { + log_v(">> readValue: %s", toString().c_str()); + + // Check to see that we are connected. + if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) { + log_e("Disconnected"); + return String(); + } + + m_semaphoreReadDescrEvt.take("readValue"); + + // Ask the BLE subsystem to retrieve the value for the remote hosted characteristic. + esp_err_t errRc = ::esp_ble_gattc_read_char_descr( + m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(), + m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(), // The connection ID to the BLE server + getHandle(), // The handle of this characteristic + m_auth); // Security + + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return ""; + } + + // Block waiting for the event that indicates that the read has completed. When it has, the String found + // in m_value will contain our data. + m_semaphoreReadDescrEvt.wait("readValue"); + + log_v("<< readValue(): length: %d", m_value.length()); + return m_value; +} // readValue + + +uint8_t BLERemoteDescriptor::readUInt8() { + String value = readValue(); + if (value.length() >= 1) { + return (uint8_t) value[0]; + } + return 0; +} // readUInt8 + + +uint16_t BLERemoteDescriptor::readUInt16() { + String value = readValue(); + if (value.length() >= 2) { + return *(uint16_t*) value.c_str(); + } + return 0; +} // readUInt16 + + +uint32_t BLERemoteDescriptor::readUInt32() { + String value = readValue(); + if (value.length() >= 4) { + return *(uint32_t*) value.c_str(); + } + return 0; +} // readUInt32 + + +/** + * @brief Return a string representation of this BLE Remote Descriptor. + * @retun A string representation of this BLE Remote Descriptor. + */ +String BLERemoteDescriptor::toString() { + char val[6]; + snprintf(val, sizeof(val), "%d", getHandle()); + String res = "handle: "; + res += val; + res += ", uuid: " + getUUID().toString(); + return res; +} // toString + + +/** + * @brief Write data to the BLE Remote Descriptor. + * @param [in] data The data to send to the remote descriptor. + * @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) { + log_v(">> writeValue: %s", toString().c_str()); + // Check to see that we are connected. + if (!getRemoteCharacteristic()->getRemoteService()->getClient()->isConnected()) { + log_e("Disconnected"); + return; + } + + m_semaphoreWriteDescrEvt.take("writeValue"); + + esp_err_t errRc = ::esp_ble_gattc_write_char_descr( + m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(), + m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(), + getHandle(), + length, // Data length + data, // Data + response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, + m_auth + ); + if (errRc != ESP_OK) { + log_e("esp_ble_gattc_write_char_descr: %d", errRc); + } + + m_semaphoreWriteDescrEvt.wait("writeValue"); + log_v("<< writeValue"); +} // writeValue + + +/** + * @brief Write data represented as a string to the BLE Remote Descriptor. + * @param [in] newValue The data to send to the remote descriptor. + * @param [in] response True if we expect a response. + */ +void BLERemoteDescriptor::writeValue(String newValue, bool response) { + writeValue((uint8_t*) newValue.c_str(), newValue.length(), response); +} // writeValue + + +/** + * @brief Write a byte value to the Descriptor. + * @param [in] The single byte to write. + * @param [in] True if we expect a response. + */ +void BLERemoteDescriptor::writeValue(uint8_t newValue, bool response) { + writeValue(&newValue, 1, response); +} // writeValue + +/** + * @brief Set authentication request type for characteristic + * @param [in] auth Authentication request type. + */ +void BLERemoteDescriptor::setAuth(esp_gatt_auth_req_t auth) { + m_auth = auth; +} + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.h new file mode 100644 index 0000000..5b9cb35 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteDescriptor.h @@ -0,0 +1,63 @@ +/* + * BLERemoteDescriptor.h + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ +#define COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include + +#include + +#include "BLERemoteCharacteristic.h" +#include "BLEUUID.h" +#include "RTOS.h" + +class BLERemoteCharacteristic; +/** + * @brief A model of remote %BLE descriptor. + */ +class BLERemoteDescriptor { +public: + uint16_t getHandle(); + BLERemoteCharacteristic* getRemoteCharacteristic(); + BLEUUID getUUID(); + String readValue(void); + uint8_t readUInt8(void); + uint16_t readUInt16(void); + uint32_t readUInt32(void); + String toString(void); + void writeValue(uint8_t* data, size_t length, bool response = false); + void writeValue(String newValue, bool response = false); + void writeValue(uint8_t newValue, bool response = false); + void setAuth(esp_gatt_auth_req_t auth); + void gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam); + +private: + friend class BLERemoteCharacteristic; + BLERemoteDescriptor( + uint16_t handle, + BLEUUID uuid, + BLERemoteCharacteristic* pRemoteCharacteristic + ); + uint16_t m_handle; // Server handle of this descriptor. + BLEUUID m_uuid; // UUID of this descriptor. + String m_value; // Last received value of the descriptor. + BLERemoteCharacteristic* m_pRemoteCharacteristic; // Reference to the Remote characteristic of which this descriptor is associated. + FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt"); + FreeRTOS::Semaphore m_semaphoreWriteDescrEvt = FreeRTOS::Semaphore("WriteDescrEvt"); + esp_gatt_auth_req_t m_auth; + + +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEREMOTEDESCRIPTOR_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteService.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteService.cpp new file mode 100644 index 0000000..8746877 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteService.cpp @@ -0,0 +1,367 @@ +/* + * BLERemoteService.cpp + * + * Created on: Jul 8, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include +#include "BLERemoteService.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" +#include +#include "esp32-hal-log.h" + +#pragma GCC diagnostic warning "-Wunused-but-set-parameter" + +BLERemoteService::BLERemoteService( + esp_gatt_id_t srvcId, + BLEClient* pClient, + uint16_t startHandle, + uint16_t endHandle + ) { + + log_v(">> BLERemoteService()"); + m_srvcId = srvcId; + m_pClient = pClient; + m_uuid = BLEUUID(m_srvcId); + m_haveCharacteristics = false; + m_startHandle = startHandle; + m_endHandle = endHandle; + + log_v("<< BLERemoteService()"); +} + + +BLERemoteService::~BLERemoteService() { + removeCharacteristics(); +} + +/* +static bool compareSrvcId(esp_gatt_srvc_id_t id1, esp_gatt_srvc_id_t id2) { + if (id1.id.inst_id != id2.id.inst_id) { + return false; + } + if (!BLEUUID(id1.id.uuid).equals(BLEUUID(id2.id.uuid))) { + return false; + } + return true; +} // compareSrvcId +*/ + +/** + * @brief Handle GATT Client events + */ +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) { + log_e("esp_ble_gattc_get_characteristic: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + break; + } + + //m_semaphoreGetCharEvt.give(); + 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_characteristicMapByHandle) { + myPair.second->gattClientEventHandler(event, gattc_if, evtParam); + } +} // gattClientEventHandler + + +/** + * @brief Get the remote characteristic object for the characteristic UUID. + * @param [in] uuid Remote characteristic uuid. + * @return Reference to the remote characteristic object. + * @throws BLEUuidNotFoundException + */ +BLERemoteCharacteristic* BLERemoteService::getCharacteristic(const char* uuid) { + return getCharacteristic(BLEUUID(uuid)); +} // getCharacteristic + +/** + * @brief Get the characteristic object for the UUID. + * @param [in] uuid Characteristic uuid. + * @return Reference to the characteristic object. + * @throws BLEUuidNotFoundException + */ +BLERemoteCharacteristic* BLERemoteService::getCharacteristic(BLEUUID uuid) { +// Design +// ------ +// We wish to retrieve the characteristic given its UUID. It is possible that we have not yet asked the +// device what characteristics it has in which case we have nothing to match against. If we have not +// asked the device about its characteristics, then we do that now. Once we get the results we can then +// examine the characteristics map to see if it has the characteristic we are looking for. + if (!m_haveCharacteristics) { + retrieveCharacteristics(); + } + String v = uuid.toString(); + for (auto &myPair : m_characteristicMap) { + if (myPair.first == v) { + return myPair.second; + } + } + // 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 + + +/** + * @brief Retrieve all the characteristics for this service. + * This function will not return until we have all the characteristics. + * @return N/A + */ +void BLERemoteService::retrieveCharacteristics() { + log_v(">> getCharacteristics() for service: %s", getUUID().toString().c_str()); + + removeCharacteristics(); // Forget any previous characteristics. + + uint16_t offset = 0; + esp_gattc_char_elem_t result; + while (true) { + uint16_t count = 1; // only room for 1 result allocated, so go one by one + esp_gatt_status_t status = ::esp_ble_gattc_get_all_char( + getClient()->getGattcIf(), + getClient()->getConnId(), + m_startHandle, + m_endHandle, + &result, + &count, + offset + ); + + if (status == ESP_GATT_INVALID_OFFSET) { // We have reached the end of the entries. + break; + } + + if (status != ESP_GATT_OK) { // If we got an error, end. + log_e("esp_ble_gattc_get_all_char: %s", BLEUtils::gattStatusToString(status).c_str()); + break; + } + + if (count == 0) { // If we failed to get any new records, end. + break; + } + + log_d("Found a characteristic: Handle: %d, UUID: %s", result.char_handle, BLEUUID(result.uuid).toString().c_str()); + + // We now have a new characteristic ... let us add that to our set of known characteristics + BLERemoteCharacteristic *pNewRemoteCharacteristic = new BLERemoteCharacteristic( + result.char_handle, + BLEUUID(result.uuid), + result.properties, + this + ); + + 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. + log_v("<< getCharacteristics()"); +} // 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::getCharacteristics() { + log_v(">> 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 + // call and does not return until all the characteristics are available. + if (!m_haveCharacteristics) { + retrieveCharacteristics(); + } + log_v("<< getCharacteristics() for service: %s", getUUID().toString().c_str()); + 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() { + // 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(); + } + 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) { + log_v(">> getCharacteristics() for service: %s", getUUID().toString().c_str()); + (void)pCharacteristicMap; + // 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(); + } + log_v("<< getCharacteristics() for service: %s", getUUID().toString().c_str()); + *pCharacteristicMap = &m_characteristicMapByHandle; +} // Get the characteristics map. + +/** + * @brief Get the client associated with this service. + * @return A reference to the client associated with this service. + */ +BLEClient* BLERemoteService::getClient() { + return m_pClient; +} // getClient + + +uint16_t BLERemoteService::getEndHandle() { + return m_endHandle; +} // getEndHandle + + +esp_gatt_id_t* BLERemoteService::getSrvcId() { + return &m_srvcId; +} // getSrvcId + + +uint16_t BLERemoteService::getStartHandle() { + return m_startHandle; +} // getStartHandle + + +uint16_t BLERemoteService::getHandle() { + log_v(">> getHandle: service: %s", getUUID().toString().c_str()); + log_v("<< getHandle: %d 0x%.2x", getStartHandle(), getStartHandle()); + return getStartHandle(); +} // getHandle + + +BLEUUID BLERemoteService::getUUID() { + return m_uuid; +} + +/** + * @brief Read the value of a characteristic associated with this service. + */ +String BLERemoteService::getValue(BLEUUID characteristicUuid) { + log_v(">> readValue: uuid: %s", characteristicUuid.toString().c_str()); + String ret = getCharacteristic(characteristicUuid)->readValue(); + log_v("<< readValue"); + return ret; +} // readValue + + + +/** + * @brief Delete the characteristics in the characteristics map. + * We maintain a map called m_characteristicsMap that contains pointers to BLERemoteCharacteristic + * object references. Since we allocated these in this class, we are also responsible for deleteing + * them. This method does just that. + * @return N/A. + */ +void BLERemoteService::removeCharacteristics() { + m_characteristicMap.clear(); // Clear the map + for (auto &myPair : m_characteristicMapByHandle) { + delete myPair.second; + // delete the characteristics only once + } + m_characteristicMapByHandle.clear(); // Clear the map +} // removeCharacteristics + + +/** + * @brief Set the value of a characteristic. + * @param [in] characteristicUuid The characteristic to set. + * @param [in] value The value to set. + * @throws BLEUuidNotFound + */ +void BLERemoteService::setValue(BLEUUID characteristicUuid, String value) { + log_v(">> setValue: uuid: %s", characteristicUuid.toString().c_str()); + getCharacteristic(characteristicUuid)->writeValue(value); + log_v("<< setValue"); +} // setValue + + +/** + * @brief Create a string representation of this remote service. + * @return A string representation of this remote service. + */ +String BLERemoteService::toString() { + String res = "Service: uuid: " + m_uuid.toString(); + char val[6]; + res += ", start_handle: "; + snprintf(val, sizeof(val), "%d", m_startHandle); + res += val; + snprintf(val, sizeof(val), "%04x", m_startHandle); + res += " 0x"; + res += val; + res += ", end_handle: "; + snprintf(val, sizeof(val), "%d", m_endHandle); + res += val; + snprintf(val, sizeof(val), "%04x", m_endHandle); + res += " 0x"; + res += val; + for (auto &myPair : m_characteristicMap) { + res += "\n" + myPair.second->toString(); + // myPair.second is the value + } + return res; +} // toString + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteService.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteService.h new file mode 100644 index 0000000..6907260 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLERemoteService.h @@ -0,0 +1,89 @@ +/* + * BLERemoteService.h + * + * Created on: Jul 8, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ +#define COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include + +#include "BLEClient.h" +#include "BLERemoteCharacteristic.h" +#include "BLEUUID.h" +#include "RTOS.h" + +class BLEClient; +class BLERemoteCharacteristic; + + +/** + * @brief A model of a remote %BLE service. + */ +class BLERemoteService { +public: + virtual ~BLERemoteService(); + + // Public methods + BLERemoteCharacteristic* getCharacteristic(const char* uuid); // Get the specified characteristic reference. + BLERemoteCharacteristic* getCharacteristic(BLEUUID uuid); // Get the specified characteristic reference. + BLERemoteCharacteristic* getCharacteristic(uint16_t uuid); // Get the specified characteristic reference. + std::map* getCharacteristics(); + 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. + BLEUUID getUUID(void); // Get the UUID of this service. + String getValue(BLEUUID characteristicUuid); // Get the value of a characteristic. + void setValue(BLEUUID characteristicUuid, String value); // Set the value of a characteristic. + String toString(void); + +private: + // Private constructor ... never meant to be created by a user application. + BLERemoteService(esp_gatt_id_t srvcId, BLEClient* pClient, uint16_t startHandle, uint16_t endHandle); + + // Friends + friend class BLEClient; + friend class BLERemoteCharacteristic; + + // Private methods + void retrieveCharacteristics(void); // Retrieve the characteristics from the BLE Server. + esp_gatt_id_t* getSrvcId(void); + uint16_t getStartHandle(); // Get the start handle for this service. + uint16_t getEndHandle(); // Get the end handle for this service. + + void gattClientEventHandler( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam); + + void removeCharacteristics(); + + // Properties + + // We maintain a map of characteristics owned by this service keyed by a string representation of the UUID. + std::map m_characteristicMap; + + // We maintain a map of characteristics owned by this service keyed by a handle. + std::map m_characteristicMapByHandle; + + bool m_haveCharacteristics; // Have we previously obtained the characteristics. + BLEClient* m_pClient; + FreeRTOS::Semaphore m_semaphoreGetCharEvt = FreeRTOS::Semaphore("GetCharEvt"); + esp_gatt_id_t m_srvcId; + BLEUUID m_uuid; // The UUID of this service. + uint16_t m_startHandle; // The starting handle of this service. + uint16_t m_endHandle; // The ending handle of this service. +}; // BLERemoteService + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEREMOTESERVICE_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEScan.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEScan.cpp new file mode 100644 index 0000000..87d0deb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEScan.cpp @@ -0,0 +1,515 @@ +/* + * BLEScan.cpp + * + * Created on: Jul 1, 2017 + * Author: kolban + * + * Update: April, 2021 + * add BLE5 support + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include + +#include + +#include "BLEAdvertisedDevice.h" +#include "BLEScan.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" +#include "esp32-hal-log.h" + +/** + * Constructor + */ +BLEScan::BLEScan() { + memset(&m_scan_params, 0, sizeof(m_scan_params)); // Initialize all params + m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; // Default is a passive scan. + m_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC; + m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL; + m_scan_params.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE; + m_pAdvertisedDeviceCallbacks = nullptr; + m_stopped = true; + m_wantDuplicates = false; + m_shouldParse = true; + setInterval(100); + setWindow(100); +} // BLEScan + + +/** + * @brief Handle GAP events related to scans. + * @param [in] event The event type for this event. + * @param [in] param Parameter data for this event. + */ +void BLEScan::handleGAPEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param) { + + switch(event) { + + // --------------------------- + // 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) { + // + // ESP_GAP_SEARCH_INQ_CMPL_EVT + // + // 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: { + log_w("ESP_GAP_SEARCH_INQ_CMPL_EVT"); + m_stopped = true; + m_semaphoreScanEnd.give(); + if (m_scanCompleteCB != nullptr) { + m_scanCompleteCB(m_scanResults); + } + break; + } // ESP_GAP_SEARCH_INQ_CMPL_EVT + + // + // ESP_GAP_SEARCH_INQ_RES_EVT + // + // Result that has arrived back from a Scan inquiry. + case ESP_GAP_SEARCH_INQ_RES_EVT: { + if (m_stopped) { // If we are not scanning, nothing to do with the extra results. + break; + } + +// Examine our list of previously scanned addresses and, if we found this one already, +// ignore it. + BLEAddress advertisedAddress(param->scan_rst.bda); + bool found = false; + bool shouldDelete = true; + + if (!m_wantDuplicates) { + if (m_scanResults.m_vectorAdvertisedDevices.count(advertisedAddress.toString()) != 0) { + found = true; + } + + if (found) { // If we found a previous entry AND we don't want duplicates, then we are done. + log_d("Ignoring %s, already seen it.", advertisedAddress.toString().c_str()); + vTaskDelay(1); // <--- allow to switch task in case we scan infinity and dont have new devices to report, or we are blocked here + break; + } + } + + // We now construct a model of the advertised device that we have just found for the first + // time. + // ESP_LOG_BUFFER_HEXDUMP((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len, ESP_LOG_DEBUG); + // log_w("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); + if (m_shouldParse) { + advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len); + } else { + advertisedDevice->setPayload((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) { // if has callback, no need to record to vector + m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice); + } + if (!m_wantDuplicates && !found) { // if no callback and not want duplicate, and not already in vector, record it + m_scanResults.m_vectorAdvertisedDevices.insert(std::pair(advertisedAddress.toString(), advertisedDevice)); + shouldDelete = false; + } + if (shouldDelete) { + delete advertisedDevice; + } + + break; + } // ESP_GAP_SEARCH_INQ_RES_EVT + + default: { + break; + } + } // switch - search_evt + + + break; + } // ESP_GAP_BLE_SCAN_RESULT_EVT +#ifdef SOC_BLE_50_SUPPORTED + case ESP_GAP_BLE_EXT_ADV_REPORT_EVT: { + if (param->ext_adv_report.params.event_type & ESP_BLE_GAP_SET_EXT_ADV_PROP_LEGACY) { + log_v("legacy adv, adv type 0x%x data len %d", param->ext_adv_report.params.event_type, param->ext_adv_report.params.adv_data_len); + } + else { + log_v("extend adv, adv type 0x%x data len %d, data status: %d", param->ext_adv_report.params.event_type, param->ext_adv_report.params.adv_data_len, param->ext_adv_report.params.data_status); + } + + if (m_pExtendedScanCb != nullptr) + { + m_pExtendedScanCb->onResult(param->ext_adv_report.params); + } + + break; + } + + case ESP_GAP_BLE_SET_EXT_SCAN_PARAMS_COMPLETE_EVT: { + if (param->set_ext_scan_params.status != ESP_BT_STATUS_SUCCESS) { + log_e("extend scan parameters set failed, error status = %x", param->set_ext_scan_params.status); + break; + } + log_v("extend scan params set successfully"); + break; + } + + case ESP_GAP_BLE_EXT_SCAN_START_COMPLETE_EVT: + if (param->ext_scan_start.status != ESP_BT_STATUS_SUCCESS) { + log_e("scan start failed, error status = %x", param->scan_start_cmpl.status); + break; + } + log_v("Scan start success"); + break; + + case ESP_GAP_BLE_EXT_SCAN_STOP_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onStop(param->ext_scan_stop.status); + } + + if (param->ext_scan_stop.status != ESP_BT_STATUS_SUCCESS){ + log_e("extend Scan stop failed, error status = %x", param->ext_scan_stop.status); + break; + } + log_v("Stop extend scan successfully"); + break; + + case ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onCreateSync(param->period_adv_create_sync.status); + } + + log_v("ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT, status %d", param->period_adv_create_sync.status); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onCancelSync(param->period_adv_sync_cancel.status); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_CANCEL_COMPLETE_EVT, status %d", param->period_adv_sync_cancel.status); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onTerminateSync(param->period_adv_sync_term.status); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_TERMINATE_COMPLETE_EVT, status %d", param->period_adv_sync_term.status); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onLostSync(param->periodic_adv_sync_lost.sync_handle); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_LOST_EVT, sync handle %d", param->periodic_adv_sync_lost.sync_handle); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onSync(*(esp_ble_periodic_adv_sync_estab_param_t*)¶m->periodic_adv_sync_estab); + } + log_v("ESP_GAP_BLE_PERIODIC_ADV_SYNC_ESTAB_EVT, status %d", param->periodic_adv_sync_estab.status); + break; + + case ESP_GAP_BLE_PERIODIC_ADV_REPORT_EVT: + if (m_pPeriodicScanCb != nullptr) + { + m_pPeriodicScanCb->onReport(param->period_adv_report.params); + } + break; + +#endif // SOC_BLE_50_SUPPORTED + + default: { + break; + } // default + } // End switch +} // gapEventHandler + + +/** + * @brief Should we perform an active or passive scan? + * The default is a passive scan. An active scan means that we will wish a scan response. + * @param [in] active If true, we perform an active scan otherwise a passive scan. + * @return N/A. + */ +void BLEScan::setActiveScan(bool active) { + if (active) { + m_scan_params.scan_type = BLE_SCAN_TYPE_ACTIVE; + } else { + m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; + } +} // setActiveScan + + +/** + * @brief Set the call backs to be invoked. + * @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked. + * @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false. + * @param [in] shouldParse True if we wish to parse advertised package or raw payload. Default is true. + */ +void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates, bool shouldParse) { + m_wantDuplicates = wantDuplicates; + m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks; + m_shouldParse = shouldParse; +} // setAdvertisedDeviceCallbacks + +#ifdef SOC_BLE_50_SUPPORTED + +void BLEScan::setExtendedScanCallback(BLEExtAdvertisingCallbacks* cb) +{ + m_pExtendedScanCb = cb; +} + +/** +* @brief This function is used to set the extended scan parameters to be used on the advertising channels. +* +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t BLEScan::setExtScanParams() +{ + esp_ble_ext_scan_params_t ext_scan_params = { + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, + .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE, + .cfg_mask = ESP_BLE_GAP_EXT_SCAN_CFG_UNCODE_MASK | ESP_BLE_GAP_EXT_SCAN_CFG_CODE_MASK, + .uncoded_cfg = {BLE_SCAN_TYPE_ACTIVE, 40, 40}, + .coded_cfg = {BLE_SCAN_TYPE_ACTIVE, 40, 40}, + }; + + esp_err_t rc = esp_ble_gap_set_ext_scan_params(&ext_scan_params); + if (rc) { + log_e("set extend scan params error, error code = %x", rc); + } + return rc; +} + +/** +* @brief This function is used to set the extended scan parameters to be used on the advertising channels. +* +* @param[in] params : scan parameters +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t BLEScan::setExtScanParams(esp_ble_ext_scan_params_t* ext_scan_params) +{ + esp_err_t rc = esp_ble_gap_set_ext_scan_params(ext_scan_params); + if (rc) { + log_e("set extend scan params error, error code = %x", rc); + } + return rc; +} + +/** +* @brief This function is used to enable scanning. +* +* @param[in] duration : Scan duration +* @param[in] period : Time interval from when the Controller started its last Scan Duration until it begins the subsequent Scan Duration. +* +* @return - ESP_OK : success +* - other : failed +* +*/ +esp_err_t BLEScan::startExtScan(uint32_t duration, uint16_t period) +{ + esp_err_t rc = esp_ble_gap_start_ext_scan(duration, period); + if(rc) log_e("extended scan start failed: %d", rc); + return rc; +} + + +esp_err_t BLEScan::stopExtScan() +{ + esp_err_t rc; + rc = esp_ble_gap_stop_ext_scan(); + + return rc; +} + +void BLEScan::setPeriodicScanCallback(BLEPeriodicScanCallbacks* cb) +{ + m_pPeriodicScanCb = cb; +} + +#endif // SOC_BLE_50_SUPPORTED +/** + * @brief Set the interval to scan. + * @param [in] The interval in msecs. + */ +void BLEScan::setInterval(uint16_t intervalMSecs) { + m_scan_params.scan_interval = intervalMSecs / 0.625; +} // setInterval + + +/** + * @brief Set the window to actively scan. + * @param [in] windowMSecs How long to actively scan. + */ +void BLEScan::setWindow(uint16_t windowMSecs) { + m_scan_params.scan_window = windowMSecs / 0.625; +} // setWindow + + +/** + * @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 is_continue) { + log_v(">> start(duration=%d)", duration); + + m_semaphoreScanEnd.take(String("start")); + m_scanCompleteCB = scanCompleteCB; // Save the callback to be invoked when the scan completes. + + // 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); + + if (errRc != ESP_OK) { + log_e("esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); + m_semaphoreScanEnd.give(); + return false; + } + + errRc = ::esp_ble_gap_start_scanning(duration); + + if (errRc != ESP_OK) { + log_e("esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); + m_semaphoreScanEnd.give(); + return false; + } + + m_stopped = false; + + log_v("<< start()"); + return true; +} // start + + +/** + * @brief Start scanning and block until scanning has been completed. + * @param [in] duration The duration in seconds for which to scan. + * @return The BLEScanResults. + */ +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; +} // start + + +/** + * @brief Stop an in progress scan. + * @return N/A. + */ +void BLEScan::stop() { + log_v(">> stop()"); + + esp_err_t errRc = ::esp_ble_gap_stop_scanning(); + + m_stopped = true; + m_semaphoreScanEnd.give(); + + if (errRc != ESP_OK) { + log_e("esp_ble_gap_stop_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + log_v("<< 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) { + log_i("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. + */ +void BLEScanResults::dump() { + log_v(">> Dump scan results:"); + for (int i=0; isecond; + 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_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEScan.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEScan.h new file mode 100644 index 0000000..1e35586 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEScan.h @@ -0,0 +1,126 @@ +/* + * BLEScan.h + * + * Created on: Jul 1, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESCAN_H_ +#define COMPONENTS_CPP_UTILS_BLESCAN_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include + +// #include +#include +#include "BLEAdvertisedDevice.h" +#include "BLEClient.h" +#include "RTOS.h" + +class BLEAdvertisedDevice; +class BLEAdvertisedDeviceCallbacks; +class BLEExtAdvertisingCallbacks; +class BLEClient; +class BLEScan; +class BLEPeriodicScanCallbacks; + +struct esp_ble_periodic_adv_sync_estab_param_t { + uint8_t status; /*!< periodic advertising sync status */ + uint16_t sync_handle; /*!< periodic advertising sync handle */ + uint8_t sid; /*!< periodic advertising sid */ + esp_ble_addr_type_t adv_addr_type; /*!< periodic advertising address type */ + esp_bd_addr_t adv_addr; /*!< periodic advertising address */ + esp_ble_gap_phy_t adv_phy; /*!< periodic advertising phy type */ + uint16_t period_adv_interval; /*!< periodic advertising interval */ + uint8_t adv_clk_accuracy; /*!< periodic advertising clock accuracy */ +}; + +/** + * @brief The result of having performed a scan. + * When a scan completes, we have a set of found devices. Each device is described + * by a BLEAdvertisedDevice object. The number of items in the set is given by + * getCount(). We can retrieve a device by calling getDevice() passing in the + * index (starting at 0) of the desired device. + */ +class BLEScanResults { +public: + void dump(); + int getCount(); + BLEAdvertisedDevice getDevice(uint32_t i); + +private: + friend BLEScan; + std::map m_vectorAdvertisedDevices; +}; + +/** + * @brief Perform and manage %BLE scans. + * + * Scanning is associated with a %BLE client that is attempting to locate BLE servers. + */ +class BLEScan { +public: + void setActiveScan(bool active); + void setAdvertisedDeviceCallbacks( + BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, + bool wantDuplicates = false, + bool shouldParse = true); + void setInterval(uint16_t intervalMSecs); + void setWindow(uint16_t windowMSecs); + 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(); + +#ifdef SOC_BLE_50_SUPPORTED + void setExtendedScanCallback(BLEExtAdvertisingCallbacks* cb); + void setPeriodicScanCallback(BLEPeriodicScanCallbacks* cb); + + esp_err_t stopExtScan(); + esp_err_t setExtScanParams(); + esp_err_t setExtScanParams(esp_ble_ext_scan_params_t* ext_scan_params); + esp_err_t startExtScan(uint32_t duration, uint16_t period); +private: + BLEExtAdvertisingCallbacks* m_pExtendedScanCb = nullptr; + BLEPeriodicScanCallbacks* m_pPeriodicScanCb = nullptr; +#endif // SOC_BLE_50_SUPPORTED + +private: + BLEScan(); // One doesn't create a new instance instead one asks the BLEDevice for the singleton. + friend class BLEDevice; + void handleGAPEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param); + + + esp_ble_scan_params_t m_scan_params; + BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr; + bool m_stopped = true; + bool m_shouldParse = true; + FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd"); + BLEScanResults m_scanResults; + bool m_wantDuplicates; + void (*m_scanCompleteCB)(BLEScanResults scanResults); +}; // BLEScan + +class BLEPeriodicScanCallbacks { +public: + virtual ~BLEPeriodicScanCallbacks() {} + + virtual void onCreateSync(esp_bt_status_t status) {} + virtual void onCancelSync(esp_bt_status_t status) {} + virtual void onTerminateSync(esp_bt_status_t status) {} + virtual void onLostSync(uint16_t sync_handle) {} + virtual void onSync(esp_ble_periodic_adv_sync_estab_param_t) {} + virtual void onReport(esp_ble_gap_periodic_adv_report_t params) {} + virtual void onStop(esp_bt_status_t status) {} +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLESCAN_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLESecurity.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLESecurity.cpp new file mode 100644 index 0000000..8437ee7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLESecurity.cpp @@ -0,0 +1,120 @@ +/* + * BLESecurity.cpp + * + * Created on: Dec 17, 2017 + * Author: chegewara + */ + +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "BLESecurity.h" +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +BLESecurity::BLESecurity() { +} + +BLESecurity::~BLESecurity() { +} +/* + * @brief Set requested authentication mode + */ +void BLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) { + m_authReq = auth_req; + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &m_authReq, sizeof(uint8_t)); // <--- setup requested authentication mode +} + +/** + * @brief Set our device IO capability to let end user perform authorization + * either by displaying or entering generated 6-digits pin code + */ +void BLESecurity::setCapability(esp_ble_io_cap_t iocap) { + m_iocap = iocap; + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); +} // setCapability + + +/** + * @brief Init encryption key by server + * @param key_size is value between 7 and 16 + */ +void BLESecurity::setInitEncryptionKey(uint8_t init_key) { + m_initKey = init_key; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &m_initKey, sizeof(uint8_t)); +} // setInitEncryptionKey + + +/** + * @brief Init encryption key by client + * @param key_size is value between 7 and 16 + */ +void BLESecurity::setRespEncryptionKey(uint8_t resp_key) { + m_respKey = resp_key; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &m_respKey, sizeof(uint8_t)); +} // setRespEncryptionKey + + +/** + * + * + */ +void BLESecurity::setKeySize(uint8_t key_size) { + m_keySize = 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* key_str = nullptr; + 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"; + break; + case ESP_LE_KEY_PID: + key_str = (char*) "ESP_LE_KEY_PID"; + break; + case ESP_LE_KEY_PCSRK: + key_str = (char*) "ESP_LE_KEY_PCSRK"; + break; + case ESP_LE_KEY_PLK: + key_str = (char*) "ESP_LE_KEY_PLK"; + break; + case 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; + } + return key_str; +} // esp_key_type_to_str + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLESecurity.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLESecurity.h new file mode 100644 index 0000000..06c7dcd --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLESecurity.h @@ -0,0 +1,77 @@ +/* + * BLESecurity.h + * + * Created on: Dec 17, 2017 + * Author: chegewara + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESECURITY_H_ +#define COMPONENTS_CPP_UTILS_BLESECURITY_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include + +class BLESecurity { +public: + BLESecurity(); + virtual ~BLESecurity(); + void setAuthenticationMode(esp_ble_auth_req_t auth_req); + void setCapability(esp_ble_io_cap_t iocap); + 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: + esp_ble_auth_req_t m_authReq; + esp_ble_io_cap_t m_iocap; + uint8_t m_initKey; + uint8_t m_respKey; + uint8_t m_keySize; + +}; // BLESecurity + + +/* + * @brief Callbacks to handle GAP events related to authorization + */ +class BLESecurityCallbacks { +public: + virtual ~BLESecurityCallbacks() {}; + + /** + * @brief Its request from peer device to input authentication pin code displayed on peer device. + * It requires that our device is capable to input 6-digits code by end user + * @return Return 6-digits integer value from input device + */ + virtual uint32_t onPassKeyRequest() = 0; + + /** + * @brief Provide us 6-digits code to perform authentication. + * It requires that our device is capable to display this code to end user + * @param + */ + 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() = 0 ; + /** + * Provide us information when authentication process is completed + */ + virtual void onAuthenticationComplete(esp_ble_auth_cmpl_t) = 0; + + virtual bool onConfirmPIN(uint32_t pin) = 0; +}; // BLESecurityCallbacks + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif // COMPONENTS_CPP_UTILS_BLESECURITY_H_ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServer.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServer.cpp new file mode 100644 index 0000000..2fe3b64 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServer.cpp @@ -0,0 +1,445 @@ +/* + * BLEServer.cpp + * + * Created on: Apr 16, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "GeneralUtils.h" +#include "BLEDevice.h" +#include "BLEServer.h" +#include "BLEService.h" +#include "BLEUtils.h" +#include +#include +#include +#include "esp32-hal-log.h" + +/** + * @brief Construct a %BLE Server + * + * This class is not designed to be individually instantiated. Instead one should create a server by asking + * the BLEDevice class. + */ +BLEServer::BLEServer() { + m_appId = ESP_GATT_IF_NONE; + m_gatts_if = ESP_GATT_IF_NONE; + m_connectedCount = 0; + m_connId = ESP_GATT_IF_NONE; + m_pServerCallbacks = nullptr; +} // BLEServer + + +void BLEServer::createApp(uint16_t appId) { + m_appId = appId; + registerApp(appId); +} // createApp + + +/** + * @brief Create a %BLE Service. + * + * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition + * of a new service. Every service must have a unique UUID. + * @param [in] uuid The UUID of the new service. + * @return A reference to the new service object. + */ +BLEService* BLEServer::createService(const char* uuid) { + return createService(BLEUUID(uuid)); +} + + +/** + * @brief Create a %BLE Service. + * + * With a %BLE server, we can host one or more services. Invoking this function causes the creation of a definition + * of a new service. Every service must have a unique UUID. + * @param [in] uuid The UUID of the new service. + * @param [in] numHandles The maximum number of handles associated with this service. + * @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service. + * @return A reference to the new service object. + */ +BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t inst_id) { + log_v(">> createService - %s", uuid.toString().c_str()); + m_semaphoreCreateEvt.take("createService"); + + // Check that a service with the supplied UUID does not already exist. + if (m_serviceMap.getByUUID(uuid) != nullptr) { + log_w("<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", + uuid.toString().c_str()); + } + + BLEService* pService = new BLEService(uuid, numHandles); + 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. + + m_semaphoreCreateEvt.wait("createService"); + + log_v("<< createService"); + return pService; +} // 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 BLEDevice::getAdvertising(); +} + +uint16_t BLEServer::getConnId() { + return m_connId; +} + + +/** + * @brief Return the number of connected clients. + * @return The number of connected clients. + */ +uint32_t BLEServer::getConnectedCount() { + return m_connectedCount; +} // getConnectedCount + + +uint16_t BLEServer::getGattsIf() { + return m_gatts_if; +} + + +/** + * @brief Handle a GATT Server Event. + * + * @param [in] event + * @param [in] gatts_if + * @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) { + log_v(">> handleGATTServerEvent: %s", + BLEUtils::gattServerEventTypeToString(event).c_str()); + + switch(event) { + // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. + // add_char: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + // + case ESP_GATTS_ADD_CHAR_EVT: { + break; + } // ESP_GATTS_ADD_CHAR_EVT + + case ESP_GATTS_MTU_EVT: + updatePeerMTU(param->mtu.conn_id, param->mtu.mtu); + if (m_pServerCallbacks != nullptr) { + m_pServerCallbacks->onMtuChanged(this, param); + } + break; + + // ESP_GATTS_CONNECT_EVT + // connect: + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // + case ESP_GATTS_CONNECT_EVT: { + 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. + break; + } // ESP_GATTS_CONNECT_EVT + + + // ESP_GATTS_CREATE_EVT + // Called when a new service is registered as having been created. + // + // create: + // * esp_gatt_status_t status + // * uint16_t service_handle + // * esp_gatt_srvc_id_t service_id + // + case ESP_GATTS_CREATE_EVT: { + 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; + } // ESP_GATTS_CREATE_EVT + + + // ESP_GATTS_DISCONNECT_EVT + // + // disconnect + // - 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. + case ESP_GATTS_DISCONNECT_EVT: { + if (m_pServerCallbacks != nullptr) { // If we have callbacks, call now. + m_pServerCallbacks->onDisconnect(this); + m_pServerCallbacks->onDisconnect(this, param); + } + if(m_connId == ESP_GATT_IF_NONE) { + return; + } + + // only decrement if connection is found in map and removed + // sometimes this event triggers w/o a valid connection + if(removePeerDevice(param->disconnect.conn_id, false)) { + m_connectedCount--; // Decrement the number of connected devices count. + } + break; + } // ESP_GATTS_DISCONNECT_EVT + + + // ESP_GATTS_READ_EVT - A request to read the value of a characteristic has arrived. + // + // read: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool is_long + // - bool need_rsp + // + case ESP_GATTS_READ_EVT: { + break; + } // ESP_GATTS_READ_EVT + + + // ESP_GATTS_REG_EVT + // reg: + // - esp_gatt_status_t status + // - uint16_t app_id + // + case ESP_GATTS_REG_EVT: { + m_gatts_if = gatts_if; + m_semaphoreRegisterAppEvt.give(); // Unlock the mutex waiting for the registration of the app. + break; + } // ESP_GATTS_REG_EVT + + + // ESP_GATTS_WRITE_EVT - A request to write the value of a characteristic has arrived. + // + // write: + // - uint16_t conn_id + // - uint16_t trans_id + // - esp_bd_addr_t bda + // - uint16_t handle + // - uint16_t offset + // - bool need_rsp + // - bool is_prep + // - uint16_t len + // - uint8_t* value + // + case ESP_GATTS_WRITE_EVT: { + break; + } + + 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); + + log_v("<< handleGATTServerEvent"); +} // handleGATTServerEvent + + +/** + * @brief Register the app. + * + * @return N/A + */ +void BLEServer::registerApp(uint16_t m_appId) { + log_v(">> 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); + m_semaphoreRegisterAppEvt.wait("registerApp"); + log_v("<< registerApp"); +} // registerApp + + +/** + * @brief Set the server callbacks. + * + * As a %BLE server operates, it will generate server level events such as a new client connecting or a previous client + * disconnecting. This function can be called to register a callback handler that will be invoked when these + * events are detected. + * + * @param [in] pCallbacks The callbacks to be invoked. + */ +void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) { + m_pServerCallbacks = pCallbacks; +} // setCallbacks + +/* + * Remove service + */ +void BLEServer::removeService(BLEService* service) { + service->stop(); + service->executeDelete(); + m_serviceMap.removeService(service); +} + +/** + * @brief Start advertising. + * + * Start the server advertising its existence. This is a convenience function and is equivalent to + * retrieving the advertising object and invoking start upon it. + */ +void BLEServer::startAdvertising() { + log_v(">> startAdvertising"); + BLEDevice::startAdvertising(); + log_v("<< 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) { + log_e("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. + log_v("<< connect(), rc=%d", rc==ESP_GATT_OK); + return rc == ESP_GATT_OK; +} // connect + + + +void BLEServerCallbacks::onConnect(BLEServer* pServer) { + log_d("BLEServerCallbacks", ">> onConnect(): Default"); + log_d("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str()); + log_d("BLEServerCallbacks", "<< onConnect()"); +} // onConnect + +void BLEServerCallbacks::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) { + log_d("BLEServerCallbacks", ">> onConnect(): Default"); + log_d("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str()); + log_d("BLEServerCallbacks", "<< onConnect()"); +} // onConnect + + +void BLEServerCallbacks::onDisconnect(BLEServer* pServer) { + log_d("BLEServerCallbacks", ">> onDisconnect(): Default"); + log_d("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str()); + log_d("BLEServerCallbacks", "<< onDisconnect()"); +} // onDisconnect + +void BLEServerCallbacks::onDisconnect(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) { + log_d("BLEServerCallbacks", ">> onDisconnect(): Default"); + log_d("BLEServerCallbacks", "Device: %s", BLEDevice::toString().c_str()); + log_d("BLEServerCallbacks", "<< onDisconnect()"); +} // onDisconnect + +void BLEServerCallbacks::onMtuChanged(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) { + log_d("BLEServerCallbacks", ">> onMtuChanged(): Default"); + log_d("BLEServerCallbacks", "Device: %s MTU: %d", BLEDevice::toString().c_str(), param->mtu.mtu); + log_d("BLEServerCallbacks", "<< onMtuChanged()"); +} // onMtuChanged + +/* 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)); +} + +bool BLEServer::removePeerDevice(uint16_t conn_id, bool _client) { + return m_connectedServersMap.erase(conn_id) > 0; +} +/* 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_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServer.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServer.h new file mode 100644 index 0000000..ef2d8f9 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServer.h @@ -0,0 +1,156 @@ +/* + * BLEServer.h + * + * Created on: Apr 16, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESERVER_H_ +#define COMPONENTS_CPP_UTILS_BLESERVER_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include + +#include +#include +// #include "BLEDevice.h" + +#include "BLEUUID.h" +#include "BLEAdvertising.h" +#include "BLECharacteristic.h" +#include "BLEService.h" +#include "BLESecurity.h" +#include "RTOS.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; + + +/** + * @brief A data structure that manages the %BLE servers owned by a BLE server. + */ +class BLEServiceMap { +public: + BLEService* getByHandle(uint16_t handle); + BLEService* getByUUID(const char* uuid); + 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); + String toString(); + BLEService* getFirst(); + BLEService* getNext(); + void removeService(BLEService *service); + int getRegisteredServiceCount(); + +private: + std::map m_handleMap; + std::map m_uuidMap; + std::map::iterator m_iterator; +}; + + +/** + * @brief The model of a %BLE server. + */ +class BLEServer { +public: + uint32_t getConnectedCount(); + BLEService* createService(const char* uuid); + BLEService* createService(BLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0); + BLEAdvertising* getAdvertising(); + void setCallbacks(BLEServerCallbacks* pCallbacks); + void startAdvertising(); + 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); + bool 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: + BLEServer(); + friend class BLEService; + friend class BLECharacteristic; + friend class BLEDevice; + esp_ble_adv_data_t m_adv_data; + // 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 = nullptr; + + void createApp(uint16_t appId); + uint16_t getGattsIf(); + void handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); + void registerApp(uint16_t); +}; // BLEServer + + +/** + * @brief Callbacks associated with the operation of a %BLE server. + */ +class BLEServerCallbacks { +public: + virtual ~BLEServerCallbacks() {}; + /** + * @brief Handle a new client connection. + * + * When a new client connects, we are invoked. + * + * @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. + * + * When an existing client disconnects, we are invoked. + * + * @param [in] pServer A reference to the %BLE server that received the existing client disconnection. + */ + virtual void onDisconnect(BLEServer* pServer); + virtual void onDisconnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param); + + /** + * @brief Handle a new client connection. + * + * When the MTU changes this method is invoked. + * + * @param [in] pServer A reference to the %BLE server that received the client connection. + * @param [in] param A reference to esp_ble_gatts_cb_param_t. + */ + virtual void onMtuChanged(BLEServer* pServer, esp_ble_gatts_cb_param_t* param); +}; // BLEServerCallbacks + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLESERVER_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEService.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEService.cpp new file mode 100644 index 0000000..554db97 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEService.cpp @@ -0,0 +1,417 @@ +/* + * BLEService.cpp + * + * Created on: Mar 25, 2017 + * Author: kolban + */ + +// A service is identified by a UUID. A service is also the container for one or more characteristics. + +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include + +#include +#include +#include + +#include "BLEServer.h" +#include "BLEService.h" +#include "BLEUtils.h" +#include "GeneralUtils.h" +#include "esp32-hal-log.h" + +#define NULL_HANDLE (0xffff) + + +/** + * @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, uint16_t numHandles) : BLEService(BLEUUID(uuid), numHandles) { +} + + +/** + * @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(BLEUUID uuid, uint16_t numHandles) { + m_uuid = uuid; + m_handle = NULL_HANDLE; + m_pServer = nullptr; + //m_serializeMutex.setName("BLEService"); + m_lastCreatedCharacteristic = nullptr; + m_numHandles = numHandles; +} // BLEService + + +/** + * @brief Create the service. + * Create the service. + * @param [in] gatts_if The handle of the GATT server interface. + * @return N/A. + */ + +void BLEService::executeCreate(BLEServer* pServer) { + log_v(">> 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_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. + + if (errRc != ESP_OK) { + log_e("esp_ble_gatts_create_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreCreateEvt.wait("executeCreate"); + log_v("<< executeCreate"); +} // executeCreate + + +/** + * @brief Delete the service. + * Delete the service. + * @return N/A. + */ + +void BLEService::executeDelete() { + log_v(">> 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()); + + if (errRc != ESP_OK) { + log_e("esp_ble_gatts_delete_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreDeleteEvt.wait("executeDelete"); + log_v("<< executeDelete"); +} // executeDelete + + +/** + * @brief Dump details of this BLE GATT service. + * @return N/A. + */ +void BLEService::dump() { + log_d("Service: uuid:%s, handle: 0x%.2x", + m_uuid.toString().c_str(), + m_handle); + log_d("Characteristics:\n%s", m_characteristicMap.toString().c_str()); +} // dump + + +/** + * @brief Get the UUID of the service. + * @return the UUID of the service. + */ +BLEUUID BLEService::getUUID() { + return m_uuid; +} // getUUID + + +/** + * @brief Start the service. + * Here we wish to start the service which means that we will respond to partner requests about it. + * Starting a service also means that we can create the corresponding characteristics. + * @return Start the service. + */ +void BLEService::start() { +// 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(). +// + log_v(">> start(): Starting service (esp_ble_gatts_start_service): %s", toString().c_str()); + if (m_handle == NULL_HANDLE) { + log_e("<< !!! We attempted to start a service but don't know its handle!"); + return; + } + + BLECharacteristic *pCharacteristic = m_characteristicMap.getFirst(); + + while (pCharacteristic != nullptr) { + m_lastCreatedCharacteristic = pCharacteristic; + pCharacteristic->executeCreate(this); + + pCharacteristic = m_characteristicMap.getNext(); + } + // Start each of the characteristics ... these are found in the m_characteristicMap. + + m_semaphoreStartEvt.take("start"); + esp_err_t errRc = ::esp_ble_gatts_start_service(m_handle); + + if (errRc != ESP_OK) { + log_e("<< esp_ble_gatts_start_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + m_semaphoreStartEvt.wait("start"); + + log_v("<< start()"); +} // start + + +/** + * @brief 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(). + log_v(">> stop(): Stopping service (esp_ble_gatts_stop_service): %s", toString().c_str()); + if (m_handle == NULL_HANDLE) { + log_e("<< !!! We attempted to stop a service but don't know its handle!"); + return; + } + + m_semaphoreStopEvt.take("stop"); + esp_err_t errRc = ::esp_ble_gatts_stop_service(m_handle); + + if (errRc != ESP_OK) { + log_e("<< esp_ble_gatts_stop_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + m_semaphoreStopEvt.wait("stop"); + + log_v("<< stop()"); +} // start + + +/** + * @brief Set the handle associated with this service. + * @param [in] handle The handle associated with the service. + */ +void BLEService::setHandle(uint16_t handle) { + log_v(">> setHandle - Handle=0x%.2x, service UUID=%s)", handle, getUUID().toString().c_str()); + if (m_handle != NULL_HANDLE) { + log_e("!!! Handle is already set %.2x", m_handle); + return; + } + m_handle = handle; + log_v("<< setHandle"); +} // setHandle + + +/** + * @brief Get the handle associated with this service. + * @return The handle associated with this service. + */ +uint16_t BLEService::getHandle() { + return m_handle; +} // getHandle + + +/** + * @brief Add a characteristic to the service. + * @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). + + log_v(">> addCharacteristic()"); + log_d("Adding characteristic: uuid=%s to service: %s", + pCharacteristic->getUUID().toString().c_str(), + toString().c_str()); + + // Check that we don't add the same characteristic twice. + if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) { + log_w("<< Adding a new characteristic with the same UUID as a previous one"); + //return; + } + + // Remember this characteristic in our map of characteristics. At this point, we can lookup by UUID + // but not by handle. The handle is allocated to us on the ESP_GATTS_ADD_CHAR_EVT. + m_characteristicMap.setByUUID(pCharacteristic, pCharacteristic->getUUID()); + + log_v("<< addCharacteristic()"); +} // addCharacteristic + + +/** + * @brief Create a new BLE Characteristic associated with this service. + * @param [in] uuid - The UUID of the characteristic. + * @param [in] properties - The properties of the characteristic. + * @return The new BLE characteristic. + */ +BLECharacteristic* BLEService::createCharacteristic(const char* uuid, uint32_t properties) { + return createCharacteristic(BLEUUID(uuid), properties); +} + + +/** + * @brief Create a new BLE Characteristic associated with this service. + * @param [in] uuid - The UUID of the characteristic. + * @param [in] properties - The properties of the characteristic. + * @return The new BLE characteristic. + */ +BLECharacteristic* BLEService::createCharacteristic(BLEUUID uuid, uint32_t properties) { + BLECharacteristic* pCharacteristic = new BLECharacteristic(uuid, properties); + addCharacteristic(pCharacteristic); + return pCharacteristic; +} // createCharacteristic + + +/** + * @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) { + // ESP_GATTS_ADD_CHAR_EVT - Indicate that a characteristic was added to the service. + // add_char: + // - esp_gatt_status_t status + // - uint16_t attr_handle + // - uint16_t service_handle + // - esp_bt_uuid_t char_uuid + + // If we have reached the correct service, then locate the characteristic and remember the handle + // for that characteristic. + case ESP_GATTS_ADD_CHAR_EVT: { + if (m_handle == param->add_char.service_handle) { + BLECharacteristic *pCharacteristic = getLastCreatedCharacteristic(); + if (pCharacteristic == nullptr) { + log_e("Expected to find characteristic with UUID: %s, but didnt!", + BLEUUID(param->add_char.char_uuid).toString().c_str()); + dump(); + break; + } + pCharacteristic->setHandle(param->add_char.attr_handle); + m_characteristicMap.setByHandle(param->add_char.attr_handle, pCharacteristic); + break; + } // Reached the correct service. + break; + } // ESP_GATTS_ADD_CHAR_EVT + + + // ESP_GATTS_START_EVT + // + // start: + // esp_gatt_status_t status + // uint16_t service_handle + case ESP_GATTS_START_EVT: { + if (param->start.service_handle == getHandle()) { + m_semaphoreStartEvt.give(); + } + break; + } // ESP_GATTS_START_EVT + + // ESP_GATTS_STOP_EVT + // + // stop: + // esp_gatt_status_t status + // uint16_t service_handle + // + case ESP_GATTS_STOP_EVT: { + if (param->stop.service_handle == getHandle()) { + m_semaphoreStopEvt.give(); + } + break; + } // ESP_GATTS_STOP_EVT + + + // ESP_GATTS_CREATE_EVT + // Called when a new service is registered as having been created. + // + // create: + // * esp_gatt_status_t status + // * uint16_t service_handle + // * esp_gatt_srvc_id_t service_id + // * - esp_gatt_id id + // * - esp_bt_uuid uuid + // * - uint8_t inst_id + // * - bool is_primary + // + case ESP_GATTS_CREATE_EVT: { + 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(); + } + break; + } // ESP_GATTS_CREATE_EVT + + + // ESP_GATTS_DELETE_EVT + // Called when a service is deleted. + // + // delete: + // * esp_gatt_status_t status + // * uint16_t service_handle + // + case ESP_GATTS_DELETE_EVT: { + if (param->del.service_handle == getHandle()) { + m_semaphoreDeleteEvt.give(); + } + break; + } // ESP_GATTS_DELETE_EVT + + default: + break; + } // Switch + + // Invoke the GATTS handler in each of the associated characteristics. + m_characteristicMap.handleGATTServerEvent(event, gatts_if, param); +} // handleGATTServerEvent + + +BLECharacteristic* BLEService::getCharacteristic(const char* uuid) { + return getCharacteristic(BLEUUID(uuid)); +} + + +BLECharacteristic* BLEService::getCharacteristic(BLEUUID uuid) { + return m_characteristicMap.getByUUID(uuid); +} + + +/** + * @brief Return a string representation of this service. + * A service is defined by: + * * Its UUID + * * Its handle + * @return A string representation of this service. + */ +String BLEService::toString() { + String res = "UUID: " + getUUID().toString(); + char hex[5]; + snprintf(hex, sizeof(hex), "%04x", getHandle()); + res += ", handle: 0x"; + res += hex; + return res; +} // toString + + +/** + * @brief Get the last created characteristic. + * It is lamentable that this function has to exist. It returns the last created characteristic. + * We need this because the descriptor API is built around the notion that a new descriptor, when created, + * is associated with the last characteristics created and we need that information. + * @return The last created characteristic. + */ +BLECharacteristic* BLEService::getLastCreatedCharacteristic() { + return m_lastCreatedCharacteristic; +} // getLastCreatedCharacteristic + + +/** + * @brief Get the BLE server associated with this service. + * @return The BLEServer associated with this service. + */ +BLEServer* BLEService::getServer() { + return m_pServer; +} // getServer + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEService.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEService.h new file mode 100644 index 0000000..2d8a03b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEService.h @@ -0,0 +1,101 @@ +/* + * BLEService.h + * + * Created on: Mar 25, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESERVICE_H_ +#define COMPONENTS_CPP_UTILS_BLESERVICE_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +#include + +#include "BLECharacteristic.h" +#include "BLEServer.h" +#include "BLEUUID.h" +#include "RTOS.h" + +class BLEServer; + +/** + * @brief A data mapping used to manage the set of %BLE characteristics known to the server. + */ +class BLECharacteristicMap { +public: + void setByUUID(BLECharacteristic* pCharacteristic, const char* uuid); + void setByUUID(BLECharacteristic* pCharacteristic, BLEUUID uuid); + void setByHandle(uint16_t handle, BLECharacteristic* pCharacteristic); + BLECharacteristic* getByUUID(const char* uuid); + BLECharacteristic* getByUUID(BLEUUID uuid); + BLECharacteristic* getByHandle(uint16_t handle); + BLECharacteristic* getFirst(); + BLECharacteristic* getNext(); + String toString(); + 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; + std::map m_handleMap; + std::map::iterator m_iterator; +}; + + +/** + * @brief The model of a %BLE service. + * + */ +class BLEService { +public: + void addCharacteristic(BLECharacteristic* pCharacteristic); + BLECharacteristic* createCharacteristic(const char* uuid, uint32_t properties); + BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties); + void dump(); + void executeCreate(BLEServer* pServer); + void executeDelete(); + BLECharacteristic* getCharacteristic(const char* uuid); + BLECharacteristic* getCharacteristic(BLEUUID uuid); + BLEUUID getUUID(); + BLEServer* getServer(); + void start(); + void stop(); + String toString(); + uint16_t getHandle(); + uint8_t m_instId = 0; + +private: + BLEService(const char* uuid, uint16_t numHandles); + BLEService(BLEUUID uuid, uint16_t numHandles); + friend class BLEServer; + friend class BLEServiceMap; + friend class BLEDescriptor; + friend class BLECharacteristic; + friend class BLEDevice; + + BLECharacteristicMap m_characteristicMap; + uint16_t m_handle; + BLECharacteristic* m_lastCreatedCharacteristic = nullptr; + BLEServer* m_pServer = nullptr; + BLEUUID m_uuid; + + FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + FreeRTOS::Semaphore m_semaphoreDeleteEvt = FreeRTOS::Semaphore("DeleteEvt"); + FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt"); + FreeRTOS::Semaphore m_semaphoreStopEvt = FreeRTOS::Semaphore("StopEvt"); + + 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 setHandle(uint16_t handle); + //void setService(esp_gatt_srvc_id_t srvc_id); +}; // BLEService + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLESERVICE_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServiceMap.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServiceMap.cpp new file mode 100644 index 0000000..eab54cf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEServiceMap.cpp @@ -0,0 +1,141 @@ +/* + * BLEServiceMap.cpp + * + * Created on: Jun 22, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include "BLEService.h" + + +/** + * @brief Return the service by UUID. + * @param [in] UUID The UUID to look up the service. + * @return The characteristic. + */ +BLEService* BLEServiceMap::getByUUID(const char* 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, uint8_t inst_id) { + for (auto &myPair : m_uuidMap) { + if (myPair.first->getUUID().equals(uuid)) { + return myPair.first; + } + } + //return m_uuidMap.at(uuid.toString()); + return nullptr; +} // getByUUID + + +/** + * @brief Return the service by handle. + * @param [in] handle The handle to look up the service. + * @return The service. + */ +BLEService* BLEServiceMap::getByHandle(uint16_t handle) { + return m_handleMap.at(handle); +} // getByHandle + + +/** + * @brief Set the service by UUID. + * @param [in] uuid The uuid of the service. + * @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())); +} // setByUUID + + +/** + * @brief Set the service by handle. + * @param [in] handle The handle of the service. + * @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)); +} // setByHandle + + +/** + * @brief Return a string representation of the service map. + * @return A string representation of the service map. + */ +String BLEServiceMap::toString() { + String res; + char hex[5]; + for (auto &myPair: m_handleMap) { + res += "handle: 0x"; + snprintf(hex, sizeof(hex), "%04x", myPair.first); + res += hex; + res += ", uuid: " + myPair.second->getUUID().toString() + "\n"; + } + return res; +} // toString + +void BLEServiceMap::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) { + myPair.first->handleGATTServerEvent(event, gatts_if, param); + } +} + +/** + * @brief Get the first service in the map. + * @return The first service in the map. + */ +BLEService* BLEServiceMap::getFirst() { + m_iterator = m_uuidMap.begin(); + if (m_iterator == m_uuidMap.end()) return nullptr; + BLEService* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getFirst + +/** + * @brief Get the next service in the map. + * @return The next service in the map. + */ +BLEService* BLEServiceMap::getNext() { + if (m_iterator == m_uuidMap.end()) return nullptr; + BLEService* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getNext + +/** + * @brief Removes service from maps. + * @return N/A. + */ +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_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUUID.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUUID.cpp new file mode 100644 index 0000000..d345372 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUUID.cpp @@ -0,0 +1,397 @@ +/* + * BLEUUID.cpp + * + * Created on: Jun 21, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include +#include +#include +#include +#include +#include +#include "BLEUUID.h" +#include "esp32-hal-log.h" + +/** + * @brief Copy memory from source to target but in reverse order. + * + * When we move memory from one location it is normally: + * + * ``` + * [0][1][2]...[n] -> [0][1][2]...[n] + * ``` + * + * with this function, it is: + * + * ``` + * [0][1][2]...[n] -> [n][n-1][n-2]...[0] + * ``` + * + * @param [in] target The target of the copy + * @param [in] source The source of the copy + * @param [in] size The number of bytes to copy + */ +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 + while (size > 0) { + *target = *source; + target--; + source++; + size--; + } +} // memrcpy + + +/** + * @brief Create a UUID from a string. + * + * Create a UUID from a string. There will be two possible stories here. Either the string represents + * a binary data field or the string represents a hex encoding of a UUID. + * For the hex encoding, here is an example: + * + * ``` + * "beb5483e-36e1-4688-b7f5-ea07361b26a8" + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * 12345678-90ab-cdef-1234-567890abcdef + * ``` + * + * This has a length of 36 characters. We need to parse this into 16 bytes. + * + * @param [in] value The string to build a UUID from. + */ +BLEUUID::BLEUUID(String value) { + //Serial.printf("BLEUUID constructor from String=\"%s\"\n", value.c_str()); + m_valueSet = true; + if (value.length() == 4) { + m_uuid.len = ESP_UUID_LEN_16; + 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() == 8) { + m_uuid.len = ESP_UUID_LEN_32; + 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) { // How we can have 16 byte length string representing 128 bit uuid??? needs to be investigated (lack of time) - maybe raw data encoded as String (128b==16B)? + m_uuid.len = ESP_UUID_LEN_128; + memrcpy(m_uuid.uuid.uuid128, (uint8_t*)value.c_str(), 16); + } + else if (value.length() == 36) { + //log_d("36 characters:"); + // 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 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 { + log_e("ERROR: UUID value not 2, 4, 16 or 36 bytes"); + m_valueSet = false; + } +} //BLEUUID(String) + +/* +BLEUUID::BLEUUID(String value) { + this.BLEUUID(String(value.c_str(), value.length())); +} //BLEUUID(String) +*/ + +/** + * @brief Create a UUID from 16 bytes of memory. + * + * @param [in] pData The pointer to the start of the UUID. + * @param [in] size The size of the data. + * @param [in] msbFirst Is the MSB first in pData memory? + */ +BLEUUID::BLEUUID(uint8_t* pData, size_t size, bool msbFirst) { + if (size != 16) { + log_e("ERROR: UUID length not 16 bytes"); + return; + } + m_uuid.len = ESP_UUID_LEN_128; + if (msbFirst) { + memrcpy(m_uuid.uuid.uuid128, pData, 16); + } else { + memcpy(m_uuid.uuid.uuid128, pData, 16); + } + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the 16bit value. + * + * @param [in] uuid The 16bit short form UUID. + */ +BLEUUID::BLEUUID(uint16_t uuid) { + m_uuid.len = ESP_UUID_LEN_16; + m_uuid.uuid.uuid16 = uuid; + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the 32bit value. + * + * @param [in] uuid The 32bit short form UUID. + */ +BLEUUID::BLEUUID(uint32_t uuid) { + m_uuid.len = ESP_UUID_LEN_32; + m_uuid.uuid.uuid32 = uuid; + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the native UUID. + * + * @param [in] uuid The native UUID. + */ +BLEUUID::BLEUUID(esp_bt_uuid_t uuid) { + m_uuid = uuid; + m_valueSet = true; +} // BLEUUID + + +/** + * @brief Create a UUID from the ESP32 esp_gat_id_t. + * + * @param [in] gattId The data to create the UUID from. + */ +BLEUUID::BLEUUID(esp_gatt_id_t gattId) : BLEUUID(gattId.uuid) { +} // BLEUUID + + +BLEUUID::BLEUUID() { + m_valueSet = false; +} // BLEUUID + + +/** + * @brief Get the number of bits in this uuid. + * @return The number of bits in the UUID. One of 16, 32 or 128. + */ +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: + return 32; + case ESP_UUID_LEN_128: + return 128; + default: + log_e("Unknown UUID length: %d", m_uuid.len); + return 0; + } // End of switch +} // bitSize + + +/** + * @brief Compare a UUID against this UUID. + * + * @param [in] uuid The UUID to compare against. + * @return True if the UUIDs are equal and false otherwise. + */ +bool BLEUUID::equals(BLEUUID uuid) { + //log_d("Comparing: %s to %s", toString().c_str(), uuid.toString().c_str()); + if (!m_valueSet || !uuid.m_valueSet) return false; + + if (uuid.m_uuid.len != m_uuid.len) { + return uuid.toString() == toString(); + } + + if (uuid.m_uuid.len == ESP_UUID_LEN_16) { + return uuid.m_uuid.uuid.uuid16 == m_uuid.uuid.uuid16; + } + + if (uuid.m_uuid.len == ESP_UUID_LEN_32) { + return uuid.m_uuid.uuid.uuid32 == m_uuid.uuid.uuid32; + } + + return memcmp(uuid.m_uuid.uuid.uuid128, m_uuid.uuid.uuid128, 16) == 0; +} // equals + + +/** + * Create a BLEUUID from a string of the form: + * 0xNNNN + * 0xNNNNNNNN + * 0x + * NNNN + * NNNNNNNN + * + */ +BLEUUID BLEUUID::fromString(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) { + uint16_t x = strtoul(_uuid.substring(start, start+len).c_str(), NULL, 16); + return BLEUUID(x); + } else if (len == 8) { + uint32_t x = strtoul(_uuid.substring(start, start+len).c_str(), NULL, 16); + return BLEUUID(x); + } else if (len == 36) { + return BLEUUID(_uuid); + } + return BLEUUID(); +} // fromString + + +/** + * @brief Get the native UUID value. + * + * @return The native UUID value or NULL if not set. + */ +esp_bt_uuid_t* BLEUUID::getNative() { + //log_d(">> getNative()") + if (m_valueSet == false) { + log_v("<< Return of un-initialized UUID!"); + return nullptr; + } + //log_d("<< getNative()"); + return &m_uuid; +} // getNative + + +/** + * @brief Convert a UUID to its 128 bit representation. + * + * A UUID can be internally represented as 16bit, 32bit or the full 128bit. This method + * will convert 16 or 32 bit representations to the full 128bit. + */ +BLEUUID BLEUUID::to128() { + //log_v(">> 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 || m_uuid.len == ESP_UUID_LEN_128) { + return *this; + } + + // If we are 16 bit or 32 bit, then set the 4 bytes of the variable part of the UUID. + if (m_uuid.len == ESP_UUID_LEN_16) { + uint16_t temp = m_uuid.uuid.uuid16; + m_uuid.uuid.uuid128[15] = 0; + m_uuid.uuid.uuid128[14] = 0; + m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; + m_uuid.uuid.uuid128[12] = temp & 0xff; + + } + else if (m_uuid.len == ESP_UUID_LEN_32) { + uint32_t temp = m_uuid.uuid.uuid32; + m_uuid.uuid.uuid128[15] = (temp >> 24) & 0xff; + m_uuid.uuid.uuid128[14] = (temp >> 16) & 0xff; + m_uuid.uuid.uuid128[13] = (temp >> 8) & 0xff; + m_uuid.uuid.uuid128[12] = temp & 0xff; + } + + // Set the fixed parts of the UUID. + m_uuid.uuid.uuid128[11] = 0x00; + m_uuid.uuid.uuid128[10] = 0x00; + + m_uuid.uuid.uuid128[9] = 0x10; + m_uuid.uuid.uuid128[8] = 0x00; + + m_uuid.uuid.uuid128[7] = 0x80; + m_uuid.uuid.uuid128[6] = 0x00; + + m_uuid.uuid.uuid128[5] = 0x00; + m_uuid.uuid.uuid128[4] = 0x80; + m_uuid.uuid.uuid128[3] = 0x5f; + m_uuid.uuid.uuid128[2] = 0x9b; + m_uuid.uuid.uuid128[1] = 0x34; + m_uuid.uuid.uuid128[0] = 0xfb; + + m_uuid.len = ESP_UUID_LEN_128; + //log_d("<< toFull <- %s", toString().c_str()); + return *this; +} // to128 + + + + +/** + * @brief Get a string representation of the UUID. + * + * The format of a string is: + * 01234567 8901 2345 6789 012345678901 + * 0000180d-0000-1000-8000-00805f9b34fb + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * + * @return A string representation of the UUID. + */ +String BLEUUID::toString() { + if (!m_valueSet) return ""; // If we have no value, nothing to format. + // If the UUIDs are 16 or 32 bit, pad correctly. + + if (m_uuid.len == ESP_UUID_LEN_16) { // If the UUID is 16bit, pad correctly. + char hex[9]; + snprintf(hex, sizeof(hex), "%08x", m_uuid.uuid.uuid16); + return String(hex) + "-0000-1000-8000-00805f9b34fb"; + } // End 16bit UUID + + if (m_uuid.len == ESP_UUID_LEN_32) { // If the UUID is 32bit, pad correctly. + char hex[9]; + snprintf(hex, sizeof(hex), "%08lx", m_uuid.uuid.uuid32); + return String(hex) + "-0000-1000-8000-00805f9b34fb"; + } // End 32bit UUID + + // The UUID is not 16bit or 32bit which means that it is 128bit. + // + // UUID string format: + // AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP + auto size = 37; // 32 for UUID data, 4 for '-' delimiters and one for a terminator == 37 chars + char *hex = (char *)malloc(size); + snprintf(hex, size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + m_uuid.uuid.uuid128[15], m_uuid.uuid.uuid128[14], + m_uuid.uuid.uuid128[13], m_uuid.uuid.uuid128[12], + m_uuid.uuid.uuid128[11], m_uuid.uuid.uuid128[10], + m_uuid.uuid.uuid128[9], m_uuid.uuid.uuid128[8], + m_uuid.uuid.uuid128[7], m_uuid.uuid.uuid128[6], + m_uuid.uuid.uuid128[5], m_uuid.uuid.uuid128[4], + m_uuid.uuid.uuid128[3], m_uuid.uuid.uuid128[2], + m_uuid.uuid.uuid128[1], m_uuid.uuid.uuid128[0]); + String res(hex); + free(hex); + return res; +} // toString + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUUID.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUUID.h new file mode 100644 index 0000000..7101f0e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUUID.h @@ -0,0 +1,44 @@ +/* + * BLEUUID.h + * + * Created on: Jun 21, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEUUID_H_ +#define COMPONENTS_CPP_UTILS_BLEUUID_H_ +#include "soc/soc_caps.h" +#include "WString.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if CONFIG_BLUEDROID_ENABLED +#include + +/** + * @brief A model of a %BLE UUID. + */ +class BLEUUID { +public: + BLEUUID(String uuid); + BLEUUID(uint16_t uuid); + BLEUUID(uint32_t uuid); + BLEUUID(esp_bt_uuid_t uuid); + BLEUUID(uint8_t* pData, size_t size, bool msbFirst); + BLEUUID(esp_gatt_id_t gattId); + BLEUUID(); + uint8_t bitSize(); // Get the number of bits in this uuid. + bool equals(BLEUUID uuid); + esp_bt_uuid_t* getNative(); + BLEUUID to128(); + String toString(); + static BLEUUID fromString(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 = false; // Is there a value set for this instance. +}; // BLEUUID + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEUUID_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUtils.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUtils.cpp new file mode 100644 index 0000000..c226a13 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUtils.cpp @@ -0,0 +1,2040 @@ +/* + * BLEUtils.cpp + * + * Created on: Mar 25, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include "BLEAddress.h" +#include "BLEClient.h" +#include "BLEUtils.h" +#include "BLEUUID.h" +#include "GeneralUtils.h" + +#include +#include +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 ESP-IDF +#include // Part of C++ STL +#include +#include + +#include "esp32-hal-log.h" + +typedef struct { + uint32_t assignedNumber; + const char* name; +} member_t; + +static const member_t members_ids[] = { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + {0xFE08, "Microsoft"}, + {0xFE09, "Pillsy, Inc."}, + {0xFE0A, "ruwido austria gmbh"}, + {0xFE0B, "ruwido austria gmbh"}, + {0xFE0C, "Procter & Gamble"}, + {0xFE0D, "Procter & Gamble"}, + {0xFE0E, "Setec Pty Ltd"}, + {0xFE0F, "Philips Lighting B.V."}, + {0xFE10, "Lapis Semiconductor Co., Ltd."}, + {0xFE11, "GMC-I Messtechnik GmbH"}, + {0xFE12, "M-Way Solutions GmbH"}, + {0xFE13, "Apple Inc."}, + {0xFE14, "Flextronics International USA Inc."}, + {0xFE15, "Amazon Fulfillment Services, Inc."}, + {0xFE16, "Footmarks, Inc."}, + {0xFE17, "Telit Wireless Solutions GmbH"}, + {0xFE18, "Runtime, Inc."}, + {0xFE19, "Google Inc."}, + {0xFE1A, "Tyto Life LLC"}, + {0xFE1B, "Tyto Life LLC"}, + {0xFE1C, "NetMedia, Inc."}, + {0xFE1D, "Illuminati Instrument Corporation"}, + {0xFE1E, "Smart Innovations Co., Ltd"}, + {0xFE1F, "Garmin International, Inc."}, + {0xFE20, "Emerson"}, + {0xFE21, "Bose Corporation"}, + {0xFE22, "Zoll Medical Corporation"}, + {0xFE23, "Zoll Medical Corporation"}, + {0xFE24, "August Home Inc"}, + {0xFE25, "Apple, Inc. "}, + {0xFE26, "Google Inc."}, + {0xFE27, "Google Inc."}, + {0xFE28, "Ayla Networks"}, + {0xFE29, "Gibson Innovations"}, + {0xFE2A, "DaisyWorks, Inc."}, + {0xFE2B, "ITT Industries"}, + {0xFE2C, "Google Inc."}, + {0xFE2D, "SMART INNOVATION Co.,Ltd"}, + {0xFE2E, "ERi,Inc."}, + {0xFE2F, "CRESCO Wireless, Inc"}, + {0xFE30, "Volkswagen AG"}, + {0xFE31, "Volkswagen AG"}, + {0xFE32, "Pro-Mark, Inc."}, + {0xFE33, "CHIPOLO d.o.o."}, + {0xFE34, "SmallLoop LLC"}, + {0xFE35, "HUAWEI Technologies Co., Ltd"}, + {0xFE36, "HUAWEI Technologies Co., Ltd"}, + {0xFE37, "Spaceek LTD"}, + {0xFE38, "Spaceek LTD"}, + {0xFE39, "TTS Tooltechnic Systems AG & Co. KG"}, + {0xFE3A, "TTS Tooltechnic Systems AG & Co. KG"}, + {0xFE3B, "Dolby Laboratories"}, + {0xFE3C, "Alibaba"}, + {0xFE3D, "BD Medical"}, + {0xFE3E, "BD Medical"}, + {0xFE3F, "Friday Labs Limited"}, + {0xFE40, "Inugo Systems Limited"}, + {0xFE41, "Inugo Systems Limited"}, + {0xFE42, "Nets A/S "}, + {0xFE43, "Andreas Stihl AG & Co. KG"}, + {0xFE44, "SK Telecom "}, + {0xFE45, "Snapchat Inc"}, + {0xFE46, "B&O Play A/S "}, + {0xFE47, "General Motors"}, + {0xFE48, "General Motors"}, + {0xFE49, "SenionLab AB"}, + {0xFE4A, "OMRON HEALTHCARE Co., Ltd."}, + {0xFE4B, "Philips Lighting B.V."}, + {0xFE4C, "Volkswagen AG"}, + {0xFE4D, "Casambi Technologies Oy"}, + {0xFE4E, "NTT docomo"}, + {0xFE4F, "Molekule, Inc."}, + {0xFE50, "Google Inc."}, + {0xFE51, "SRAM"}, + {0xFE52, "SetPoint Medical"}, + {0xFE53, "3M"}, + {0xFE54, "Motiv, Inc."}, + {0xFE55, "Google Inc."}, + {0xFE56, "Google Inc."}, + {0xFE57, "Dotted Labs"}, + {0xFE58, "Nordic Semiconductor ASA"}, + {0xFE59, "Nordic Semiconductor ASA"}, + {0xFE5A, "Chronologics Corporation"}, + {0xFE5B, "GT-tronics HK Ltd"}, + {0xFE5C, "million hunters GmbH"}, + {0xFE5D, "Grundfos A/S"}, + {0xFE5E, "Plastc Corporation"}, + {0xFE5F, "Eyefi, Inc."}, + {0xFE60, "Lierda Science & Technology Group Co., Ltd."}, + {0xFE61, "Logitech International SA"}, + {0xFE62, "Indagem Tech LLC"}, + {0xFE63, "Connected Yard, Inc."}, + {0xFE64, "Siemens AG"}, + {0xFE65, "CHIPOLO d.o.o."}, + {0xFE66, "Intel Corporation"}, + {0xFE67, "Lab Sensor Solutions"}, + {0xFE68, "Qualcomm Life Inc"}, + {0xFE69, "Qualcomm Life Inc"}, + {0xFE6A, "Kontakt Micro-Location Sp. z o.o."}, + {0xFE6B, "TASER International, Inc."}, + {0xFE6C, "TASER International, Inc."}, + {0xFE6D, "The University of Tokyo"}, + {0xFE6E, "The University of Tokyo"}, + {0xFE6F, "LINE Corporation"}, + {0xFE70, "Beijing Jingdong Century Trading Co., Ltd."}, + {0xFE71, "Plume Design Inc"}, + {0xFE72, "St. Jude Medical, Inc."}, + {0xFE73, "St. Jude Medical, Inc."}, + {0xFE74, "unwire"}, + {0xFE75, "TangoMe"}, + {0xFE76, "TangoMe"}, + {0xFE77, "Hewlett-Packard Company"}, + {0xFE78, "Hewlett-Packard Company"}, + {0xFE79, "Zebra Technologies"}, + {0xFE7A, "Bragi GmbH"}, + {0xFE7B, "Orion Labs, Inc."}, + {0xFE7C, "Telit Wireless Solutions (Formerly Stollmann E+V GmbH)"}, + {0xFE7D, "Aterica Health Inc."}, + {0xFE7E, "Awear Solutions Ltd"}, + {0xFE7F, "Doppler Lab"}, + {0xFE80, "Doppler Lab"}, + {0xFE81, "Medtronic Inc."}, + {0xFE82, "Medtronic Inc."}, + {0xFE83, "Blue Bite"}, + {0xFE84, "RF Digital Corp"}, + {0xFE85, "RF Digital Corp"}, + {0xFE86, "HUAWEI Technologies Co., Ltd. ( )"}, + {0xFE87, "Qingdao Yeelink Information Technology Co., Ltd. ( )"}, + {0xFE88, "SALTO SYSTEMS S.L."}, + {0xFE89, "B&O Play A/S"}, + {0xFE8A, "Apple, Inc."}, + {0xFE8B, "Apple, Inc."}, + {0xFE8C, "TRON Forum"}, + {0xFE8D, "Interaxon Inc."}, + {0xFE8E, "ARM Ltd"}, + {0xFE8F, "CSR"}, + {0xFE90, "JUMA"}, + {0xFE91, "Shanghai Imilab Technology Co.,Ltd"}, + {0xFE92, "Jarden Safety & Security"}, + {0xFE93, "OttoQ Inc."}, + {0xFE94, "OttoQ Inc."}, + {0xFE95, "Xiaomi Inc."}, + {0xFE96, "Tesla Motor Inc."}, + {0xFE97, "Tesla Motor Inc."}, + {0xFE98, "Currant, Inc."}, + {0xFE99, "Currant, Inc."}, + {0xFE9A, "Estimote"}, + {0xFE9B, "Samsara Networks, Inc"}, + {0xFE9C, "GSI Laboratories, Inc."}, + {0xFE9D, "Mobiquity Networks Inc"}, + {0xFE9E, "Dialog Semiconductor B.V."}, + {0xFE9F, "Google Inc."}, + {0xFEA0, "Google Inc."}, + {0xFEA1, "Intrepid Control Systems, Inc."}, + {0xFEA2, "Intrepid Control Systems, Inc."}, + {0xFEA3, "ITT Industries"}, + {0xFEA4, "Paxton Access Ltd"}, + {0xFEA5, "GoPro, Inc."}, + {0xFEA6, "GoPro, Inc."}, + {0xFEA7, "UTC Fire and Security"}, + {0xFEA8, "Savant Systems LLC"}, + {0xFEA9, "Savant Systems LLC"}, + {0xFEAA, "Google Inc."}, + {0xFEAB, "Nokia Corporation"}, + {0xFEAC, "Nokia Corporation"}, + {0xFEAD, "Nokia Corporation"}, + {0xFEAE, "Nokia Corporation"}, + {0xFEAF, "Nest Labs Inc."}, + {0xFEB0, "Nest Labs Inc."}, + {0xFEB1, "Electronics Tomorrow Limited"}, + {0xFEB2, "Microsoft Corporation"}, + {0xFEB3, "Taobao"}, + {0xFEB4, "WiSilica Inc."}, + {0xFEB5, "WiSilica Inc."}, + {0xFEB6, "Vencer Co, Ltd"}, + {0xFEB7, "Facebook, Inc."}, + {0xFEB8, "Facebook, Inc."}, + {0xFEB9, "LG Electronics"}, + {0xFEBA, "Tencent Holdings Limited"}, + {0xFEBB, "adafruit industries"}, + {0xFEBC, "Dexcom, Inc. "}, + {0xFEBD, "Clover Network, Inc."}, + {0xFEBE, "Bose Corporation"}, + {0xFEBF, "Nod, Inc."}, + {0xFEC0, "KDDI Corporation"}, + {0xFEC1, "KDDI Corporation"}, + {0xFEC2, "Blue Spark Technologies, Inc."}, + {0xFEC3, "360fly, Inc."}, + {0xFEC4, "PLUS Location Systems"}, + {0xFEC5, "Realtek Semiconductor Corp."}, + {0xFEC6, "Kocomojo, LLC"}, + {0xFEC7, "Apple, Inc."}, + {0xFEC8, "Apple, Inc."}, + {0xFEC9, "Apple, Inc."}, + {0xFECA, "Apple, Inc."}, + {0xFECB, "Apple, Inc."}, + {0xFECC, "Apple, Inc."}, + {0xFECD, "Apple, Inc."}, + {0xFECE, "Apple, Inc."}, + {0xFECF, "Apple, Inc."}, + {0xFED0, "Apple, Inc."}, + {0xFED1, "Apple, Inc."}, + {0xFED2, "Apple, Inc."}, + {0xFED3, "Apple, Inc."}, + {0xFED4, "Apple, Inc."}, + {0xFED5, "Plantronics Inc."}, + {0xFED6, "Broadcom Corporation"}, + {0xFED7, "Broadcom Corporation"}, + {0xFED8, "Google Inc."}, + {0xFED9, "Pebble Technology Corporation"}, + {0xFEDA, "ISSC Technologies Corporation"}, + {0xFEDB, "Perka, Inc."}, + {0xFEDC, "Jawbone"}, + {0xFEDD, "Jawbone"}, + {0xFEDE, "Coin, Inc."}, + {0xFEDF, "Design SHIFT"}, + {0xFEE0, "Anhui Huami Information Technology Co."}, + {0xFEE1, "Anhui Huami Information Technology Co."}, + {0xFEE2, "Anki, Inc."}, + {0xFEE3, "Anki, Inc."}, + {0xFEE4, "Nordic Semiconductor ASA"}, + {0xFEE5, "Nordic Semiconductor ASA"}, + {0xFEE6, "Silvair, Inc."}, + {0xFEE7, "Tencent Holdings Limited"}, + {0xFEE8, "Quintic Corp."}, + {0xFEE9, "Quintic Corp."}, + {0xFEEA, "Swirl Networks, Inc."}, + {0xFEEB, "Swirl Networks, Inc."}, + {0xFEEC, "Tile, Inc."}, + {0xFEED, "Tile, Inc."}, + {0xFEEE, "Polar Electro Oy"}, + {0xFEEF, "Polar Electro Oy"}, + {0xFEF0, "Intel"}, + {0xFEF1, "CSR"}, + {0xFEF2, "CSR"}, + {0xFEF3, "Google Inc."}, + {0xFEF4, "Google Inc."}, + {0xFEF5, "Dialog Semiconductor GmbH"}, + {0xFEF6, "Wicentric, Inc."}, + {0xFEF7, "Aplix Corporation"}, + {0xFEF8, "Aplix Corporation"}, + {0xFEF9, "PayPal, Inc."}, + {0xFEFA, "PayPal, Inc."}, + {0xFEFB, "Telit Wireless Solutions (Formerly Stollmann E+V GmbH)"}, + {0xFEFC, "Gimbal, Inc."}, + {0xFEFD, "Gimbal, Inc."}, + {0xFEFE, "GN ReSound A/S"}, + {0xFEFF, "GN Netcom"}, + {0xFFFF, "Reserved"}, /*for testing purposes only*/ +#endif + {0, "" } +}; + +typedef struct { + uint32_t assignedNumber; + const char* name; +} gattdescriptor_t; + +static const gattdescriptor_t g_descriptor_ids[] = { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + {0x2905,"Characteristic Aggregate Format"}, + {0x2900,"Characteristic Extended Properties"}, + {0x2904,"Characteristic Presentation Format"}, + {0x2901,"Characteristic User Description"}, + {0x2902,"Client Characteristic Configuration"}, + {0x290B,"Environmental Sensing Configuration"}, + {0x290C,"Environmental Sensing Measurement"}, + {0x290D,"Environmental Sensing Trigger Setting"}, + {0x2907,"External Report Reference"}, + {0x2909,"Number of Digitals"}, + {0x2908,"Report Reference"}, + {0x2903,"Server Characteristic Configuration"}, + {0x290E,"Time Trigger Setting"}, + {0x2906,"Valid Range"}, + {0x290A,"Value Trigger Setting"}, +#endif + { 0, "" } +}; + +typedef struct { + uint32_t assignedNumber; + const char* name; +} characteristicMap_t; + +static const characteristicMap_t g_characteristicsMappings[] = { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + {0x2A7E,"Aerobic Heart Rate Lower Limit"}, + {0x2A84,"Aerobic Heart Rate Upper Limit"}, + {0x2A7F,"Aerobic Threshold"}, + {0x2A80,"Age"}, + {0x2A5A,"Aggregate"}, + {0x2A43,"Alert Category ID"}, + {0x2A42,"Alert Category ID Bit Mask"}, + {0x2A06,"Alert Level"}, + {0x2A44,"Alert Notification Control Point"}, + {0x2A3F,"Alert Status"}, + {0x2AB3,"Altitude"}, + {0x2A81,"Anaerobic Heart Rate Lower Limit"}, + {0x2A82,"Anaerobic Heart Rate Upper Limit"}, + {0x2A83,"Anaerobic Threshold"}, + {0x2A58,"Analog"}, + {0x2A59,"Analog Output"}, + {0x2A73,"Apparent Wind Direction"}, + {0x2A72,"Apparent Wind Speed"}, + {0x2A01,"Appearance"}, + {0x2AA3,"Barometric Pressure Trend"}, + {0x2A19,"Battery Level"}, + {0x2A1B,"Battery Level State"}, + {0x2A1A,"Battery Power State"}, + {0x2A49,"Blood Pressure Feature"}, + {0x2A35,"Blood Pressure Measurement"}, + {0x2A9B,"Body Composition Feature"}, + {0x2A9C,"Body Composition Measurement"}, + {0x2A38,"Body Sensor Location"}, + {0x2AA4,"Bond Management Control Point"}, + {0x2AA5,"Bond Management Features"}, + {0x2A22,"Boot Keyboard Input Report"}, + {0x2A32,"Boot Keyboard Output Report"}, + {0x2A33,"Boot Mouse Input Report"}, + {0x2AA6,"Central Address Resolution"}, + {0x2AA8,"CGM Feature"}, + {0x2AA7,"CGM Measurement"}, + {0x2AAB,"CGM Session Run Time"}, + {0x2AAA,"CGM Session Start Time"}, + {0x2AAC,"CGM Specific Ops Control Point"}, + {0x2AA9,"CGM Status"}, + {0x2ACE,"Cross Trainer Data"}, + {0x2A5C,"CSC Feature"}, + {0x2A5B,"CSC Measurement"}, + {0x2A2B,"Current Time"}, + {0x2A66,"Cycling Power Control Point"}, + {0x2A66,"Cycling Power Control Point"}, + {0x2A65,"Cycling Power Feature"}, + {0x2A65,"Cycling Power Feature"}, + {0x2A63,"Cycling Power Measurement"}, + {0x2A64,"Cycling Power Vector"}, + {0x2A99,"Database Change Increment"}, + {0x2A85,"Date of Birth"}, + {0x2A86,"Date of Threshold Assessment"}, + {0x2A08,"Date Time"}, + {0x2A0A,"Day Date Time"}, + {0x2A09,"Day of Week"}, + {0x2A7D,"Descriptor Value Changed"}, + {0x2A00,"Device Name"}, + {0x2A7B,"Dew Point"}, + {0x2A56,"Digital"}, + {0x2A57,"Digital Output"}, + {0x2A0D,"DST Offset"}, + {0x2A6C,"Elevation"}, + {0x2A87,"Email Address"}, + {0x2A0B,"Exact Time 100"}, + {0x2A0C,"Exact Time 256"}, + {0x2A88,"Fat Burn Heart Rate Lower Limit"}, + {0x2A89,"Fat Burn Heart Rate Upper Limit"}, + {0x2A26,"Firmware Revision String"}, + {0x2A8A,"First Name"}, + {0x2AD9,"Fitness Machine Control Point"}, + {0x2ACC,"Fitness Machine Feature"}, + {0x2ADA,"Fitness Machine Status"}, + {0x2A8B,"Five Zone Heart Rate Limits"}, + {0x2AB2,"Floor Number"}, + {0x2A8C,"Gender"}, + {0x2A51,"Glucose Feature"}, + {0x2A18,"Glucose Measurement"}, + {0x2A34,"Glucose Measurement Context"}, + {0x2A74,"Gust Factor"}, + {0x2A27,"Hardware Revision String"}, + {0x2A39,"Heart Rate Control Point"}, + {0x2A8D,"Heart Rate Max"}, + {0x2A37,"Heart Rate Measurement"}, + {0x2A7A,"Heat Index"}, + {0x2A8E,"Height"}, + {0x2A4C,"HID Control Point"}, + {0x2A4A,"HID Information"}, + {0x2A8F,"Hip Circumference"}, + {0x2ABA,"HTTP Control Point"}, + {0x2AB9,"HTTP Entity Body"}, + {0x2AB7,"HTTP Headers"}, + {0x2AB8,"HTTP Status Code"}, + {0x2ABB,"HTTPS Security"}, + {0x2A6F,"Humidity"}, + {0x2A2A,"IEEE 11073-20601 Regulatory Certification Data List"}, + {0x2AD2,"Indoor Bike Data"}, + {0x2AAD,"Indoor Positioning Configuration"}, + {0x2A36,"Intermediate Cuff Pressure"}, + {0x2A1E,"Intermediate Temperature"}, + {0x2A77,"Irradiance"}, + {0x2AA2,"Language"}, + {0x2A90,"Last Name"}, + {0x2AAE,"Latitude"}, + {0x2A6B,"LN Control Point"}, + {0x2A6A,"LN Feature"}, + {0x2AB1,"Local East Coordinate"}, + {0x2AB0,"Local North Coordinate"}, + {0x2A0F,"Local Time Information"}, + {0x2A67,"Location and Speed Characteristic"}, + {0x2AB5,"Location Name"}, + {0x2AAF,"Longitude"}, + {0x2A2C,"Magnetic Declination"}, + {0x2AA0,"Magnetic Flux Density - 2D"}, + {0x2AA1,"Magnetic Flux Density - 3D"}, + {0x2A29,"Manufacturer Name String"}, + {0x2A91,"Maximum Recommended Heart Rate"}, + {0x2A21,"Measurement Interval"}, + {0x2A24,"Model Number String"}, + {0x2A68,"Navigation"}, + {0x2A3E,"Network Availability"}, + {0x2A46,"New Alert"}, + {0x2AC5,"Object Action Control Point"}, + {0x2AC8,"Object Changed"}, + {0x2AC1,"Object First-Created"}, + {0x2AC3,"Object ID"}, + {0x2AC2,"Object Last-Modified"}, + {0x2AC6,"Object List Control Point"}, + {0x2AC7,"Object List Filter"}, + {0x2ABE,"Object Name"}, + {0x2AC4,"Object Properties"}, + {0x2AC0,"Object Size"}, + {0x2ABF,"Object Type"}, + {0x2ABD,"OTS Feature"}, + {0x2A04,"Peripheral Preferred Connection Parameters"}, + {0x2A02,"Peripheral Privacy Flag"}, + {0x2A5F,"PLX Continuous Measurement Characteristic"}, + {0x2A60,"PLX Features"}, + {0x2A5E,"PLX Spot-Check Measurement"}, + {0x2A50,"PnP ID"}, + {0x2A75,"Pollen Concentration"}, + {0x2A2F,"Position 2D"}, + {0x2A30,"Position 3D"}, + {0x2A69,"Position Quality"}, + {0x2A6D,"Pressure"}, + {0x2A4E,"Protocol Mode"}, + {0x2A62,"Pulse Oximetry Control Point"}, + {0x2A60,"Pulse Oximetry Pulsatile Event Characteristic"}, + {0x2A78,"Rainfall"}, + {0x2A03,"Reconnection Address"}, + {0x2A52,"Record Access Control Point"}, + {0x2A14,"Reference Time Information"}, + {0x2A3A,"Removable"}, + {0x2A4D,"Report"}, + {0x2A4B,"Report Map"}, + {0x2AC9,"Resolvable Private Address Only"}, + {0x2A92,"Resting Heart Rate"}, + {0x2A40,"Ringer Control point"}, + {0x2A41,"Ringer Setting"}, + {0x2AD1,"Rower Data"}, + {0x2A54,"RSC Feature"}, + {0x2A53,"RSC Measurement"}, + {0x2A55,"SC Control Point"}, + {0x2A4F,"Scan Interval Window"}, + {0x2A31,"Scan Refresh"}, + {0x2A3C,"Scientific Temperature Celsius"}, + {0x2A10,"Secondary Time Zone"}, + {0x2A5D,"Sensor Location"}, + {0x2A25,"Serial Number String"}, + {0x2A05,"Service Changed"}, + {0x2A3B,"Service Required"}, + {0x2A28,"Software Revision String"}, + {0x2A93,"Sport Type for Aerobic and Anaerobic Thresholds"}, + {0x2AD0,"Stair Climber Data"}, + {0x2ACF,"Step Climber Data"}, + {0x2A3D,"String"}, + {0x2AD7,"Supported Heart Rate Range"}, + {0x2AD5,"Supported Inclination Range"}, + {0x2A47,"Supported New Alert Category"}, + {0x2AD8,"Supported Power Range"}, + {0x2AD6,"Supported Resistance Level Range"}, + {0x2AD4,"Supported Speed Range"}, + {0x2A48,"Supported Unread Alert Category"}, + {0x2A23,"System ID"}, + {0x2ABC,"TDS Control Point"}, + {0x2A6E,"Temperature"}, + {0x2A1F,"Temperature Celsius"}, + {0x2A20,"Temperature Fahrenheit"}, + {0x2A1C,"Temperature Measurement"}, + {0x2A1D,"Temperature Type"}, + {0x2A94,"Three Zone Heart Rate Limits"}, + {0x2A12,"Time Accuracy"}, + {0x2A15,"Time Broadcast"}, + {0x2A13,"Time Source"}, + {0x2A16,"Time Update Control Point"}, + {0x2A17,"Time Update State"}, + {0x2A11,"Time with DST"}, + {0x2A0E,"Time Zone"}, + {0x2AD3,"Training Status"}, + {0x2ACD,"Treadmill Data"}, + {0x2A71,"True Wind Direction"}, + {0x2A70,"True Wind Speed"}, + {0x2A95,"Two Zone Heart Rate Limit"}, + {0x2A07,"Tx Power Level"}, + {0x2AB4,"Uncertainty"}, + {0x2A45,"Unread Alert Status"}, + {0x2AB6,"URI"}, + {0x2A9F,"User Control Point"}, + {0x2A9A,"User Index"}, + {0x2A76,"UV Index"}, + {0x2A96,"VO2 Max"}, + {0x2A97,"Waist Circumference"}, + {0x2A98,"Weight"}, + {0x2A9D,"Weight Measurement"}, + {0x2A9E,"Weight Scale Feature"}, + {0x2A79,"Wind Chill"}, +#endif + {0, ""} +}; + +/** + * @brief Mapping from service ids to names + */ +typedef struct { + const char* name; + const char* type; + uint32_t assignedNumber; +} gattService_t; + + +/** + * Definition of the service ids to names that we know about. + */ +static const gattService_t g_gattServices[] = { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + {"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}, + {"Blood Pressure", "org.bluetooth.service.blood_pressure", 0x1810}, + {"Body Composition", "org.bluetooth.service.body_composition", 0x181B}, + {"Bond Management", "org.bluetooth.service.bond_management", 0x181E}, + {"Continuous Glucose Monitoring", "org.bluetooth.service.continuous_glucose_monitoring", 0x181F}, + {"Current Time Service", "org.bluetooth.service.current_time", 0x1805}, + {"Cycling Power", "org.bluetooth.service.cycling_power", 0x1818}, + {"Cycling Speed and Cadence", "org.bluetooth.service.cycling_speed_and_cadence", 0x1816}, + {"Device Information", "org.bluetooth.service.device_information", 0x180A}, + {"Environmental Sensing", "org.bluetooth.service.environmental_sensing", 0x181A}, + {"Generic Access", "org.bluetooth.service.generic_access", 0x1800}, + {"Generic Attribute", "org.bluetooth.service.generic_attribute", 0x1801}, + {"Glucose", "org.bluetooth.service.glucose", 0x1808}, + {"Health Thermometer", "org.bluetooth.service.health_thermometer", 0x1809}, + {"Heart Rate", "org.bluetooth.service.heart_rate", 0x180D}, + {"HTTP Proxy", "org.bluetooth.service.http_proxy", 0x1823}, + {"Human Interface Device", "org.bluetooth.service.human_interface_device", 0x1812}, + {"Immediate Alert", "org.bluetooth.service.immediate_alert", 0x1802}, + {"Indoor Positioning", "org.bluetooth.service.indoor_positioning", 0x1821}, + {"Internet Protocol Support", "org.bluetooth.service.internet_protocol_support", 0x1820}, + {"Link Loss", "org.bluetooth.service.link_loss", 0x1803}, + {"Location and Navigation", "org.bluetooth.service.location_and_navigation", 0x1819}, + {"Next DST Change Service", "org.bluetooth.service.next_dst_change", 0x1807}, + {"Object Transfer", "org.bluetooth.service.object_transfer", 0x1825}, + {"Phone Alert Status Service", "org.bluetooth.service.phone_alert_status", 0x180E}, + {"Pulse Oximeter", "org.bluetooth.service.pulse_oximeter", 0x1822}, + {"Reference Time Update Service", "org.bluetooth.service.reference_time_update", 0x1806}, + {"Running Speed and Cadence", "org.bluetooth.service.running_speed_and_cadence", 0x1814}, + {"Scan Parameters", "org.bluetooth.service.scan_parameters", 0x1813}, + {"Transport Discovery", "org.bluetooth.service.transport_discovery", 0x1824}, + {"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 } +}; + + +/** + * @brief Convert characteristic properties into a string representation. + * @param [in] prop Characteristic properties. + * @return A string representation of characteristic properties. + */ +String BLEUtils::characteristicPropertiesToString(esp_gatt_char_prop_t prop) { + String res = "broadcast: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_BROADCAST)?"1":"0"); + res += ", read: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_READ)?"1":"0"); + res += ", write_nr: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)?"1":"0"); + res += ", write: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_WRITE)?"1":"0"); + res += ", notify: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_NOTIFY)?"1":"0"); + res += ", indicate: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_INDICATE)?"1":"0"); + res += ", auth: "; + res += ((prop & ESP_GATT_CHAR_PROP_BIT_AUTH)?"1":"0"); + return res; +} // characteristicPropertiesToString + +/** + * @brief Convert an esp_gatt_id_t to a string. + */ +static String gattIdToString(esp_gatt_id_t gattId) { + String res = "uuid: " + BLEUUID(gattId.uuid).toString() + ", inst_id: "; + char val[8]; + snprintf(val, sizeof(val), "%d", (int)gattId.inst_id); + res += val; + return res; +} // gattIdToString + + +/** + * @brief Convert an esp_ble_addr_type_t to a string representation. + */ +const char* BLEUtils::addressTypeToString(esp_ble_addr_type_t type) { + switch (type) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case BLE_ADDR_TYPE_PUBLIC: + return "BLE_ADDR_TYPE_PUBLIC"; + case BLE_ADDR_TYPE_RANDOM: + return "BLE_ADDR_TYPE_RANDOM"; + case BLE_ADDR_TYPE_RPA_PUBLIC: + return "BLE_ADDR_TYPE_RPA_PUBLIC"; + case BLE_ADDR_TYPE_RPA_RANDOM: + return "BLE_ADDR_TYPE_RPA_RANDOM"; +#endif + default: + return " esp_ble_addr_type_t"; + } +} // addressTypeToString + + +/** + * @brief Convert the BLE Advertising Data flags to a string. + * @param adFlags The flags to convert + * @return String A string representation of the advertising flags. + */ +String BLEUtils::adFlagsToString(uint8_t adFlags) { + String res; + if (adFlags & (1 << 0)) { + res += "[LE Limited Discoverable Mode] "; + } + if (adFlags & (1 << 1)) { + res += "[LE General Discoverable Mode] "; + } + if (adFlags & (1 << 2)) { + res += "[BR/EDR Not Supported] "; + } + if (adFlags & (1 << 3)) { + res += "[Simultaneous LE and BR/EDR to Same Device Capable (Controller)] "; + } + if (adFlags & (1 << 4)) { + res += "[Simultaneous LE and BR/EDR to Same Device Capable (Host)] "; + } + return res; +} // adFlagsToString + + +/** + * @brief Given an advertising type, return a string representation of the type. + * + * For details see ... + * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile + * + * @return A string representation of the type. + */ +const char* BLEUtils::advTypeToString(uint8_t advType) { + switch (advType) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_BLE_AD_TYPE_FLAG: // 0x01 + return "ESP_BLE_AD_TYPE_FLAG"; + case ESP_BLE_AD_TYPE_16SRV_PART: // 0x02 + return "ESP_BLE_AD_TYPE_16SRV_PART"; + case ESP_BLE_AD_TYPE_16SRV_CMPL: // 0x03 + return "ESP_BLE_AD_TYPE_16SRV_CMPL"; + case ESP_BLE_AD_TYPE_32SRV_PART: // 0x04 + return "ESP_BLE_AD_TYPE_32SRV_PART"; + case ESP_BLE_AD_TYPE_32SRV_CMPL: // 0x05 + return "ESP_BLE_AD_TYPE_32SRV_CMPL"; + case ESP_BLE_AD_TYPE_128SRV_PART: // 0x06 + return "ESP_BLE_AD_TYPE_128SRV_PART"; + case ESP_BLE_AD_TYPE_128SRV_CMPL: // 0x07 + return "ESP_BLE_AD_TYPE_128SRV_CMPL"; + case ESP_BLE_AD_TYPE_NAME_SHORT: // 0x08 + return "ESP_BLE_AD_TYPE_NAME_SHORT"; + case ESP_BLE_AD_TYPE_NAME_CMPL: // 0x09 + return "ESP_BLE_AD_TYPE_NAME_CMPL"; + case ESP_BLE_AD_TYPE_TX_PWR: // 0x0a + return "ESP_BLE_AD_TYPE_TX_PWR"; + case ESP_BLE_AD_TYPE_DEV_CLASS: // 0x0b + return "ESP_BLE_AD_TYPE_DEV_CLASS"; + case ESP_BLE_AD_TYPE_SM_TK: // 0x10 + return "ESP_BLE_AD_TYPE_SM_TK"; + 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 + return "ESP_BLE_AD_TYPE_INT_RANGE"; + 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 + return "ESP_BLE_AD_TYPE_128SOL_SRV_UUID"; + case ESP_BLE_AD_TYPE_SERVICE_DATA: // 0x16 + return "ESP_BLE_AD_TYPE_SERVICE_DATA"; + case ESP_BLE_AD_TYPE_PUBLIC_TARGET: // 0x17 + return "ESP_BLE_AD_TYPE_PUBLIC_TARGET"; + case ESP_BLE_AD_TYPE_RANDOM_TARGET: // 0x18 + return "ESP_BLE_AD_TYPE_RANDOM_TARGET"; + case ESP_BLE_AD_TYPE_APPEARANCE: // 0x19 + return "ESP_BLE_AD_TYPE_APPEARANCE"; + 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 + return "ESP_BLE_AD_TYPE_32SERVICE_DATA"; + 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"; +#endif + default: + log_v(" adv data type: 0x%x", advType); + return ""; + } // End switch +} // advTypeToString + + +esp_gatt_id_t BLEUtils::buildGattId(esp_bt_uuid_t uuid, uint8_t inst_id) { + esp_gatt_id_t retGattId; + retGattId.uuid = uuid; + retGattId.inst_id = inst_id; + return retGattId; +} + +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; + return retSrvcId; +} + +/** + * @brief Create a hex representation of data. + * + * @param [in] target Where to write the hex string. If this is null, we malloc storage. + * @param [in] source The start of the binary data. + * @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; + + if (target == nullptr) { + target = (uint8_t*) malloc(length * 2 + 1); + if (target == nullptr) { + log_e("buildHexData: malloc failed"); + return nullptr; + } + } + char* startOfData = (char*) target; + + for (int i = 0; i < length; i++) { + sprintf((char*) target, "%.2x", (char) *source); + source++; + target += 2; + } + + // Handle the special case where there was no data. + if (length == 0) { + *startOfData = 0; + } + + return startOfData; +} // buildHexData + + +/** + * @brief Build a printable string of memory range. + * Create a string representation of a piece of memory. Only printable characters will be included + * while those that are not printable will be replaced with '.'. + * @param [in] source Start of memory. + * @param [in] length Length of memory. + * @return A string representation of a piece of memory. + */ +String BLEUtils::buildPrintData(uint8_t* source, size_t length) { + String res; + for (int i = 0; i < length; i++) { + char c = *source; + res += (isprint(c) ? c : '.'); + source++; + } + return res; +} // buildPrintData + + +/** + * @brief Convert a close/disconnect reason to a string. + * @param [in] reason The close reason. + * @return A string representation of the reason. + */ +String BLEUtils::gattCloseReasonToString(esp_gatt_conn_reason_t reason) { + switch (reason) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_GATT_CONN_UNKNOWN: { + return "ESP_GATT_CONN_UNKNOWN"; + } + case ESP_GATT_CONN_L2C_FAILURE: { + return "ESP_GATT_CONN_L2C_FAILURE"; + } + case ESP_GATT_CONN_TIMEOUT: { + return "ESP_GATT_CONN_TIMEOUT"; + } + case ESP_GATT_CONN_TERMINATE_PEER_USER: { + return "ESP_GATT_CONN_TERMINATE_PEER_USER"; + } + case ESP_GATT_CONN_TERMINATE_LOCAL_HOST: { + return "ESP_GATT_CONN_TERMINATE_LOCAL_HOST"; + } + case ESP_GATT_CONN_FAIL_ESTABLISH: { + return "ESP_GATT_CONN_FAIL_ESTABLISH"; + } + case ESP_GATT_CONN_LMP_TIMEOUT: { + return "ESP_GATT_CONN_LMP_TIMEOUT"; + } + case ESP_GATT_CONN_CONN_CANCEL: { + return "ESP_GATT_CONN_CONN_CANCEL"; + } + case ESP_GATT_CONN_NONE: { + return "ESP_GATT_CONN_NONE"; + } +#endif + default: { + return "Unknown"; + } + } +} // gattCloseReasonToString + + +String BLEUtils::gattClientEventTypeToString(esp_gattc_cb_event_t eventType) { + switch (eventType) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_GATTC_ACL_EVT: + return "ESP_GATTC_ACL_EVT"; + case ESP_GATTC_ADV_DATA_EVT: + return "ESP_GATTC_ADV_DATA_EVT"; + case ESP_GATTC_ADV_VSC_EVT: + return "ESP_GATTC_ADV_VSC_EVT"; + case ESP_GATTC_BTH_SCAN_CFG_EVT: + return "ESP_GATTC_BTH_SCAN_CFG_EVT"; + case ESP_GATTC_BTH_SCAN_DIS_EVT: + return "ESP_GATTC_BTH_SCAN_DIS_EVT"; + case ESP_GATTC_BTH_SCAN_ENB_EVT: + return "ESP_GATTC_BTH_SCAN_ENB_EVT"; + case ESP_GATTC_BTH_SCAN_PARAM_EVT: + return "ESP_GATTC_BTH_SCAN_PARAM_EVT"; + case ESP_GATTC_BTH_SCAN_RD_EVT: + return "ESP_GATTC_BTH_SCAN_RD_EVT"; + case ESP_GATTC_BTH_SCAN_THR_EVT: + return "ESP_GATTC_BTH_SCAN_THR_EVT"; + case ESP_GATTC_CANCEL_OPEN_EVT: + return "ESP_GATTC_CANCEL_OPEN_EVT"; + case ESP_GATTC_CFG_MTU_EVT: + return "ESP_GATTC_CFG_MTU_EVT"; + case ESP_GATTC_CLOSE_EVT: + return "ESP_GATTC_CLOSE_EVT"; + case ESP_GATTC_CONGEST_EVT: + return "ESP_GATTC_CONGEST_EVT"; + case ESP_GATTC_CONNECT_EVT: + return "ESP_GATTC_CONNECT_EVT"; + case ESP_GATTC_DISCONNECT_EVT: + return "ESP_GATTC_DISCONNECT_EVT"; + case ESP_GATTC_ENC_CMPL_CB_EVT: + return "ESP_GATTC_ENC_CMPL_CB_EVT"; + case ESP_GATTC_EXEC_EVT: + return "ESP_GATTC_EXEC_EVT"; + //case ESP_GATTC_GET_CHAR_EVT: +// return "ESP_GATTC_GET_CHAR_EVT"; + //case ESP_GATTC_GET_DESCR_EVT: +// return "ESP_GATTC_GET_DESCR_EVT"; + //case ESP_GATTC_GET_INCL_SRVC_EVT: +// return "ESP_GATTC_GET_INCL_SRVC_EVT"; + case ESP_GATTC_MULT_ADV_DATA_EVT: + return "ESP_GATTC_MULT_ADV_DATA_EVT"; + case ESP_GATTC_MULT_ADV_DIS_EVT: + return "ESP_GATTC_MULT_ADV_DIS_EVT"; + case ESP_GATTC_MULT_ADV_ENB_EVT: + return "ESP_GATTC_MULT_ADV_ENB_EVT"; + case ESP_GATTC_MULT_ADV_UPD_EVT: + return "ESP_GATTC_MULT_ADV_UPD_EVT"; + case ESP_GATTC_NOTIFY_EVT: + return "ESP_GATTC_NOTIFY_EVT"; + case ESP_GATTC_OPEN_EVT: + return "ESP_GATTC_OPEN_EVT"; + case ESP_GATTC_PREP_WRITE_EVT: + return "ESP_GATTC_PREP_WRITE_EVT"; + case ESP_GATTC_READ_CHAR_EVT: + return "ESP_GATTC_READ_CHAR_EVT"; + case ESP_GATTC_REG_EVT: + return "ESP_GATTC_REG_EVT"; + case ESP_GATTC_REG_FOR_NOTIFY_EVT: + return "ESP_GATTC_REG_FOR_NOTIFY_EVT"; + case ESP_GATTC_SCAN_FLT_CFG_EVT: + return "ESP_GATTC_SCAN_FLT_CFG_EVT"; + case ESP_GATTC_SCAN_FLT_PARAM_EVT: + return "ESP_GATTC_SCAN_FLT_PARAM_EVT"; + case ESP_GATTC_SCAN_FLT_STATUS_EVT: + return "ESP_GATTC_SCAN_FLT_STATUS_EVT"; + case ESP_GATTC_SEARCH_CMPL_EVT: + return "ESP_GATTC_SEARCH_CMPL_EVT"; + case ESP_GATTC_SEARCH_RES_EVT: + return "ESP_GATTC_SEARCH_RES_EVT"; + case ESP_GATTC_SRVC_CHG_EVT: + return "ESP_GATTC_SRVC_CHG_EVT"; + case ESP_GATTC_READ_DESCR_EVT: + return "ESP_GATTC_READ_DESCR_EVT"; + case ESP_GATTC_UNREG_EVT: + return "ESP_GATTC_UNREG_EVT"; + case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: + return "ESP_GATTC_UNREG_FOR_NOTIFY_EVT"; + case ESP_GATTC_WRITE_CHAR_EVT: + return "ESP_GATTC_WRITE_CHAR_EVT"; + case ESP_GATTC_WRITE_DESCR_EVT: + return "ESP_GATTC_WRITE_DESCR_EVT"; +#endif + default: + log_v("Unknown GATT Client event type: %d", eventType); + return "Unknown"; + } +} // gattClientEventTypeToString + + +/** + * @brief Return a string representation of a GATT server event code. + * @param [in] eventType A GATT server event code. + * @return A string representation of the GATT server event code. + */ +String BLEUtils::gattServerEventTypeToString(esp_gatts_cb_event_t eventType) { + switch (eventType) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_GATTS_REG_EVT: + return "ESP_GATTS_REG_EVT"; + case ESP_GATTS_READ_EVT: + return "ESP_GATTS_READ_EVT"; + case ESP_GATTS_WRITE_EVT: + return "ESP_GATTS_WRITE_EVT"; + case ESP_GATTS_EXEC_WRITE_EVT: + return "ESP_GATTS_EXEC_WRITE_EVT"; + case ESP_GATTS_MTU_EVT: + return "ESP_GATTS_MTU_EVT"; + case ESP_GATTS_CONF_EVT: + return "ESP_GATTS_CONF_EVT"; + case ESP_GATTS_UNREG_EVT: + return "ESP_GATTS_UNREG_EVT"; + case ESP_GATTS_CREATE_EVT: + return "ESP_GATTS_CREATE_EVT"; + case ESP_GATTS_ADD_INCL_SRVC_EVT: + return "ESP_GATTS_ADD_INCL_SRVC_EVT"; + case ESP_GATTS_ADD_CHAR_EVT: + return "ESP_GATTS_ADD_CHAR_EVT"; + case ESP_GATTS_ADD_CHAR_DESCR_EVT: + return "ESP_GATTS_ADD_CHAR_DESCR_EVT"; + case ESP_GATTS_DELETE_EVT: + return "ESP_GATTS_DELETE_EVT"; + case ESP_GATTS_START_EVT: + return "ESP_GATTS_START_EVT"; + case ESP_GATTS_STOP_EVT: + return "ESP_GATTS_STOP_EVT"; + case ESP_GATTS_CONNECT_EVT: + return "ESP_GATTS_CONNECT_EVT"; + case ESP_GATTS_DISCONNECT_EVT: + return "ESP_GATTS_DISCONNECT_EVT"; + case ESP_GATTS_OPEN_EVT: + return "ESP_GATTS_OPEN_EVT"; + case ESP_GATTS_CANCEL_OPEN_EVT: + return "ESP_GATTS_CANCEL_OPEN_EVT"; + case ESP_GATTS_CLOSE_EVT: + return "ESP_GATTS_CLOSE_EVT"; + case ESP_GATTS_LISTEN_EVT: + return "ESP_GATTS_LISTEN_EVT"; + case ESP_GATTS_CONGEST_EVT: + return "ESP_GATTS_CONGEST_EVT"; + case ESP_GATTS_RESPONSE_EVT: + return "ESP_GATTS_RESPONSE_EVT"; + case ESP_GATTS_CREAT_ATTR_TAB_EVT: + return "ESP_GATTS_CREAT_ATTR_TAB_EVT"; + case ESP_GATTS_SET_ATTR_VAL_EVT: + return "ESP_GATTS_SET_ATTR_VAL_EVT"; + case ESP_GATTS_SEND_SERVICE_CHANGE_EVT: + return "ESP_GATTS_SEND_SERVICE_CHANGE_EVT"; +#endif + default: + return "Unknown"; + } +} // gattServerEventTypeToString + + + +/** + * @brief Convert a BLE device type to a string. + * @param [in] type The device type. + */ +const char* BLEUtils::devTypeToString(esp_bt_dev_type_t type) { + switch (type) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_BT_DEVICE_TYPE_BREDR: + return "ESP_BT_DEVICE_TYPE_BREDR"; + case ESP_BT_DEVICE_TYPE_BLE: + return "ESP_BT_DEVICE_TYPE_BLE"; + case ESP_BT_DEVICE_TYPE_DUMO: + return "ESP_BT_DEVICE_TYPE_DUMO"; +#endif + default: + return "Unknown"; + } +} // devTypeToString + + +/** + * @brief Dump the GAP event to the log. + */ +void BLEUtils::dumpGapEvent( + esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param) { + log_v("Received a GAP event: %s", gapEventToString(event)); + switch (event) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + // ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT + // adv_data_cmpl + // - esp_bt_status_t + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: { + log_v("[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: { + log_v("[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: { + log_v("[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: { + log_v("[status: %d]", param->adv_stop_cmpl.status); + break; + } // ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT + + // ESP_GAP_BLE_AUTH_CMPL_EVT + // + // auth_cmpl + // - esp_bd_addr_t bd_addr + // - bool key_present + // - esp_link_key key + // - bool success + // - 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: { + log_v("[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, + param->ble_security.auth_cmpl.success, + param->ble_security.auth_cmpl.fail_reason, + BLEUtils::devTypeToString(param->ble_security.auth_cmpl.dev_type) + ); + 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: { + log_v("[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: { + log_v("[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: { + log_v("[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() + ); + 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: { + log_v("[status: %d]", param->scan_param_cmpl.status); + break; + } // ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT + + // ESP_GAP_BLE_SCAN_RESULT_EVT + // + // scan_rst: + // - search_evt + // - bda + // - dev_type + // - ble_addr_type + // - ble_evt_type + // - rssi + // - ble_adv + // - flag + // - num_resps + // - adv_data_len + // - scan_rsp_len + case ESP_GAP_BLE_SCAN_RESULT_EVT: { + switch (param->scan_rst.search_evt) { + case ESP_GAP_SEARCH_INQ_RES_EVT: { + log_v("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), + addressTypeToString(param->scan_rst.ble_addr_type), + eventTypeToString(param->scan_rst.ble_evt_type), + param->scan_rst.rssi, + param->scan_rst.flag, + adFlagsToString(param->scan_rst.flag).c_str(), + param->scan_rst.num_resps, + param->scan_rst.adv_data_len, + param->scan_rst.scan_rsp_len + ); + break; + } // ESP_GAP_SEARCH_INQ_RES_EVT + + default: { + log_v("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: { + log_v("[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: { + log_v("[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: { + log_v("[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: { + log_v("[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 + // - esp_bt_status_t status + // - esp_bd_addr_t bda + // - uint16_t min_int + // - uint16_t max_int + // - uint16_t latency + // - uint16_t conn_int + // - uint16_t timeout + case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT: { + log_v("[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, + param->update_conn_params.max_int, + param->update_conn_params.latency, + param->update_conn_params.conn_int, + param->update_conn_params.timeout + ); + break; + } // ESP_GAP_BLE_SCAN_UPDATE_CONN_PARAMS_EVT + + // ESP_GAP_BLE_SEC_REQ_EVT + case ESP_GAP_BLE_SEC_REQ_EVT: { + log_v("[bd_addr: %s]", BLEAddress(param->ble_security.ble_req.bd_addr).toString().c_str()); + break; + } // ESP_GAP_BLE_SEC_REQ_EVT +#endif + default: { + log_v("*** dumpGapEvent: Logger not coded ***"); + break; + } // default + } // switch +} // dumpGapEvent + + +/** + * @brief Decode and dump a GATT client event + * + * @param [in] event The type of event received. + * @param [in] evtParam The data associated with the event. + */ +void BLEUtils::dumpGattClientEvent( + esp_gattc_cb_event_t event, + 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; + log_v("GATT Event: %s", BLEUtils::gattClientEventTypeToString(event).c_str()); + switch (event) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + // ESP_GATTC_CLOSE_EVT + // + // close: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - esp_gatt_conn_reason_t reason + case ESP_GATTC_CLOSE_EVT: { + log_v("[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: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + case ESP_GATTC_CONNECT_EVT: { + log_v("[conn_id: %d, remote_bda: %s]", + evtParam->connect.conn_id, + BLEAddress(evtParam->connect.remote_bda).toString().c_str() + ); + break; + } + + // ESP_GATTC_DISCONNECT_EVT + // + // disconnect: + // - esp_gatt_conn_reason_t reason + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + case ESP_GATTC_DISCONNECT_EVT: { + log_v("[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() + ); + break; + } // ESP_GATTC_DISCONNECT_EVT + + // 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: { + + // If the status of the event shows that we have a value other than ESP_GATT_OK then the + // characteristic fields are not set to a usable value .. so don't try and log them. + if (evtParam->get_char.status == ESP_GATT_OK) { + String description = "Unknown"; + if (evtParam->get_char.char_id.uuid.len == ESP_UUID_LEN_16) { + description = BLEUtils::gattCharacteristicUUIDToString(evtParam->get_char.char_id.uuid.uuid.uuid16); + } + log_v("[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(), + gattIdToString(evtParam->get_char.char_id).c_str(), + description.c_str(), + BLEUtils::characteristicPropertiesToString(evtParam->get_char.char_prop).c_str() + ); + } else { + log_v("[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() + ); + } + break; + } // ESP_GATTC_GET_CHAR_EVT + */ + + // ESP_GATTC_NOTIFY_EVT + // + // notify + // uint16_t conn_id + // esp_bd_addr_t remote_bda + // handle handle + // uint16_t value_len + // uint8_t* value + // bool is_notify + // + case ESP_GATTC_NOTIFY_EVT: { + log_v("[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, + evtParam->notify.handle, + evtParam->notify.value_len, + evtParam->notify.is_notify + ); + break; + } + + // ESP_GATTC_OPEN_EVT + // + // open: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - esp_bd_addr_t remote_bda + // - uint16_t mtu + // + case ESP_GATTC_OPEN_EVT: { + log_v("[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(), + evtParam->open.mtu); + break; + } // ESP_GATTC_OPEN_EVT + + // ESP_GATTC_READ_CHAR_EVT + // + // Callback to indicate that requested data that we wanted to read is now available. + // + // read: + // esp_gatt_status_t status + // uint16_t conn_id + // uint16_t handle + // uint8_t* value + // uint16_t value_type + // uint16_t value_len + case ESP_GATTC_READ_CHAR_EVT: { + log_v("[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, + evtParam->read.handle, + evtParam->read.value_len + ); + 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); + log_v("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: { + log_v("[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: { + log_v("[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 + ); + 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: { + log_v("[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: + // - uint16_t conn_id + // - uint16_t start_handle + // - uint16_t end_handle + // - esp_gatt_id_t srvc_id + case ESP_GATTC_SEARCH_RES_EVT: { + log_v("[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, + evtParam->search_res.end_handle, + evtParam->search_res.end_handle, + gattIdToString(evtParam->search_res.srvc_id).c_str()); + break; + } // ESP_GATTC_SEARCH_RES_EVT + + // ESP_GATTC_WRITE_CHAR_EVT + // + // write: + // - esp_gatt_status_t status + // - uint16_t conn_id + // - uint16_t handle + // - uint16_t offset + case ESP_GATTC_WRITE_CHAR_EVT: { + log_v("[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, + evtParam->write.handle, + evtParam->write.offset + ); + break; + } // ESP_GATTC_WRITE_CHAR_EVT +#endif + default: + break; + } +} // dumpGattClientEvent + + +/** + * @brief Dump the details of a GATT server event. + * A GATT Server event is a callback received from the BLE subsystem when we are acting as a BLE + * server. The callback indicates the type of event in the `event` field. The `evtParam` is a + * union of structures where we can use the `event` to indicate which of the structures has been + * populated and hence is valid. + * + * @param [in] event The event type that was posted. + * @param [in] evtParam A union of structures only one of which is populated. + */ +void BLEUtils::dumpGattServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* evtParam) { + log_v("GATT ServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str()); + switch (event) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + + case ESP_GATTS_ADD_CHAR_DESCR_EVT: { + log_v("[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, + evtParam->add_char_descr.service_handle, + evtParam->add_char_descr.service_handle, + BLEUUID(evtParam->add_char_descr.descr_uuid).toString().c_str()); + break; + } // ESP_GATTS_ADD_CHAR_DESCR_EVT + + case ESP_GATTS_ADD_CHAR_EVT: { + if (evtParam->add_char.status == ESP_GATT_OK) { + log_v("[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, + evtParam->add_char.service_handle, + evtParam->add_char.service_handle, + BLEUUID(evtParam->add_char.char_uuid).toString().c_str()); + } else { + log_e("[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, + evtParam->add_char.service_handle, + evtParam->add_char.service_handle, + BLEUUID(evtParam->add_char.char_uuid).toString().c_str()); + } + break; + } // ESP_GATTS_ADD_CHAR_EVT + + + // ESP_GATTS_CONF_EVT + // + // conf: + // - esp_gatt_status_t status – The status code. + // - uint16_t conn_id – The connection used. + case ESP_GATTS_CONF_EVT: { + log_v("[status: %s, conn_id: 0x%.2x]", + gattStatusToString(evtParam->conf.status).c_str(), + evtParam->conf.conn_id); + break; + } // ESP_GATTS_CONF_EVT + + + case ESP_GATTS_CONGEST_EVT: { + log_v("[conn_id: %d, congested: %d]", + evtParam->congest.conn_id, + evtParam->congest.congested); + break; + } // ESP_GATTS_CONGEST_EVT + + case ESP_GATTS_CONNECT_EVT: { + log_v("[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: { + log_v("[status: %s, service_handle: %d 0x%.2x, service_id: [%s]]", + gattStatusToString(evtParam->create.status).c_str(), + evtParam->create.service_handle, + evtParam->create.service_handle, + gattServiceIdToString(evtParam->create.service_id).c_str()); + break; + } // ESP_GATTS_CREATE_EVT + + case ESP_GATTS_DISCONNECT_EVT: { + log_v("[conn_id: %d, remote_bda: %s]", + evtParam->connect.conn_id, + BLEAddress(evtParam->connect.remote_bda).toString().c_str()); + break; + } // ESP_GATTS_DISCONNECT_EVT + + + // ESP_GATTS_EXEC_WRITE_EVT + // exec_write: + // - uint16_t conn_id + // - uint32_t trans_id + // - esp_bd_addr_t bda + // - uint8_t exec_write_flag +#ifdef ARDUHAL_LOG_LEVEL_VERBOSE + case ESP_GATTS_EXEC_WRITE_EVT: { + char* pWriteFlagText; + switch (evtParam->exec_write.exec_write_flag) { + case ESP_GATT_PREP_WRITE_EXEC: { + pWriteFlagText = (char*) "WRITE"; + break; + } + + case ESP_GATT_PREP_WRITE_CANCEL: { + pWriteFlagText = (char*) "CANCEL"; + break; + } + + default: + pWriteFlagText = (char*) ""; + break; + } + + log_v("[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(), + evtParam->exec_write.exec_write_flag, + pWriteFlagText); + break; + } // ESP_GATTS_DISCONNECT_EVT +#endif + + case ESP_GATTS_MTU_EVT: { + log_v("[conn_id: %d, mtu: %d]", + evtParam->mtu.conn_id, + evtParam->mtu.mtu); + break; + } // ESP_GATTS_MTU_EVT + + case ESP_GATTS_READ_EVT: { + log_v("[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(), + evtParam->read.handle, + evtParam->read.is_long, + evtParam->read.need_rsp); + break; + } // ESP_GATTS_READ_EVT + + case ESP_GATTS_RESPONSE_EVT: { + log_v("[status: %s, handle: 0x%.2x]", + gattStatusToString(evtParam->rsp.status).c_str(), + evtParam->rsp.handle); + break; + } // ESP_GATTS_RESPONSE_EVT + + case ESP_GATTS_REG_EVT: { + log_v("[status: %s, app_id: %d]", + gattStatusToString(evtParam->reg.status).c_str(), + evtParam->reg.app_id); + break; + } // ESP_GATTS_REG_EVT + + + // ESP_GATTS_START_EVT + // + // start: + // - esp_gatt_status_t status + // - uint16_t service_handle + case ESP_GATTS_START_EVT: { + log_v("[status: %s, service_handle: 0x%.2x]", + gattStatusToString(evtParam->start.status).c_str(), + evtParam->start.service_handle); + break; + } // ESP_GATTS_START_EVT + + + // ESP_GATTS_WRITE_EVT + // + // write: + // - uint16_t conn_id – The connection id. + // - uint16_t trans_id – The transfer id. + // - esp_bd_addr_t bda – The address of the partner. + // - uint16_t handle – The attribute handle. + // - uint16_t offset – The offset of the currently received within the whole value. + // - bool need_rsp – Do we need a response? + // - 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: { + log_v("[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(), + evtParam->write.handle, + evtParam->write.offset, + evtParam->write.need_rsp, + evtParam->write.is_prep, + evtParam->write.len); + char* pHex = buildHexData(nullptr, evtParam->write.value, evtParam->write.len); + log_v("[Data: %s]", pHex); + free(pHex); + break; + } // ESP_GATTS_WRITE_EVT +#endif + default: + log_v("dumpGattServerEvent: *** NOT CODED ***"); + break; + } +} // dumpGattServerEvent + + +/** + * @brief Convert a BLE event type to a string. + * @param [in] eventType The event type. + * @return The event type as a string. + */ +const char* BLEUtils::eventTypeToString(esp_ble_evt_type_t eventType) { + switch (eventType) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_BLE_EVT_CONN_ADV: + return "ESP_BLE_EVT_CONN_ADV"; + case ESP_BLE_EVT_CONN_DIR_ADV: + return "ESP_BLE_EVT_CONN_DIR_ADV"; + case ESP_BLE_EVT_DISC_ADV: + return "ESP_BLE_EVT_DISC_ADV"; + case ESP_BLE_EVT_NON_CONN_ADV: + return "ESP_BLE_EVT_NON_CONN_ADV"; + case ESP_BLE_EVT_SCAN_RSP: + return "ESP_BLE_EVT_SCAN_RSP"; +#endif + default: + log_v("Unknown esp_ble_evt_type_t: %d (0x%.2x)", eventType, eventType); + return "*** Unknown ***"; + } +} // eventTypeToString + + + +/** + * @brief Convert a BT GAP event type to a string representation. + * @param [in] eventType The type of event. + * @return A string representation of the event type. + */ +const char* BLEUtils::gapEventToString(uint32_t eventType) { + switch (eventType) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + 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 */ + return "ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT"; + 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 */ + return "ESP_GAP_BLE_KEY_EVT"; + 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 */ + return "ESP_GAP_BLE_LOCAL_ER_EVT"; + 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 */ + return "ESP_GAP_BLE_OOB_REQ_EVT"; + 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 */ + 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 */ + 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"; +#endif + default: + log_v("gapEventToString: Unknown event type %d 0x%.2x", eventType, eventType); + return "Unknown event type"; + } +} // gapEventToString + + +String BLEUtils::gattCharacteristicUUIDToString(uint32_t characteristicUUID) { + const characteristicMap_t* p = g_characteristicsMappings; + while (strlen(p->name) > 0) { + if (p->assignedNumber == characteristicUUID) { + return String(p->name); + } + p++; + } + return "Unknown"; +} // gattCharacteristicUUIDToString + + +/** + * @brief Given the UUID for a BLE defined descriptor, return its string representation. + * @param [in] descriptorUUID UUID of the descriptor to be returned as a string. + * @return The string representation of a descriptor UUID. + */ +String BLEUtils::gattDescriptorUUIDToString(uint32_t descriptorUUID) { + gattdescriptor_t* p = (gattdescriptor_t*) g_descriptor_ids; + while (strlen(p->name) > 0) { + if (p->assignedNumber == descriptorUUID) { + return String(p->name); + } + p++; + } + return ""; +} // gattDescriptorUUIDToString + + +/** + * @brief Return a string representation of an esp_gattc_service_elem_t. + * @return A string representation of an esp_gattc_service_elem_t. + */ +String BLEUtils::gattcServiceElementToString(esp_gattc_service_elem_t* pGATTCServiceElement) { + String res; + char val[6]; + res += "[uuid: " + BLEUUID(pGATTCServiceElement->uuid).toString() + ", start_handle: "; + snprintf(val, sizeof(val), "%d", pGATTCServiceElement->start_handle); + res += val; + res += " 0x"; + snprintf(val, sizeof(val), "%04x", pGATTCServiceElement->start_handle); + res += val; + res += ", end_handle: "; + snprintf(val, sizeof(val), "%d", pGATTCServiceElement->end_handle); + res += val; + res += " 0x"; + snprintf(val, sizeof(val), "%04x", pGATTCServiceElement->end_handle); + res += val; + res += "]"; + return res; +} // gattcServiceElementToString + + +/** + * @brief Convert an esp_gatt_srvc_id_t to a string. + */ +String BLEUtils::gattServiceIdToString(esp_gatt_srvc_id_t srvcId) { + return gattIdToString(srvcId.id); +} // gattServiceIdToString + + +String BLEUtils::gattServiceToString(uint32_t serviceId) { + gattService_t* p = (gattService_t*) g_gattServices; + while (strlen(p->name) > 0) { + if (p->assignedNumber == serviceId) { + return String(p->name); + } + p++; + } + return "Unknown"; +} // gattServiceToString + + +/** + * @brief Convert a GATT status to a string. + * + * @param [in] status The status to convert. + * @return A string representation of the status. + */ +String BLEUtils::gattStatusToString(esp_gatt_status_t status) { + switch (status) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_GATT_OK: + return "ESP_GATT_OK"; + case ESP_GATT_INVALID_HANDLE: + return "ESP_GATT_INVALID_HANDLE"; + case ESP_GATT_READ_NOT_PERMIT: + return "ESP_GATT_READ_NOT_PERMIT"; + case ESP_GATT_WRITE_NOT_PERMIT: + return "ESP_GATT_WRITE_NOT_PERMIT"; + case ESP_GATT_INVALID_PDU: + return "ESP_GATT_INVALID_PDU"; + case ESP_GATT_INSUF_AUTHENTICATION: + return "ESP_GATT_INSUF_AUTHENTICATION"; + case ESP_GATT_REQ_NOT_SUPPORTED: + return "ESP_GATT_REQ_NOT_SUPPORTED"; + case ESP_GATT_INVALID_OFFSET: + return "ESP_GATT_INVALID_OFFSET"; + case ESP_GATT_INSUF_AUTHORIZATION: + return "ESP_GATT_INSUF_AUTHORIZATION"; + case ESP_GATT_PREPARE_Q_FULL: + return "ESP_GATT_PREPARE_Q_FULL"; + case ESP_GATT_NOT_FOUND: + return "ESP_GATT_NOT_FOUND"; + case ESP_GATT_NOT_LONG: + return "ESP_GATT_NOT_LONG"; + case ESP_GATT_INSUF_KEY_SIZE: + return "ESP_GATT_INSUF_KEY_SIZE"; + case ESP_GATT_INVALID_ATTR_LEN: + return "ESP_GATT_INVALID_ATTR_LEN"; + case ESP_GATT_ERR_UNLIKELY: + return "ESP_GATT_ERR_UNLIKELY"; + case ESP_GATT_INSUF_ENCRYPTION: + return "ESP_GATT_INSUF_ENCRYPTION"; + case ESP_GATT_UNSUPPORT_GRP_TYPE: + return "ESP_GATT_UNSUPPORT_GRP_TYPE"; + case ESP_GATT_INSUF_RESOURCE: + return "ESP_GATT_INSUF_RESOURCE"; + case ESP_GATT_NO_RESOURCES: + return "ESP_GATT_NO_RESOURCES"; + case ESP_GATT_INTERNAL_ERROR: + return "ESP_GATT_INTERNAL_ERROR"; + case ESP_GATT_WRONG_STATE: + return "ESP_GATT_WRONG_STATE"; + case ESP_GATT_DB_FULL: + return "ESP_GATT_DB_FULL"; + case ESP_GATT_BUSY: + return "ESP_GATT_BUSY"; + case ESP_GATT_ERROR: + return "ESP_GATT_ERROR"; + case ESP_GATT_CMD_STARTED: + return "ESP_GATT_CMD_STARTED"; + case ESP_GATT_ILLEGAL_PARAMETER: + return "ESP_GATT_ILLEGAL_PARAMETER"; + case ESP_GATT_PENDING: + return "ESP_GATT_PENDING"; + case ESP_GATT_AUTH_FAIL: + return "ESP_GATT_AUTH_FAIL"; + case ESP_GATT_MORE: + return "ESP_GATT_MORE"; + case ESP_GATT_INVALID_CFG: + return "ESP_GATT_INVALID_CFG"; + case ESP_GATT_SERVICE_STARTED: + return "ESP_GATT_SERVICE_STARTED"; + case ESP_GATT_ENCRYPTED_NO_MITM: + return "ESP_GATT_ENCRYPTED_NO_MITM"; + case ESP_GATT_NOT_ENCRYPTED: + return "ESP_GATT_NOT_ENCRYPTED"; + case ESP_GATT_CONGESTED: + return "ESP_GATT_CONGESTED"; + case ESP_GATT_DUP_REG: + return "ESP_GATT_DUP_REG"; + case ESP_GATT_ALREADY_OPEN: + return "ESP_GATT_ALREADY_OPEN"; + case ESP_GATT_CANCEL: + return "ESP_GATT_CANCEL"; + case ESP_GATT_STACK_RSP: + return "ESP_GATT_STACK_RSP"; + case ESP_GATT_APP_RSP: + return "ESP_GATT_APP_RSP"; + case ESP_GATT_UNKNOWN_ERROR: + return "ESP_GATT_UNKNOWN_ERROR"; + case ESP_GATT_CCC_CFG_ERR: + return "ESP_GATT_CCC_CFG_ERR"; + case ESP_GATT_PRC_IN_PROGRESS: + return "ESP_GATT_PRC_IN_PROGRESS"; + case ESP_GATT_OUT_OF_RANGE: + return "ESP_GATT_OUT_OF_RANGE"; +#endif + default: + return "Unknown"; + } +} // gattStatusToString + + + +String BLEUtils::getMember(uint32_t memberId) { + member_t* p = (member_t*) members_ids; + + while (strlen(p->name) > 0) { + if (p->assignedNumber == memberId) { + return String(p->name); + } + p++; + } + return "Unknown"; +} + +/** + * @brief convert a GAP search event to a string. + * @param [in] searchEvt + * @return The search event type as a string. + */ +const char* BLEUtils::searchEventTypeToString(esp_gap_search_evt_t searchEvt) { + switch (searchEvt) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_GAP_SEARCH_INQ_RES_EVT: + return "ESP_GAP_SEARCH_INQ_RES_EVT"; + case ESP_GAP_SEARCH_INQ_CMPL_EVT: + return "ESP_GAP_SEARCH_INQ_CMPL_EVT"; + case ESP_GAP_SEARCH_DISC_RES_EVT: + return "ESP_GAP_SEARCH_DISC_RES_EVT"; + case ESP_GAP_SEARCH_DISC_BLE_RES_EVT: + return "ESP_GAP_SEARCH_DISC_BLE_RES_EVT"; + case ESP_GAP_SEARCH_DISC_CMPL_EVT: + return "ESP_GAP_SEARCH_DISC_CMPL_EVT"; + case ESP_GAP_SEARCH_DI_DISC_CMPL_EVT: + return "ESP_GAP_SEARCH_DI_DISC_CMPL_EVT"; + case ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT: + return "ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT"; +#endif + default: + log_v("Unknown event type: 0x%x", searchEvt); + return "Unknown event type"; + } +} // searchEventTypeToString + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUtils.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUtils.h new file mode 100644 index 0000000..d0ec834 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEUtils.h @@ -0,0 +1,67 @@ +/* + * BLEUtils.h + * + * Created on: Mar 25, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEUTILS_H_ +#define COMPONENTS_CPP_UTILS_BLEUTILS_H_ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include // ESP32 BLE +#include // ESP32 BLE +#include // ESP32 BLE +#include +#include "BLEClient.h" + +/** + * @brief A set of general %BLE utilities. + */ +class BLEUtils { +public: + static const char* addressTypeToString(esp_ble_addr_type_t type); + static String adFlagsToString(uint8_t adFlags); + static const char* advTypeToString(uint8_t advType); + static char* buildHexData(uint8_t* target, uint8_t* source, uint8_t length); + static String buildPrintData(uint8_t* source, size_t length); + static 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); + static void dumpGattClientEvent( + esp_gattc_cb_event_t event, + esp_gatt_if_t gattc_if, + esp_ble_gattc_cb_param_t* evtParam); + static void dumpGattServerEvent( + esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* evtParam); + static const char* eventTypeToString(esp_ble_evt_type_t eventType); + static BLEClient* findByAddress(BLEAddress address); + static BLEClient* findByConnId(uint16_t conn_id); + static const char* gapEventToString(uint32_t eventType); + static String gattCharacteristicUUIDToString(uint32_t characteristicUUID); + static String gattClientEventTypeToString(esp_gattc_cb_event_t eventType); + static String gattCloseReasonToString(esp_gatt_conn_reason_t reason); + static String gattcServiceElementToString(esp_gattc_service_elem_t* pGATTCServiceElement); + static String gattDescriptorUUIDToString(uint32_t descriptorUUID); + static String gattServerEventTypeToString(esp_gatts_cb_event_t eventType); + static String gattServiceIdToString(esp_gatt_srvc_id_t srvcId); + static String gattServiceToString(uint32_t serviceId); + static String gattStatusToString(esp_gatt_status_t status); + static String getMember(uint32_t memberId); + static void registerByAddress(BLEAddress address, BLEClient* pDevice); + static void registerByConnId(uint16_t conn_id, BLEClient* pDevice); + static const char* searchEventTypeToString(esp_gap_search_evt_t searchEvt); +}; + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEUTILS_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEValue.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEValue.cpp new file mode 100644 index 0000000..e67bba4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEValue.cpp @@ -0,0 +1,134 @@ +/* + * BLEValue.cpp + * + * Created on: Jul 17, 2017 + * Author: kolban + */ +#include "soc/soc_caps.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) +#include "BLEValue.h" +#include "esp32-hal-log.h" + +BLEValue::BLEValue() { + m_accumulation = ""; + m_value = ""; + m_readOffset = 0; +} // BLEValue + + +/** + * @brief Add a message part to the accumulation. + * The accumulation is a growing set of data that is added to until a commit or cancel. + * @param [in] part A message part being added. + */ +void BLEValue::addPart(String part) { + log_v(">> addPart: length=%d", part.length()); + m_accumulation += part; +} // addPart + + +/** + * @brief Add a message part to the accumulation. + * The accumulation is a growing set of data that is added to until a commit or cancel. + * @param [in] pData A message part being added. + * @param [in] length The number of bytes being added. + */ +void BLEValue::addPart(uint8_t* pData, size_t length) { + log_v(">> addPart: length=%d", length); + m_accumulation += String((char*) pData, length); +} // addPart + + +/** + * @brief Cancel the current accumulation. + */ +void BLEValue::cancel() { + log_v(">> cancel"); + m_accumulation = ""; + m_readOffset = 0; +} // cancel + + +/** + * @brief Commit the current accumulation. + * When writing a value, we may find that we write it in "parts" meaning that the writes come in in pieces + * of the overall message. After the last part has been received, we may perform a commit which means that + * we now have the complete message and commit the change as a unit. + */ +void BLEValue::commit() { + log_v(">> commit"); + // If there is nothing to commit, do nothing. + if (m_accumulation.length() == 0) return; + setValue(m_accumulation); + m_accumulation = ""; + m_readOffset = 0; +} // commit + + +/** + * @brief Get a pointer to the data. + * @return A pointer to the data. + */ +uint8_t* BLEValue::getData() { + return (uint8_t*) m_value.c_str(); +} + + +/** + * @brief Get the length of the data in bytes. + * @return The length of the data in bytes. + */ +size_t BLEValue::getLength() { + return m_value.length(); +} // getLength + + +/** + * @brief Get the read offset. + * @return The read offset into the read. + */ +uint16_t BLEValue::getReadOffset() { + return m_readOffset; +} // getReadOffset + + +/** + * @brief Get the current value. + */ +String BLEValue::getValue() { + return m_value; +} // getValue + + +/** + * @brief Set the read offset + * @param [in] readOffset The offset into the read. + */ +void BLEValue::setReadOffset(uint16_t readOffset) { + m_readOffset = readOffset; +} // setReadOffset + + +/** + * @brief Set the current value. + */ +void BLEValue::setValue(String value) { + m_value = value; +} // setValue + + +/** + * @brief Set the current value. + * @param [in] pData The data for the current value. + * @param [in] The length of the new current value. + */ +void BLEValue::setValue(uint8_t* pData, size_t length) { + m_value = String((char*) pData, length); +} // setValue + + +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEValue.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEValue.h new file mode 100644 index 0000000..0740a69 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/BLEValue.h @@ -0,0 +1,43 @@ +/* + * BLEValue.h + * + * Created on: Jul 17, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_BLEVALUE_H_ +#define COMPONENTS_CPP_UTILS_BLEVALUE_H_ +#include "soc/soc_caps.h" +#include "WString.h" +#if SOC_BLE_SUPPORTED + +#include "sdkconfig.h" +#if defined(CONFIG_BLUEDROID_ENABLED) + +/** + * @brief The model of a %BLE value. + */ +class BLEValue { +public: + BLEValue(); + void addPart(String part); + void addPart(uint8_t* pData, size_t length); + void cancel(); + void commit(); + uint8_t* getData(); + size_t getLength(); + uint16_t getReadOffset(); + String getValue(); + void setReadOffset(uint16_t readOffset); + void setValue(String value); + void setValue(uint8_t* pData, size_t length); + +private: + String m_accumulation; + uint16_t m_readOffset; + String m_value; + +}; +#endif /* CONFIG_BLUEDROID_ENABLED */ +#endif /* SOC_BLE_SUPPORTED */ +#endif /* COMPONENTS_CPP_UTILS_BLEVALUE_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/FreeRTOS.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/FreeRTOS.cpp new file mode 100644 index 0000000..6941727 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/FreeRTOS.cpp @@ -0,0 +1,306 @@ +/* + * FreeRTOS.cpp + * + * Created on: Feb 24, 2017 + * Author: kolban + */ +#include // Include the base FreeRTOS definitions +#include // Include the task definitions +#include // Include the semaphore definitions +#include +#include +#include +#include "RTOS.h" +#include "sdkconfig.h" +#include "esp32-hal-log.h" + +/** + * 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); +} // sleep + + +/** + * Start a new task. + * @param[in] task The function pointer to the function to be run in the task. + * @param[in] taskName A string identifier for the task. + * @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*), String taskName, void* param, uint32_t stackSize) { + ::xTaskCreate(task, taskName.c_str(), stackSize, param, 5, NULL); +} // startTask + + +/** + * Delete the task. + * @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted. + */ +void FreeRTOS::deleteTask(TaskHandle_t pTask) { + ::vTaskDelete(pTask); +} // deleteTask + + +/** + * Get the time in milliseconds since the %FreeRTOS scheduler started. + * @return The time in milliseconds since the %FreeRTOS scheduler started. + */ +uint32_t FreeRTOS::getTimeSinceStart() { + return (uint32_t) (xTaskGetTickCount() * portTICK_PERIOD_MS); +} // getTimeSinceStart + + +/** + * @brief Wait for a semaphore to be released by trying to take it and + * then releasing it again. + * @param [in] owner A debug tag. + * @return The value associated with the semaphore. + */ +uint32_t FreeRTOS::Semaphore::wait(String owner) { + log_v(">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str()); + + if (m_usePthreads) { + pthread_mutex_lock(&m_pthread_mutex); + } else { + xSemaphoreTake(m_semaphore, portMAX_DELAY); + } + + if (m_usePthreads) { + pthread_mutex_unlock(&m_pthread_mutex); + } else { + xSemaphoreGive(m_semaphore); + } + + log_v("<< wait: Semaphore released: %s", toString().c_str()); + return m_value; +} // wait + +/** + * @brief Wait for a semaphore to be released in a given period of time by trying to take it and + * then releasing it again. The value associated with the semaphore can be taken by value() call after return + * @param [in] owner A debug tag. + * @param [in] timeoutMs timeout to wait in ms. + * @return True if we took the semaphore within timeframe. + */ +bool FreeRTOS::Semaphore::timedWait(String owner, uint32_t timeoutMs) { + log_v(">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str()); + + if (m_usePthreads && timeoutMs != portMAX_DELAY) { + assert(false); // We apparently don't have a timed wait for pthreads. + } + + auto ret = pdTRUE; + + if (m_usePthreads) { + pthread_mutex_lock(&m_pthread_mutex); + } else { + ret = xSemaphoreTake(m_semaphore, timeoutMs); + } + + if (m_usePthreads) { + pthread_mutex_unlock(&m_pthread_mutex); + } else { + xSemaphoreGive(m_semaphore); + } + + log_v("<< wait: Semaphore %s released: %d", toString().c_str(), ret); + return ret; +} // wait + + +FreeRTOS::Semaphore::Semaphore(String name) { + m_usePthreads = false; // Are we using pThreads or FreeRTOS? + if (m_usePthreads) { + pthread_mutex_init(&m_pthread_mutex, nullptr); + } else { + m_semaphore = xSemaphoreCreateBinary(); + xSemaphoreGive(m_semaphore); + } + + m_name = name; + m_owner = String(""); + m_value = 0; +} + + +FreeRTOS::Semaphore::~Semaphore() { + if (m_usePthreads) { + pthread_mutex_destroy(&m_pthread_mutex); + } else { + vSemaphoreDelete(m_semaphore); + } +} + + +/** + * @brief Give a semaphore. + * The Semaphore is given. + */ +void FreeRTOS::Semaphore::give() { + log_v("Semaphore giving: %s", toString().c_str()); + m_owner = String(""); + + if (m_usePthreads) { + pthread_mutex_unlock(&m_pthread_mutex); + } else { + xSemaphoreGive(m_semaphore); + } +// #ifdef ARDUINO_ARCH_ESP32 +// FreeRTOS::sleep(10); +// #endif + +} // Semaphore::give + + +/** + * @brief Give a semaphore. + * The Semaphore is given with an associated value. + * @param [in] value The value to associate with the semaphore. + */ +void FreeRTOS::Semaphore::give(uint32_t value) { + m_value = value; + give(); +} // give + + +/** + * @brief Give a semaphore from an ISR. + */ +void FreeRTOS::Semaphore::giveFromISR() { + BaseType_t higherPriorityTaskWoken; + if (m_usePthreads) { + assert(false); + } else { + xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken); + } +} // giveFromISR + + +/** + * @brief Take a semaphore. + * Take a semaphore and wait indefinitely. + * @param [in] owner The new owner (for debugging) + * @return True if we took the semaphore. + */ +bool FreeRTOS::Semaphore::take(String owner) { + log_v("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) == pdTRUE; + } + if (rc) { + m_owner = owner; + log_v("Semaphore taken: %s", toString().c_str()); + } else { + log_e("Semaphore NOT taken: %s", toString().c_str()); + } + return rc; +} // Semaphore::take + + +/** + * @brief Take a semaphore. + * Take a semaphore but return if we haven't obtained it in the given period of milliseconds. + * @param [in] timeoutMs Timeout in milliseconds. + * @param [in] owner The new owner (for debugging) + * @return True if we took the semaphore. + */ +bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, String owner) { + log_v("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) == pdTRUE; + } + if (rc) { + m_owner = owner; + log_v("Semaphore taken: %s", toString().c_str()); + } else { + log_e("Semaphore NOT taken: %s", toString().c_str()); + } + return rc; +} // Semaphore::take + + + +/** + * @brief Create a string representation of the semaphore. + * @return A string representation of the semaphore. + */ +String FreeRTOS::Semaphore::toString() { + char hex[9]; + String res = "name: " + m_name + " (0x"; + snprintf(hex, sizeof(hex), "%08lx", (uint32_t)m_semaphore); + res += hex; + res += "), owner: " + m_owner; + return res; +} // toString + + +/** + * @brief Set the name of the semaphore. + * @param [in] name The name of the semaphore. + */ +void FreeRTOS::Semaphore::setName(String name) { + m_name = name; +} // setName + + +/** + * @brief Create a ring buffer. + * @param [in] length The amount of storage to allocate for the ring buffer. + * @param [in] type The type of buffer. One of RINGBUF_TYPE_NOSPLIT, RINGBUF_TYPE_ALLOWSPLIT, RINGBUF_TYPE_BYTEBUF. + */ +#ifdef ESP_IDF_VERSION_MAJOR +Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type) +#else +Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) +#endif +{ + m_handle = ::xRingbufferCreate(length, type); +} // Ringbuffer + + +Ringbuffer::~Ringbuffer() { + ::vRingbufferDelete(m_handle); +} // ~Ringbuffer + + +/** + * @brief Receive data from the buffer. + * @param [out] size On return, the size of data returned. + * @param [in] wait How long to wait. + * @return A pointer to the storage retrieved. + */ +void* Ringbuffer::receive(size_t* size, TickType_t wait) { + return ::xRingbufferReceive(m_handle, size, wait); +} // receive + + +/** + * @brief Return an item. + * @param [in] item The item to be returned/released. + */ +void Ringbuffer::returnItem(void* item) { + ::vRingbufferReturnItem(m_handle, item); +} // returnItem + + +/** + * @brief Send data to the buffer. + * @param [in] data The data to place into the buffer. + * @param [in] length The length of data to place into the buffer. + * @param [in] wait How long to wait before giving up. The default is to wait indefinitely. + * @return + */ +bool Ringbuffer::send(void* data, size_t length, TickType_t wait) { + return ::xRingbufferSend(m_handle, data, length, wait) == pdTRUE; +} // send + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/GeneralUtils.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/GeneralUtils.cpp new file mode 100644 index 0000000..0c86bf4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/GeneralUtils.cpp @@ -0,0 +1,549 @@ +/* + * GeneralUtils.cpp + * + * Created on: May 20, 2017 + * Author: kolban + */ + +#include "GeneralUtils.h" +#include +#include +#include +#include +#include +#include +#include "RTOS.h" +#include +#include +#include +#include +#include +#include "esp_chip_info.h" +#include "esp32-hal-log.h" + +static const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +static int base64EncodedLength(size_t length) { + return (length + 2 - ((length + 2) % 3)) / 3 * 4; +} // base64EncodedLength + + +static int base64EncodedLength(const String& in) { + return base64EncodedLength(in.length()); +} // base64EncodedLength + + +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); + a4[3] = (a3[2] & 0x3f); +} // a3_to_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]; +} // a4_to_a3 + + +/** + * @brief Encode a string into base 64. + * @param [in] in + * @param [out] out + */ +bool GeneralUtils::base64Encode(const String& in, String* out) { + std::string std_in(in.c_str()); + std::string std_out(out->c_str()); + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + std_out.resize(base64EncodedLength(in)); + + int input_len = std_in.length(); + std::string::const_iterator input = std_in.begin(); + + while (input_len--) { + a3[i++] = *(input++); + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + (std_out)[enc_len++] = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + (std_out)[enc_len++] = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + (std_out)[enc_len++] = '='; + } + } + *out = String(std_out.c_str()); + + return (enc_len == out->length()); +} // base64Encode + + +/** + * @brief Dump general info to the log. + * Data includes: + * * Amount of free RAM + */ +void GeneralUtils::dumpInfo() { + esp_chip_info_t chipInfo; + esp_chip_info(&chipInfo); + log_v("--- dumpInfo ---"); + log_v("Free heap: %d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); + log_v("Chip Info: Model: %d, cores: %d, revision: %d", chipInfo.model, chipInfo.cores, chipInfo.revision); + log_v("ESP-IDF version: %s", esp_get_idf_version()); + log_v("---"); +} // dumpInfo + + +/** + * @brief Does the string end with a specific character? + * @param [in] str The string to examine. + * @param [in] c The character to look form. + * @return True if the string ends with the given character. + */ +bool GeneralUtils::endsWith(String str, char c) { + if (str.length() == 0) { + return false; + } + if (str.charAt(str.length() - 1) == c) { + return true; + } + return false; +} // endsWidth + +/* +static int DecodedLength(const String& in) { + int numEq = 0; + int n = (int) in.length(); + + //for (String::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { + for (int it = in.length()-1; in.charAt(it) == '='; --it) { + ++numEq; + } + return ((6 * n) / 8) - numEq; +} // DecodedLength +*/ + +static unsigned char b64_lookup(unsigned char c) { + if(c >='A' && c <='Z') return c - 'A'; + if(c >='a' && c <='z') return c - 71; + if(c >='0' && c <='9') return c + 4; + if(c == '+') return 62; + if(c == '/') return 63; + return 255; +}; // b64_lookup + + +/** + * @brief Decode a chunk of data that is base64 encoded. + * @param [in] in The string to be decoded. + * @param [out] out The resulting data. + */ +bool GeneralUtils::base64Decode(const String& in, String* out) { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + int input_len = in.length(); + int input_iterator = 0; + + //out->resize(DecodedLength(in)); + + while (input_len--) { + //if (*input == '=') { + if (in[input_iterator] == '=') { + break; + } + + a4[i++] = in[input_iterator++]; + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + out->concat(a3[i]); + dec_len++; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + (*out)[dec_len++] = a3[j]; + } + } + + return (dec_len == out->length()); + } // base64Decode + +/* +void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { + uint32_t index=0; + Stringstream ascii; + Stringstream hex; + char asciiBuf[80]; + char hexBuf[80]; + hex.str(""); + ascii.str(""); + while(index < length) { + hex << std::setfill('0') << std::setw(2) << std::hex << (int)pData[index] << ' '; + if (std::isprint(pData[index])) { + ascii << pData[index]; + } else { + ascii << '.'; + } + index++; + if (index % 16 == 0) { + strcpy(hexBuf, hex.str().c_str()); + strcpy(asciiBuf, ascii.str().c_str()); + log_v("%s %s", hexBuf, asciiBuf); + hex.str(""); + ascii.str(""); + } + } + if (index %16 != 0) { + while(index % 16 != 0) { + hex << " "; + index++; + } + strcpy(hexBuf, hex.str().c_str()); + strcpy(asciiBuf, ascii.str().c_str()); + log_v("%s %s", hexBuf, asciiBuf); + //log_v("%s %s", hex.str().c_str(), ascii.str().c_str()); + } + FreeRTOS::sleep(1000); +} +*/ + +/* +void GeneralUtils::hexDump(uint8_t* pData, uint32_t length) { + uint32_t index=0; + static Stringstream ascii; + static Stringstream hex; + hex.str(""); + ascii.str(""); + while(index < length) { + hex << std::setfill('0') << std::setw(2) << std::hex << (int)pData[index] << ' '; + if (std::isprint(pData[index])) { + ascii << pData[index]; + } else { + ascii << '.'; + } + index++; + if (index % 16 == 0) { + log_v("%s %s", hex.str().c_str(), ascii.str().c_str()); + hex.str(""); + ascii.str(""); + } + } + if (index %16 != 0) { + while(index % 16 != 0) { + hex << " "; + index++; + } + log_v("%s %s", hex.str().c_str(), ascii.str().c_str()); + } + FreeRTOS::sleep(1000); +} +*/ + + +/** + * @brief Dump a representation of binary data to the console. + * + * @param [in] pData Pointer to the start of data to be logged. + * @param [in] length Length of the data (in bytes) to be logged. + * @return N/A. + */ +void GeneralUtils::hexDump(const uint8_t* pData, uint32_t length) { + char ascii[80]; + char hex[80]; + char tempBuf[80]; + uint32_t lineNumber = 0; + + log_v(" 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"); + log_v(" -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); + strcpy(ascii, ""); + strcpy(hex, ""); + uint32_t index = 0; + while (index < length) { + sprintf(tempBuf, "%.2x ", pData[index]); + strcat(hex, tempBuf); + if (isprint(pData[index])) { + sprintf(tempBuf, "%c", pData[index]); + } else { + sprintf(tempBuf, "."); + } + strcat(ascii, tempBuf); + index++; + if (index % 16 == 0) { + log_v("%.4x %s %s", lineNumber * 16, hex, ascii); + strcpy(ascii, ""); + strcpy(hex, ""); + lineNumber++; + } + } + if (index %16 != 0) { + while (index % 16 != 0) { + strcat(hex, " "); + index++; + } + log_v("%.4x %s %s", lineNumber * 16, hex, ascii); + } +} // hexDump + + +/** + * @brief Convert an IP address to string. + * @param ip The 4 byte IP address. + * @return A string representation of the IP address. + */ +String GeneralUtils::ipToString(uint8_t *ip) { + auto size = 16; + char *val = (char*)malloc(size); + snprintf(val, size, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + String res(val); + free(val); + return res; +} // ipToString + + +/** + * @brief Split a string into parts based on a delimiter. + * @param [in] source The source string to split. + * @param [in] delimiter The delimiter characters. + * @return A vector of strings that are the split of the input. + */ +std::vector GeneralUtils::split(String source, char delimiter) { + // See also: https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g + std::vector strings; + std::size_t current, previous = 0; + std::string std_source(source.c_str()); + current = std_source.find(delimiter); + while (current != std::string::npos) { + strings.push_back(trim(source.substring(previous, current))); + previous = current + 1; + current = std_source.find(delimiter, previous); + } + strings.push_back(trim(source.substring(previous, current))); + return strings; +} // split + + +/** + * @brief Convert an ESP error code to a string. + * @param [in] errCode The errCode to be converted. + * @return A string representation of the error code. + */ +const char* GeneralUtils::errorToString(esp_err_t errCode) { + switch (errCode) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + case ESP_OK: + return "ESP_OK"; + case ESP_FAIL: + return "ESP_FAIL"; + case ESP_ERR_NO_MEM: + return "ESP_ERR_NO_MEM"; + case ESP_ERR_INVALID_ARG: + return "ESP_ERR_INVALID_ARG"; + case ESP_ERR_INVALID_SIZE: + return "ESP_ERR_INVALID_SIZE"; + case ESP_ERR_INVALID_STATE: + return "ESP_ERR_INVALID_STATE"; + case ESP_ERR_NOT_FOUND: + return "ESP_ERR_NOT_FOUND"; + case ESP_ERR_NOT_SUPPORTED: + return "ESP_ERR_NOT_SUPPORTED"; + case ESP_ERR_TIMEOUT: + return "ESP_ERR_TIMEOUT"; + case ESP_ERR_NVS_NOT_INITIALIZED: + return "ESP_ERR_NVS_NOT_INITIALIZED"; + case ESP_ERR_NVS_NOT_FOUND: + return "ESP_ERR_NVS_NOT_FOUND"; + case ESP_ERR_NVS_TYPE_MISMATCH: + return "ESP_ERR_NVS_TYPE_MISMATCH"; + case ESP_ERR_NVS_READ_ONLY: + return "ESP_ERR_NVS_READ_ONLY"; + case ESP_ERR_NVS_NOT_ENOUGH_SPACE: + return "ESP_ERR_NVS_NOT_ENOUGH_SPACE"; + case ESP_ERR_NVS_INVALID_NAME: + return "ESP_ERR_NVS_INVALID_NAME"; + case ESP_ERR_NVS_INVALID_HANDLE: + return "ESP_ERR_NVS_INVALID_HANDLE"; + case ESP_ERR_NVS_REMOVE_FAILED: + return "ESP_ERR_NVS_REMOVE_FAILED"; + case ESP_ERR_NVS_KEY_TOO_LONG: + return "ESP_ERR_NVS_KEY_TOO_LONG"; + case ESP_ERR_NVS_PAGE_FULL: + return "ESP_ERR_NVS_PAGE_FULL"; + case ESP_ERR_NVS_INVALID_STATE: + return "ESP_ERR_NVS_INVALID_STATE"; + case ESP_ERR_NVS_INVALID_LENGTH: + return "ESP_ERR_NVS_INVALID_LENGTH"; + case ESP_ERR_WIFI_NOT_INIT: + return "ESP_ERR_WIFI_NOT_INIT"; + //case ESP_ERR_WIFI_NOT_START: + // return "ESP_ERR_WIFI_NOT_START"; + case ESP_ERR_WIFI_IF: + return "ESP_ERR_WIFI_IF"; + case ESP_ERR_WIFI_MODE: + return "ESP_ERR_WIFI_MODE"; + case ESP_ERR_WIFI_STATE: + return "ESP_ERR_WIFI_STATE"; + case ESP_ERR_WIFI_CONN: + return "ESP_ERR_WIFI_CONN"; + case ESP_ERR_WIFI_NVS: + return "ESP_ERR_WIFI_NVS"; + case ESP_ERR_WIFI_MAC: + return "ESP_ERR_WIFI_MAC"; + case ESP_ERR_WIFI_SSID: + return "ESP_ERR_WIFI_SSID"; + case ESP_ERR_WIFI_PASSWORD: + return "ESP_ERR_WIFI_PASSWORD"; + case ESP_ERR_WIFI_TIMEOUT: + return "ESP_ERR_WIFI_TIMEOUT"; + case ESP_ERR_WIFI_WAKE_FAIL: + return "ESP_ERR_WIFI_WAKE_FAIL"; +#endif + default: + 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) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG + 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"; + } +} // wifiErrorToString + + +/** + * @brief Convert a string to lower case. + * @param [in] value The string to convert to lower case. + * @return A lower case representation of the string. + */ +String GeneralUtils::toLower(String& value) { + // Question: Could this be improved with a signature of: + // String& GeneralUtils::toLower(String& value) + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + return value; +} // toLower + + +/** + * @brief Remove white space from a string. + */ +String GeneralUtils::trim(const String& str) { + std::string std_str(str.c_str()); + size_t first = std_str.find_first_not_of(' '); + if (std::string::npos == first) return str; + size_t last = std_str.find_last_not_of(' '); + return str.substring(first, (last + 1)); +} // trim diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/GeneralUtils.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/GeneralUtils.h new file mode 100644 index 0000000..285261b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/GeneralUtils.h @@ -0,0 +1,36 @@ +/* + * GeneralUtils.h + * + * Created on: May 20, 2017 + * Author: kolban + */ + +#ifndef COMPONENTS_CPP_UTILS_GENERALUTILS_H_ +#define COMPONENTS_CPP_UTILS_GENERALUTILS_H_ +#include "Arduino.h" +#include +#include +#include +#include +#include + +/** + * @brief General utilities. + */ +class GeneralUtils { +public: + static bool base64Decode(const String& in, String* out); + static bool base64Encode(const String& in, String* out); + static void dumpInfo(); + static bool endsWith(String str, char c); + static const char* errorToString(esp_err_t errCode); + static const char* wifiErrorToString(uint8_t value); + static void hexDump(const uint8_t* pData, uint32_t length); + static String ipToString(uint8_t* ip); + static std::vector split(String source, char delimiter); + static String toLower(String& value); + static String trim(const String& str); + +}; + +#endif /* COMPONENTS_CPP_UTILS_GENERALUTILS_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/HIDKeyboardTypes.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/HIDKeyboardTypes.h new file mode 100644 index 0000000..4e221d5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/HIDKeyboardTypes.h @@ -0,0 +1,402 @@ +/* Copyright (c) 2015 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Note: this file was pulled from different parts of the USBHID library, in mbed SDK + */ + +#ifndef KEYBOARD_DEFS_H +#define KEYBOARD_DEFS_H + +#define REPORT_ID_KEYBOARD 1 +#define REPORT_ID_VOLUME 3 + +/* Modifiers */ +enum MODIFIER_KEY { + KEY_CTRL = 1, + KEY_SHIFT = 2, + KEY_ALT = 4, +}; + + +enum MEDIA_KEY { + KEY_NEXT_TRACK, /*!< next Track Button */ + KEY_PREVIOUS_TRACK, /*!< Previous track Button */ + KEY_STOP, /*!< Stop Button */ + KEY_PLAY_PAUSE, /*!< Play/Pause Button */ + KEY_MUTE, /*!< Mute Button */ + KEY_VOLUME_UP, /*!< Volume Up Button */ + KEY_VOLUME_DOWN, /*!< Volume Down Button */ +}; + +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_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 */ +}; + +typedef struct { + unsigned char usage; + unsigned char modifier; +} KEYMAP; + +#ifdef US_KEYBOARD +/* US keyboard (as HID standard) */ +#define KEYMAP_SIZE (152) +const KEYMAP keymap[KEYMAP_SIZE] = { + {0, 0}, /* NUL */ + {0, 0}, /* SOH */ + {0, 0}, /* STX */ + {0, 0}, /* ETX */ + {0, 0}, /* EOT */ + {0, 0}, /* ENQ */ + {0, 0}, /* ACK */ + {0, 0}, /* BEL */ + {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */ + {0x2b, 0}, /* TAB */ /* Keyboard Tab */ + {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */ + {0, 0}, /* VT */ + {0, 0}, /* FF */ + {0, 0}, /* CR */ + {0, 0}, /* SO */ + {0, 0}, /* SI */ + {0, 0}, /* DEL */ + {0, 0}, /* DC1 */ + {0, 0}, /* DC2 */ + {0, 0}, /* DC3 */ + {0, 0}, /* DC4 */ + {0, 0}, /* NAK */ + {0, 0}, /* SYN */ + {0, 0}, /* ETB */ + {0, 0}, /* CAN */ + {0, 0}, /* EM */ + {0, 0}, /* SUB */ + {0, 0}, /* ESC */ + {0, 0}, /* FS */ + {0, 0}, /* GS */ + {0, 0}, /* RS */ + {0, 0}, /* US */ + {0x2c, 0}, /* */ + {0x1e, KEY_SHIFT}, /* ! */ + {0x34, KEY_SHIFT}, /* " */ + {0x20, KEY_SHIFT}, /* # */ + {0x21, KEY_SHIFT}, /* $ */ + {0x22, KEY_SHIFT}, /* % */ + {0x24, KEY_SHIFT}, /* & */ + {0x34, 0}, /* ' */ + {0x26, KEY_SHIFT}, /* ( */ + {0x27, KEY_SHIFT}, /* ) */ + {0x25, KEY_SHIFT}, /* * */ + {0x2e, KEY_SHIFT}, /* + */ + {0x36, 0}, /* , */ + {0x2d, 0}, /* - */ + {0x37, 0}, /* . */ + {0x38, 0}, /* / */ + {0x27, 0}, /* 0 */ + {0x1e, 0}, /* 1 */ + {0x1f, 0}, /* 2 */ + {0x20, 0}, /* 3 */ + {0x21, 0}, /* 4 */ + {0x22, 0}, /* 5 */ + {0x23, 0}, /* 6 */ + {0x24, 0}, /* 7 */ + {0x25, 0}, /* 8 */ + {0x26, 0}, /* 9 */ + {0x33, KEY_SHIFT}, /* : */ + {0x33, 0}, /* ; */ + {0x36, KEY_SHIFT}, /* < */ + {0x2e, 0}, /* = */ + {0x37, KEY_SHIFT}, /* > */ + {0x38, KEY_SHIFT}, /* ? */ + {0x1f, KEY_SHIFT}, /* @ */ + {0x04, KEY_SHIFT}, /* A */ + {0x05, KEY_SHIFT}, /* B */ + {0x06, KEY_SHIFT}, /* C */ + {0x07, KEY_SHIFT}, /* D */ + {0x08, KEY_SHIFT}, /* E */ + {0x09, KEY_SHIFT}, /* F */ + {0x0a, KEY_SHIFT}, /* G */ + {0x0b, KEY_SHIFT}, /* H */ + {0x0c, KEY_SHIFT}, /* I */ + {0x0d, KEY_SHIFT}, /* J */ + {0x0e, KEY_SHIFT}, /* K */ + {0x0f, KEY_SHIFT}, /* L */ + {0x10, KEY_SHIFT}, /* M */ + {0x11, KEY_SHIFT}, /* N */ + {0x12, KEY_SHIFT}, /* O */ + {0x13, KEY_SHIFT}, /* P */ + {0x14, KEY_SHIFT}, /* Q */ + {0x15, KEY_SHIFT}, /* R */ + {0x16, KEY_SHIFT}, /* S */ + {0x17, KEY_SHIFT}, /* T */ + {0x18, KEY_SHIFT}, /* U */ + {0x19, KEY_SHIFT}, /* V */ + {0x1a, KEY_SHIFT}, /* W */ + {0x1b, KEY_SHIFT}, /* X */ + {0x1c, KEY_SHIFT}, /* Y */ + {0x1d, KEY_SHIFT}, /* Z */ + {0x2f, 0}, /* [ */ + {0x31, 0}, /* \ */ + {0x30, 0}, /* ] */ + {0x23, KEY_SHIFT}, /* ^ */ + {0x2d, KEY_SHIFT}, /* _ */ + {0x35, 0}, /* ` */ + {0x04, 0}, /* a */ + {0x05, 0}, /* b */ + {0x06, 0}, /* c */ + {0x07, 0}, /* d */ + {0x08, 0}, /* e */ + {0x09, 0}, /* f */ + {0x0a, 0}, /* g */ + {0x0b, 0}, /* h */ + {0x0c, 0}, /* i */ + {0x0d, 0}, /* j */ + {0x0e, 0}, /* k */ + {0x0f, 0}, /* l */ + {0x10, 0}, /* m */ + {0x11, 0}, /* n */ + {0x12, 0}, /* o */ + {0x13, 0}, /* p */ + {0x14, 0}, /* q */ + {0x15, 0}, /* r */ + {0x16, 0}, /* s */ + {0x17, 0}, /* t */ + {0x18, 0}, /* u */ + {0x19, 0}, /* v */ + {0x1a, 0}, /* w */ + {0x1b, 0}, /* x */ + {0x1c, 0}, /* y */ + {0x1d, 0}, /* z */ + {0x2f, KEY_SHIFT}, /* { */ + {0x31, KEY_SHIFT}, /* | */ + {0x30, KEY_SHIFT}, /* } */ + {0x35, KEY_SHIFT}, /* ~ */ + {0,0}, /* DEL */ + + {0x3a, 0}, /* F1 */ + {0x3b, 0}, /* F2 */ + {0x3c, 0}, /* F3 */ + {0x3d, 0}, /* F4 */ + {0x3e, 0}, /* F5 */ + {0x3f, 0}, /* F6 */ + {0x40, 0}, /* F7 */ + {0x41, 0}, /* F8 */ + {0x42, 0}, /* F9 */ + {0x43, 0}, /* F10 */ + {0x44, 0}, /* F11 */ + {0x45, 0}, /* F12 */ + + {0x46, 0}, /* PRINT_SCREEN */ + {0x47, 0}, /* SCROLL_LOCK */ + {0x39, 0}, /* CAPS_LOCK */ + {0x53, 0}, /* NUM_LOCK */ + {0x49, 0}, /* INSERT */ + {0x4a, 0}, /* HOME */ + {0x4b, 0}, /* PAGE_UP */ + {0x4e, 0}, /* PAGE_DOWN */ + + {0x4f, 0}, /* RIGHT_ARROW */ + {0x50, 0}, /* LEFT_ARROW */ + {0x51, 0}, /* DOWN_ARROW */ + {0x52, 0}, /* UP_ARROW */ +}; + +#else +/* UK keyboard */ +#define KEYMAP_SIZE (152) +const KEYMAP keymap[KEYMAP_SIZE] = { + {0, 0}, /* NUL */ + {0, 0}, /* SOH */ + {0, 0}, /* STX */ + {0, 0}, /* ETX */ + {0, 0}, /* EOT */ + {0, 0}, /* ENQ */ + {0, 0}, /* ACK */ + {0, 0}, /* BEL */ + {0x2a, 0}, /* BS */ /* Keyboard Delete (Backspace) */ + {0x2b, 0}, /* TAB */ /* Keyboard Tab */ + {0x28, 0}, /* LF */ /* Keyboard Return (Enter) */ + {0, 0}, /* VT */ + {0, 0}, /* FF */ + {0, 0}, /* CR */ + {0, 0}, /* SO */ + {0, 0}, /* SI */ + {0, 0}, /* DEL */ + {0, 0}, /* DC1 */ + {0, 0}, /* DC2 */ + {0, 0}, /* DC3 */ + {0, 0}, /* DC4 */ + {0, 0}, /* NAK */ + {0, 0}, /* SYN */ + {0, 0}, /* ETB */ + {0, 0}, /* CAN */ + {0, 0}, /* EM */ + {0, 0}, /* SUB */ + {0, 0}, /* ESC */ + {0, 0}, /* FS */ + {0, 0}, /* GS */ + {0, 0}, /* RS */ + {0, 0}, /* US */ + {0x2c, 0}, /* */ + {0x1e, KEY_SHIFT}, /* ! */ + {0x1f, KEY_SHIFT}, /* " */ + {0x32, 0}, /* # */ + {0x21, KEY_SHIFT}, /* $ */ + {0x22, KEY_SHIFT}, /* % */ + {0x24, KEY_SHIFT}, /* & */ + {0x34, 0}, /* ' */ + {0x26, KEY_SHIFT}, /* ( */ + {0x27, KEY_SHIFT}, /* ) */ + {0x25, KEY_SHIFT}, /* * */ + {0x2e, KEY_SHIFT}, /* + */ + {0x36, 0}, /* , */ + {0x2d, 0}, /* - */ + {0x37, 0}, /* . */ + {0x38, 0}, /* / */ + {0x27, 0}, /* 0 */ + {0x1e, 0}, /* 1 */ + {0x1f, 0}, /* 2 */ + {0x20, 0}, /* 3 */ + {0x21, 0}, /* 4 */ + {0x22, 0}, /* 5 */ + {0x23, 0}, /* 6 */ + {0x24, 0}, /* 7 */ + {0x25, 0}, /* 8 */ + {0x26, 0}, /* 9 */ + {0x33, KEY_SHIFT}, /* : */ + {0x33, 0}, /* ; */ + {0x36, KEY_SHIFT}, /* < */ + {0x2e, 0}, /* = */ + {0x37, KEY_SHIFT}, /* > */ + {0x38, KEY_SHIFT}, /* ? */ + {0x34, KEY_SHIFT}, /* @ */ + {0x04, KEY_SHIFT}, /* A */ + {0x05, KEY_SHIFT}, /* B */ + {0x06, KEY_SHIFT}, /* C */ + {0x07, KEY_SHIFT}, /* D */ + {0x08, KEY_SHIFT}, /* E */ + {0x09, KEY_SHIFT}, /* F */ + {0x0a, KEY_SHIFT}, /* G */ + {0x0b, KEY_SHIFT}, /* H */ + {0x0c, KEY_SHIFT}, /* I */ + {0x0d, KEY_SHIFT}, /* J */ + {0x0e, KEY_SHIFT}, /* K */ + {0x0f, KEY_SHIFT}, /* L */ + {0x10, KEY_SHIFT}, /* M */ + {0x11, KEY_SHIFT}, /* N */ + {0x12, KEY_SHIFT}, /* O */ + {0x13, KEY_SHIFT}, /* P */ + {0x14, KEY_SHIFT}, /* Q */ + {0x15, KEY_SHIFT}, /* R */ + {0x16, KEY_SHIFT}, /* S */ + {0x17, KEY_SHIFT}, /* T */ + {0x18, KEY_SHIFT}, /* U */ + {0x19, KEY_SHIFT}, /* V */ + {0x1a, KEY_SHIFT}, /* W */ + {0x1b, KEY_SHIFT}, /* X */ + {0x1c, KEY_SHIFT}, /* Y */ + {0x1d, KEY_SHIFT}, /* Z */ + {0x2f, 0}, /* [ */ + {0x64, 0}, /* \ */ + {0x30, 0}, /* ] */ + {0x23, KEY_SHIFT}, /* ^ */ + {0x2d, KEY_SHIFT}, /* _ */ + {0x35, 0}, /* ` */ + {0x04, 0}, /* a */ + {0x05, 0}, /* b */ + {0x06, 0}, /* c */ + {0x07, 0}, /* d */ + {0x08, 0}, /* e */ + {0x09, 0}, /* f */ + {0x0a, 0}, /* g */ + {0x0b, 0}, /* h */ + {0x0c, 0}, /* i */ + {0x0d, 0}, /* j */ + {0x0e, 0}, /* k */ + {0x0f, 0}, /* l */ + {0x10, 0}, /* m */ + {0x11, 0}, /* n */ + {0x12, 0}, /* o */ + {0x13, 0}, /* p */ + {0x14, 0}, /* q */ + {0x15, 0}, /* r */ + {0x16, 0}, /* s */ + {0x17, 0}, /* t */ + {0x18, 0}, /* u */ + {0x19, 0}, /* v */ + {0x1a, 0}, /* w */ + {0x1b, 0}, /* x */ + {0x1c, 0}, /* y */ + {0x1d, 0}, /* z */ + {0x2f, KEY_SHIFT}, /* { */ + {0x64, KEY_SHIFT}, /* | */ + {0x30, KEY_SHIFT}, /* } */ + {0x32, KEY_SHIFT}, /* ~ */ + {0,0}, /* DEL */ + + {0x3a, 0}, /* F1 */ + {0x3b, 0}, /* F2 */ + {0x3c, 0}, /* F3 */ + {0x3d, 0}, /* F4 */ + {0x3e, 0}, /* F5 */ + {0x3f, 0}, /* F6 */ + {0x40, 0}, /* F7 */ + {0x41, 0}, /* F8 */ + {0x42, 0}, /* F9 */ + {0x43, 0}, /* F10 */ + {0x44, 0}, /* F11 */ + {0x45, 0}, /* F12 */ + + {0x46, 0}, /* PRINT_SCREEN */ + {0x47, 0}, /* SCROLL_LOCK */ + {0x39, 0}, /* CAPS_LOCK */ + {0x53, 0}, /* NUM_LOCK */ + {0x49, 0}, /* INSERT */ + {0x4a, 0}, /* HOME */ + {0x4b, 0}, /* PAGE_UP */ + {0x4e, 0}, /* PAGE_DOWN */ + + {0x4f, 0}, /* RIGHT_ARROW */ + {0x50, 0}, /* LEFT_ARROW */ + {0x51, 0}, /* DOWN_ARROW */ + {0x52, 0}, /* UP_ARROW */ +}; +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/HIDTypes.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/HIDTypes.h new file mode 100644 index 0000000..7bc0988 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/HIDTypes.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2010-2011 mbed.org, MIT License +* +* Permission is hereby granted, free of charge, to any person obtaining a copy of this software +* and associated documentation files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all copies or +* substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef USBCLASS_HID_TYPES +#define USBCLASS_HID_TYPES + +#include + +/* */ +#define HID_VERSION_1_11 (0x0111) + +/* HID Class */ +#define BLE_HID_CLASS (3) +#define BLE_HID_SUBCLASS_NONE (0) +#define BLE_HID_PROTOCOL_NONE (0) + +/* Descriptors */ +#define HID_DESCRIPTOR (33) +#define HID_DESCRIPTOR_LENGTH (0x09) +#define REPORT_DESCRIPTOR (34) + +/* Class requests */ +#define GET_REPORT (0x1) +#define GET_IDLE (0x2) +#define SET_REPORT (0x9) +#define SET_IDLE (0xa) + +/* HID Class Report Descriptor */ +/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */ +/* of data as per HID Class standard */ + +/* Main items */ +#ifdef ARDUINO_ARCH_ESP32 +#define HIDINPUT(size) (0x80 | size) +#define HIDOUTPUT(size) (0x90 | size) +#else +#define INPUT(size) (0x80 | size) +#define OUTPUT(size) (0x90 | size) +#endif +#define FEATURE(size) (0xb0 | size) +#define COLLECTION(size) (0xa0 | size) +#define END_COLLECTION(size) (0xc0 | size) + +/* Global items */ +#define USAGE_PAGE(size) (0x04 | size) +#define LOGICAL_MINIMUM(size) (0x14 | size) +#define LOGICAL_MAXIMUM(size) (0x24 | size) +#define PHYSICAL_MINIMUM(size) (0x34 | size) +#define PHYSICAL_MAXIMUM(size) (0x44 | size) +#define UNIT_EXPONENT(size) (0x54 | size) +#define UNIT(size) (0x64 | size) +#define REPORT_SIZE(size) (0x74 | size) //bits +#define REPORT_ID(size) (0x84 | size) +#define REPORT_COUNT(size) (0x94 | size) //bytes +#define PUSH(size) (0xa4 | size) +#define POP(size) (0xb4 | size) + +/* Local items */ +#define USAGE(size) (0x08 | size) +#define USAGE_MINIMUM(size) (0x18 | size) +#define USAGE_MAXIMUM(size) (0x28 | size) +#define DESIGNATOR_INDEX(size) (0x38 | size) +#define DESIGNATOR_MINIMUM(size) (0x48 | size) +#define DESIGNATOR_MAXIMUM(size) (0x58 | size) +#define STRING_INDEX(size) (0x78 | size) +#define STRING_MINIMUM(size) (0x88 | size) +#define STRING_MAXIMUM(size) (0x98 | size) +#define DELIMITER(size) (0xa8 | size) + +/* HID Report */ +/* Where report IDs are used the first byte of 'data' will be the */ +/* report ID and 'length' will include this report ID byte. */ + +#define MAX_HID_REPORT_SIZE (64) + +typedef struct { + uint32_t length; + uint8_t data[MAX_HID_REPORT_SIZE]; +} HID_REPORT; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/RTOS.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/RTOS.h new file mode 100644 index 0000000..65362a9 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BLE/src/RTOS.h @@ -0,0 +1,81 @@ +/* + * FreeRTOS.h + * + * Created on: Feb 24, 2017 + * Author: kolban + */ + +#ifdef __cplusplus +#ifndef MAIN_FREERTOS_H_ +#define MAIN_FREERTOS_H_ +#include "Arduino.h" +#include +#include + +#include // Include the base FreeRTOS definitions. +#include // Include the task definitions. +#include // Include the semaphore definitions. +#include // Include the ringbuffer definitions. + + +/** + * @brief Interface to %FreeRTOS functions. + */ +class FreeRTOS { +public: + static void sleep(uint32_t ms); + static void startTask(void task(void*), String taskName, void* param = nullptr, uint32_t stackSize = 2048); + static void deleteTask(TaskHandle_t pTask = nullptr); + + static uint32_t getTimeSinceStart(); + + class Semaphore { + public: + Semaphore(String owner = ""); + ~Semaphore(); + void give(); + void give(uint32_t value); + void giveFromISR(); + void setName(String name); + bool take(String owner = ""); + bool take(uint32_t timeoutMs, String owner = ""); + String toString(); + uint32_t wait(String owner = ""); + bool timedWait(String owner = "", uint32_t timeoutMs = portMAX_DELAY); + uint32_t value(){ return m_value; }; + + private: + SemaphoreHandle_t m_semaphore; + pthread_mutex_t m_pthread_mutex; + String m_name; + String m_owner; + uint32_t m_value; + bool m_usePthreads; + + }; +}; + + +/** + * @brief Ringbuffer. + */ +class Ringbuffer { +public: +#ifdef ESP_IDF_VERSION_MAJOR + Ringbuffer(size_t length, RingbufferType_t type = RINGBUF_TYPE_NOSPLIT); +#else + Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT); +#endif + ~Ringbuffer(); + + void* receive(size_t* size, TickType_t wait = portMAX_DELAY); + void returnItem(void* item); + bool send(void* data, size_t length, TickType_t wait = portMAX_DELAY); +private: + RingbufHandle_t m_handle; +}; + +#endif /* MAIN_FREERTOS_H_ */ +#else +#include "freertos/FreeRTOS.h" +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/README.md new file mode 100644 index 0000000..4989b3a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/README.md @@ -0,0 +1,78 @@ +## Bluetooth Serial Library + +A simple Serial compatible library using ESP32 classical Bluetooth Serial Port Profile (SPP) + +Note: Since version 3.0.0 this library does not support legacy pairing (using fixed PIN consisting of 4 digits). + +### How to use it? + +There are 3 basic use cases: phone, other ESP32 or any MCU with a Bluetooth serial module + +#### Phone + +- Download one of the Bluetooth terminal apps to your smartphone + + - For [Android](https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal) + - For [iOS](https://itunes.apple.com/us/app/hm10-bluetooth-serial-lite/id1030454675) + +- Flash an example sketch to your ESP32 + +- Scan and pair the device to your smartphone + +- Open the Bluetooth terminal app and connect + +- Enjoy + +#### ESP32 + +You can flash one of the ESP32 with the example [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) (the Master) and another ESP32 with [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino) (the Slave). +Those examples are preset to work out-of-the-box but they should be scalable to connect multiple Slaves to the Master. + +#### 3rd party Serial Bluetooth module + +Using a 3rd party Serial Bluetooth module will require to study the documentation of the particular module in order to make it work, however, one side can utilize the mentioned [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) (the Master) or [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino) (the Slave). + +### Pairing options + +There are two easy options and one difficult. + +The easy options can be used as usual. These offer pairing with and without Secure Simple Pairing (SSP). + +The difficult option offers legacy pairing (using fixed PIN) however this must be compiled with Arduino as an IDF component with disabled sdkconfig option `CONFIG_BT_SSP_ENABLED`. + +#### Without SSP + +This method will authenticate automatically any attempt to pair and should not be used if security is a concern! This option is used for the examples [`SerialToSerialBTM`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino) and [`SerialToSerialBT`](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino). + +### With SSP + +The usage of SSP provides a secure connection. This option is demonstrated in the example `SerialToSerialBT_SSP``](https://github.com/espressif/arduino-esp32/blob/master/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino) + +The Secure Simple Pairing is enabled by calling method `enableSSP` which has two variants - one is backward compatible without parameter `enableSSP()` and second with parameters `enableSSP(bool inputCapability, bool outputCapability)`. Similarly, the SSP can be disabled by calling `disableSSP()`. + +Both options must be called before `begin()` or if it is called after `begin()` the driver needs to be restarted (call `end()` followed by `begin()`) in order to take in effect enabling or disabling the SSP. + +#### The parameters define the method of authentication: + +**inputCapability** - Defines if ESP32 device has input method (Serial terminal, keyboard or similar) + +**outputCapability** - Defines if ESP32 device has output method (Serial terminal, display or similar) + +* **inputCapability=true and outputCapability=true** + * Both devices display randomly generated code and if they match the user will authenticate pairing on both devices. + * This must be implemented by registering a callback via `onConfirmRequest()` and in this callback the user will input the response and call `confirmReply(true)` if the authenticated, otherwise call `confirmReply(false)` to reject the pairing. +* **inputCapability=false and outputCapability=false** + * Only the other device authenticates pairing without any pin. +* **inputCapability=false and outputCapability=true** + * Only the other device authenticates pairing without any pin. +* **inputCapability=true and outputCapability=false** + * The user will be required to input the passkey to the ESP32 device to authenticate. + * This must be implemented by registering a callback via `onKeyRequest`()` and in this callback the entered passkey will be responded via `respondPasskey(passkey)` + +### Legacy Pairing (IDF component) + +To use Legacy pairing you will have to use [Arduino as an IDF component](https://espressif-docs.readthedocs-hosted.com/projects/arduino-esp32/en/latest/esp-idf_component.html) and disable option `CONFIG_BT_SSP_ENABLED`. +Please refer to the documentation on how to setup Arduino as an IDF component and when you are done, run `idf.py menuconfig` navigate to `Component Config -> Bluetooth -> Bluedroid -> [ ] Secure Simple Pairing` and disable it. +While in the menuconfig you will also need to change the partition scheme `Partition Table -> Partition Table -> (X) Single Factory app (large), no OTA`. +After these changes save & quit menuconfig and you are ready to go: `idf.py monitor flash`. +Please note that to use the PIN in smartphones and computers you need to use characters `SerialBT.setPin("1234", 4);` not a number `SerialBT.setPin(1234, 4);` . Numbers CAN be used if the other side uses them too, but phones and computers use characters. \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino new file mode 100644 index 0000000..4269598 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/DiscoverConnect/DiscoverConnect.ino @@ -0,0 +1,113 @@ +/** + * Bluetooth Classic Example + * Scan for devices - asyncronously, print device as soon as found + * query devices for SPP - SDP profile + * connect to first device offering a SPP connection + * + * Example python server: + * source: https://gist.github.com/ukBaz/217875c83c2535d22a16ba38fc8f2a91 + * + * Tested with Raspberry Pi onboard Wifi/BT, USB BT 4.0 dongles, USB BT 1.1 dongles, + * 202202: does NOT work with USB BT 2.0 dongles when esp32 aduino lib is compiled with SSP support! + * see https://github.com/espressif/esp-idf/issues/8394 + * + * use ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side requests 'RequireAuthentication': dbus.Boolean(True), + * use ESP_SPP_SEC_NONE or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side has Authentication: False + */ + +#include +#include + +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip. +#endif + +BluetoothSerial SerialBT; + +#define BT_DISCOVER_TIME 10000 +esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation +esp_spp_role_t role = ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER + +// std::map btDeviceList; + +void setup() { + Serial.begin(115200); + if(! SerialBT.begin("ESP32test", true) ) { + Serial.println("========== serialBT failed!"); + abort(); + } + // SerialBT.setPin("1234"); // doesn't seem to change anything + // SerialBT.enableSSP(); // doesn't seem to change anything + + + Serial.println("Starting discoverAsync..."); + BTScanResults* btDeviceList = SerialBT.getScanResults(); // maybe accessing from different threads! + if (SerialBT.discoverAsync([](BTAdvertisedDevice* pDevice) { + // BTAdvertisedDeviceSet*set = reinterpret_cast(pDevice); + // btDeviceList[pDevice->getAddress()] = * set; + Serial.printf(">>>>>>>>>>>Found a new device asynchronously: %s\n", pDevice->toString().c_str()); + } ) + ) { + delay(BT_DISCOVER_TIME); + Serial.print("Stopping discoverAsync... "); + SerialBT.discoverAsyncStop(); + Serial.println("discoverAsync stopped"); + delay(5000); + if(btDeviceList->getCount() > 0) { + BTAddress addr; + int channel=0; + Serial.println("Found devices:"); + for (int i=0; i < btDeviceList->getCount(); i++) { + BTAdvertisedDevice *device=btDeviceList->getDevice(i); + Serial.printf(" ----- %s %s %d\n", device->getAddress().toString().c_str(), device->getName().c_str(), device->getRSSI()); + std::map channels=SerialBT.getChannels(device->getAddress()); + Serial.printf("scanned for services, found %d\n", channels.size()); + for(auto const &entry : channels) { + Serial.printf(" channel %d (%s)\n", entry.first, entry.second.c_str()); + } + if(channels.size() > 0) { + addr = device->getAddress(); + channel=channels.begin()->first; + } + } + if(addr) { + Serial.printf("connecting to %s - %d\n", addr.toString().c_str(), channel); + SerialBT.connect(addr, channel, sec_mask, role); + } + } else { + Serial.println("Didn't find any devices"); + } + } else { + Serial.println("Error on discoverAsync f.e. not workin after a \"connect\""); + } +} + + +String sendData="Hi from esp32!\n"; + +void loop() { + if(! SerialBT.isClosed() && SerialBT.connected()) { + if( SerialBT.write((const uint8_t*) sendData.c_str(),sendData.length()) != sendData.length()) { + Serial.println("tx: error"); + } else { + Serial.printf("tx: %s",sendData.c_str()); + } + if(SerialBT.available()) { + Serial.print("rx: "); + while(SerialBT.available()) { + int c=SerialBT.read(); + if(c >= 0) { + Serial.print((char) c); + } + } + Serial.println(); + } + } else { + Serial.println("not connected"); + } + delay(1000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino new file mode 100644 index 0000000..2930067 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/GetLocalMAC/GetLocalMAC.ino @@ -0,0 +1,46 @@ +// This example demonstrates usage of BluetoothSerial method to retrieve MAC address of local BT device in various formats. +// By Tomas Pilny - 2023 + +#include "BluetoothSerial.h" + +String device_name = "ESP32-example"; + +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip. +#endif + +BluetoothSerial SerialBT; + +void setup() { + Serial.begin(115200); + SerialBT.begin(device_name); //Bluetooth device name + + uint8_t mac_arr[6]; // Byte array to hold the MAC address from getBtAddress() + BTAddress mac_obj; // Object holding instance of BTAddress with the MAC (for more details see libraries/BluetoothSerial/src/BTAddress.h) + String mac_str; // String holding the text version of MAC in format AA:BB:CC:DD:EE:FF + + SerialBT.getBtAddress(mac_arr); // Fill in the array + mac_obj = SerialBT.getBtAddressObject(); // Instantiate the object + mac_str = SerialBT.getBtAddressString(); // Copy the string + + Serial.print("This device is instantiated with name "); Serial.println(device_name); + + Serial.print("The mac address using byte array: "); + for(int i = 0; i < ESP_BD_ADDR_LEN-1; i++){ + Serial.print(mac_arr[i], HEX); Serial.print(":"); + } + Serial.println(mac_arr[ESP_BD_ADDR_LEN-1], HEX); + + Serial.print("The mac address using BTAddress object using default method `toString()`: "); Serial.println(mac_obj.toString().c_str()); + Serial.print("The mac address using BTAddress object using method `toString(true)`\n\twhich prints the MAC with capital letters: "); Serial.println(mac_obj.toString(true).c_str()); // This actually what is used inside the getBtAddressString() + + Serial.print("The mac address using string: "); Serial.println(mac_str.c_str()); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino new file mode 100644 index 0000000..c5ac06b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino @@ -0,0 +1,39 @@ +// This example code is in the Public Domain (or CC0 licensed, at your option.) +// By Evandro Copercini - 2018 +// +// This example creates a bridge between Serial and Classical Bluetooth (SPP) +// and also demonstrate that SerialBT have the same functionalities of a normal Serial +// Note: Pairing is authenticated automatically by this device + +#include "BluetoothSerial.h" + +String device_name = "ESP32-BT-Slave"; + +// Check if Bluetooth is available +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +// Check Serial Port Profile +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip. +#endif + +BluetoothSerial SerialBT; + +void setup() { + Serial.begin(115200); + SerialBT.begin(device_name); //Bluetooth device name + //SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin + Serial.printf("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n", device_name.c_str()); +} + +void loop() { + if (Serial.available()) { + SerialBT.write(Serial.read()); + } + if (SerialBT.available()) { + Serial.write(SerialBT.read()); + } + delay(20); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino new file mode 100644 index 0000000..a4917bf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBTM/SerialToSerialBTM.ino @@ -0,0 +1,96 @@ +// This example code is in the Public Domain (or CC0 licensed, at your option.) +// By Victor Tchistiak - 2019 +// +// This example demonstrates master mode Bluetooth connection to a slave BT device +// defined either by String "slaveName" by default "ESP32-BT-Slave" or by MAC address +// +// This example creates a bridge between Serial and Classical Bluetooth (SPP) +// This is an extension of the SerialToSerialBT example by Evandro Copercini - 2018 +// +// DO NOT try to connect to phone or laptop - they are master +// devices, same as the ESP using this code - you will be able +// to pair, but the serial communication will NOT work! +// +// You can try to flash a second ESP32 with the example SerialToSerialBT - it should +// automatically pair with ESP32 running this code +// Note: Pairing is authenticated automatically by this device + +#include "BluetoothSerial.h" + +#define USE_NAME // Comment this to use MAC address instead of a slaveName + +// Check if Bluetooth is available +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +// Check Serial Port Profile +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip. +#endif +BluetoothSerial SerialBT; + +#ifdef USE_NAME + String slaveName = "ESP32-BT-Slave"; // Change this to reflect the real name of your slave BT device +#else + String MACadd = "AA:BB:CC:11:22:33"; // This only for printing + uint8_t address[6] = {0xAA, 0xBB, 0xCC, 0x11, 0x22, 0x33}; // Change this to reflect real MAC address of your slave BT device +#endif + +String myName = "ESP32-BT-Master"; + +void setup() { + bool connected; + Serial.begin(115200); + + SerialBT.begin(myName, true); + //SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin + Serial.printf("The device \"%s\" started in master mode, make sure slave BT device is on!\n", myName.c_str()); + + #ifndef USE_NAME + SerialBT.setPin(pin); + Serial.println("Using PIN"); + #endif + + // connect(address) is fast (up to 10 secs max), connect(slaveName) is slow (up to 30 secs max) as it needs + // to resolve slaveName to address first, but it allows to connect to different devices with the same name. + // Set CoreDebugLevel to Info to view devices Bluetooth address and device names + #ifdef USE_NAME + connected = SerialBT.connect(slaveName); + Serial.printf("Connecting to slave BT device named \"%s\"\n", slaveName.c_str()); + #else + connected = SerialBT.connect(address); + Serial.print("Connecting to slave BT device with MAC "); Serial.println(MACadd); + #endif + + if(connected) { + Serial.println("Connected Successfully!"); + } else { + while(!SerialBT.connected(10000)) { + Serial.println("Failed to connect. Make sure remote device is available and in range, then restart app."); + } + } + // Disconnect() may take up to 10 secs max + if (SerialBT.disconnect()) { + Serial.println("Disconnected Successfully!"); + } + // This would reconnect to the slaveName(will use address, if resolved) or address used with connect(slaveName/address). + SerialBT.connect(); + if(connected) { + Serial.println("Reconnected Successfully!"); + } else { + while(!SerialBT.connected(10000)) { + Serial.println("Failed to reconnect. Make sure remote device is available and in range, then restart app."); + } + } +} + +void loop() { + if (Serial.available()) { + SerialBT.write(Serial.read()); + } + if (SerialBT.available()) { + Serial.write(SerialBT.read()); + } + delay(20); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino new file mode 100644 index 0000000..2343b5c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_Legacy/SerialToSerialBT_Legacy.ino @@ -0,0 +1,65 @@ +// This example code is in the Public Domain (or CC0 licensed, at your option.) +// +// This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication) +// and also demonstrate that SerialBT have the same functionalities of a normal Serial +// Legacy pairing TODO +// Must be run as idf component ... todo + +#include "BluetoothSerial.h" + +// Check if Bluetooth is available +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +// Check Serial Port Profile +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip. +#endif + +// Check Simple Secure Pairing +#if defined(CONFIG_BT_SSP_ENABLED) + #warning Legacy Pairing is disabled (CONFIG_BT_SSP_ENABLED is enabled. Disable it in menuconfig). + void setup(){} + void loop(){} +#else +const char * deviceName = "ESP32_Legacy_example"; + +BluetoothSerial SerialBT; +bool confirmRequestDone = false; + +void BTAuthCompleteCallback(boolean success){ + if (success){ + confirmRequestDone = true; + Serial.println("Pairing success!!"); + } else { + Serial.println("Pairing failed, rejected by user!!"); + } +} + +void serial_response(){ + if (Serial.available()){ + SerialBT.write(Serial.read()); + } + if (SerialBT.available()){ + Serial.write(SerialBT.read()); + } + delay(20); +} + +void setup(){ + Serial.begin(115200); + SerialBT.onAuthComplete(BTAuthCompleteCallback); + SerialBT.begin(deviceName); // Initiate Bluetooth device with name in parameter + SerialBT.setPin("1234", 4); + Serial.printf("The device started with name \"%s\", now you can pair it with Bluetooth!\n", deviceName); +} + +void loop(){ + if (confirmRequestDone){ + serial_response(); + } else { + delay(1); // Feed the watchdog + } +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino new file mode 100644 index 0000000..a39dbf1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/SerialToSerialBT_SSP/SerialToSerialBT_SSP.ino @@ -0,0 +1,134 @@ +// This example code is in the Public Domain (or CC0 licensed, at your option.) +// By Richard Li - 2020 +// +// This example creates a bridge between Serial and Classical Bluetooth (SPP with authentication) +// and also demonstrate that SerialBT have the same functionalities of a normal Serial +// SSP - Simple Secure Pairing - The device (ESP32) will display random number and the user is responsible of comparing it to the number +// displayed on the other device (for example phone). +// If the numbers match the user authenticates the pairing on both devices - on phone simply press "Pair" and in terminal for the sketch send 'Y' or 'y' to confirm. +// Alternatively uncomment AUTO_PAIR to skip the terminal confirmation. + +#include "BluetoothSerial.h" + +//#define AUTO_PAIR // Uncomment to automatically authenticate ESP32 side + +// Check if Bluetooth is available +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +// Check Serial Port Profile +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Port Profile for Bluetooth is not available or not enabled. It is only available for the ESP32 chip. +#endif + +// Check Simple Secure Pairing +#if !defined(CONFIG_BT_SSP_ENABLED) + #error Simple Secure Pairing for Bluetooth is not available or not enabled. +#endif + +const char * deviceName = "ESP32_SSP_example"; + +// The following lines defines the method of pairing +// When both Input and Output are false only the other device authenticates pairing without any pin. +// When Output is true and Input is false only the other device authenticates pairing without any pin. +// When both Input and Output are true both devices display randomly generated code and if they match authenticate pairing on both devices +// - This must be implemented by registering callback via onConfirmRequest() and in this callback request user input and call confirmReply(true); if the authenticated +// otherwise call `confirmReply(false)` to reject the pairing. +// When Input is true and Output is false User will be required to input the passkey to the ESP32 device to authenticate. +// - This must be implemented by registering callback via onKeyRequest() and in this callback the entered passkey will be responded via respondPasskey(passkey); +const bool INPUT_CAPABILITY = false; // Defines if ESP32 device has input method (Serial terminal, keyboard or similar) +const bool OUTPUT_CAPABILITY = true; // Defines if ESP32 device has output method (Serial terminal, display or similar) + +BluetoothSerial SerialBT; +bool confirmRequestDone = false; + +void BTConfirmRequestCallback(uint32_t numVal){ + confirmRequestDone = false; +#ifndef AUTO_PAIR + Serial.printf("The PIN is: %06lu. If it matches number displayed on the other device write \'Y\' or \'y\':\n", numVal); // Note the formatting "%06lu" - PIN can start with zero(s) which would be ignored with simple "%lu" + while (!Serial.available()) { + delay(1); // Feed the watchdog + // Wait until data is available on the Serial port. + } + Serial.printf("Oh you sent %d Bytes, lets see...", Serial.available()); + int dat = Serial.read(); + if (dat == 'Y' || dat == 'y'){ + SerialBT.confirmReply(true); + } + else{ + SerialBT.confirmReply(false); + } +#else + SerialBT.confirmReply(true); +#endif +} + +void BTKeyRequestCallback(){ + Serial.println("BTKeyRequestCallback"); // debug + char buffer[7] = {0}; // 6 bytes for number, one for termination '0' + while (1) { + Serial.print("Enter the passkey displayed on the other device: "); + while (!Serial.available()) { + delay(1); // Feed the watchdog + // Wait until data is available on the Serial port. + } + size_t len = Serial.readBytesUntil('\n', buffer, sizeof(buffer) - 1); + buffer[len] = '\0'; // Null-terminate the string. + try { + uint32_t passkey = std::stoi(buffer); + Serial.printf("Entered PIN: %lu\n", passkey); + SerialBT.respondPasskey(passkey); + return; + } catch (...) { + Serial.print("Wrong PIN! Try again."); + } // try + } // while(1) +} + +void BTAuthCompleteCallback(boolean success){ + if (success){ + confirmRequestDone = true; + Serial.println("Pairing success!!"); + } else { + Serial.println("Pairing failed, rejected by user!!"); + } +} + +void serial_response(){ + if (Serial.available()){ + SerialBT.write(Serial.read()); + } + if (SerialBT.available()){ + Serial.write(SerialBT.read()); + } + delay(20); +} + +void setup(){ + Serial.begin(115200); + SerialBT.enableSSP(INPUT_CAPABILITY, OUTPUT_CAPABILITY); // Must be called before begin + SerialBT.onConfirmRequest(BTConfirmRequestCallback); + SerialBT.onKeyRequest(BTKeyRequestCallback); + SerialBT.onAuthComplete(BTAuthCompleteCallback); + SerialBT.begin(deviceName); // Initiate Bluetooth device with name in parameter + //SerialBT.deleteAllBondedDevices(); // Uncomment this to delete paired devices; Must be called after begin + Serial.printf("The device started with name \"%s\", now you can pair it with Bluetooth!\n", deviceName); + if(INPUT_CAPABILITY and OUTPUT_CAPABILITY){ + Serial.println("Both devices will display randomly generated code and if they match authenticate pairing on both devices"); + }else if(not INPUT_CAPABILITY and not OUTPUT_CAPABILITY){ + Serial.println("Authenticate pairing on the other device. No PIN is used"); + }else if(not INPUT_CAPABILITY and OUTPUT_CAPABILITY){ + Serial.println("Authenticate pairing on the other device. No PIN is used"); + }else if(INPUT_CAPABILITY and not OUTPUT_CAPABILITY){ + Serial.println("After pairing is initiated you will be required to enter the passkey to the ESP32 device to authenticate\n > The Passkey will displayed on the other device"); + } +} + +void loop(){ + if (confirmRequestDone){ + serial_response(); + } else { + delay(1); // Feed the watchdog + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino new file mode 100644 index 0000000..b4ee741 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_classic_device_discovery/bt_classic_device_discovery.ino @@ -0,0 +1,56 @@ +#include + +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) + #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip. +#endif + +BluetoothSerial SerialBT; + + +#define BT_DISCOVER_TIME 10000 + + +static bool btScanAsync = true; +static bool btScanSync = true; + + +void btAdvertisedDeviceFound(BTAdvertisedDevice* pDevice) { + Serial.printf("Found a device asynchronously: %s\n", pDevice->toString().c_str()); +} + +void setup() { + Serial.begin(115200); + SerialBT.begin("ESP32test"); //Bluetooth device name + Serial.println("The device started, now you can pair it with bluetooth!"); + + + if (btScanAsync) { + Serial.print("Starting asynchronous discovery... "); + if (SerialBT.discoverAsync(btAdvertisedDeviceFound)) { + Serial.println("Findings will be reported in \"btAdvertisedDeviceFound\""); + delay(10000); + Serial.print("Stopping discoverAsync... "); + SerialBT.discoverAsyncStop(); + Serial.println("stopped"); + } else { + Serial.println("Error on discoverAsync f.e. not working after a \"connect\""); + } + } + + if (btScanSync) { + Serial.println("Starting synchronous discovery... "); + BTScanResults *pResults = SerialBT.discover(BT_DISCOVER_TIME); + if (pResults) + pResults->dump(&Serial); + else + Serial.println("Error on BT Scan, no result!"); + } +} + +void loop() { + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino new file mode 100644 index 0000000..d6f6786 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/examples/bt_remove_paired_devices/bt_remove_paired_devices.ino @@ -0,0 +1,74 @@ +// This example code is in the Public Domain (or CC0 licensed, at your option.) +// Originally by Victor Tchistiak - 2019 +// Rewritten with new API by Tomas Pilny - 2023 +// +// This example demonstrates reading and removing paired devices stored on the ESP32 flash memory +// Sometimes you may find your ESP32 device could not connect to the remote device despite +// many successful connections earlier. This is most likely a result of client replacing your paired +// device info with new one from other device. The BT clients store connection info for paired devices, +// but it is limited to a few devices only. When new device pairs and number of stored devices is exceeded, +// one of the previously paired devices would be replaced with new one. +// The only remedy is to delete this saved bound device from your device flash memory +// and pair with the other device again. + +#include "BluetoothSerial.h" +//#include "esp_bt_device.h" + +#if !defined(CONFIG_BT_SPP_ENABLED) + #error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip. +#endif + +#define REMOVE_BONDED_DEVICES true // <- Set to `false` to view all bonded devices addresses, set to `true` to remove +#define PAIR_MAX_DEVICES 20 +BluetoothSerial SerialBT; + +char *bda2str(const uint8_t* bda, char *str, size_t size){ + if (bda == NULL || str == NULL || size < 18){ + return NULL; + } + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + return str; +} + +void setup(){ + char bda_str[18]; + uint8_t pairedDeviceBtAddr[PAIR_MAX_DEVICES][6]; + Serial.begin(115200); + + SerialBT.begin(); + Serial.printf("ESP32 bluetooth address: %s\n", SerialBT.getBtAddressString().c_str()); + // SerialBT.deleteAllBondedDevices(); // If you want just delete all, this is the way + // Get the numbers of bonded/paired devices in the BT module + int count = SerialBT.getNumberOfBondedDevices(); + if(!count){ + Serial.println("No bonded devices found."); + } else { + Serial.printf("Bonded device count: %d\n", count); + if(PAIR_MAX_DEVICES < count){ + count = PAIR_MAX_DEVICES; + Serial.printf("Reset %d bonded devices\n", count); + } + count = SerialBT.getBondedDevices(count, pairedDeviceBtAddr); + char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]; + if(count > 0){ + for(int i = 0; i < count; i++){ + SerialBT.requestRemoteName(pairedDeviceBtAddr[i]); + while(!SerialBT.readRemoteName(rmt_name)){ + delay(1); // Wait for response with the device name + } + Serial.printf("Found bonded device #%d BDA:%s; Name:\"%s\"\n", i, bda2str(pairedDeviceBtAddr[i], bda_str, 18), rmt_name); + SerialBT.invalidateRemoteName(); // Allows waiting for next reading + if(REMOVE_BONDED_DEVICES){ + if(SerialBT.deleteBondedDevice(pairedDeviceBtAddr[i])){ + Serial.printf("Removed bonded device # %d\n", i); + } else { + Serial.printf("Failed to remove bonded device # %d", i); + } // if(ESP_OK == tError) + } // if(REMOVE_BONDED_DEVICES) + } // for(int i = 0; i < count; i++) + } // if(ESP_OK == tError) + } // if(!count) +} + +void loop() {} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/keywords.txt new file mode 100644 index 0000000..563e35d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For BluetoothSerial +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +BluetoothSerial KEYWORD3 + +####################################### +# Datatypes (KEYWORD1) +####################################### + +BluetoothSerial KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +SerialBT KEYWORD2 +hasClient KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/library.properties new file mode 100644 index 0000000..8581da8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/library.properties @@ -0,0 +1,9 @@ +name=BluetoothSerial +version=2.0.0 +author=Evandro Copercini +maintainer=Evandro Copercini +sentence=Simple UART to Classical Bluetooth bridge for ESP32 +paragraph= +category=Communication +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAddress.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAddress.cpp new file mode 100644 index 0000000..2cde9ed --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAddress.cpp @@ -0,0 +1,112 @@ +/* + * BTAddress.cpp + * + * Created on: Jul 2, 2017 + * Author: kolban + * Ported on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) + +#include "BTAddress.h" +#include +#include +#include +#include +#include +#include +#ifdef ARDUINO_ARCH_ESP32 +#include "esp32-hal-log.h" +#endif + + +/** + * @brief Create an address from the native ESP32 representation. + * @param [in] address The native representation. + */ +BTAddress::BTAddress(esp_bd_addr_t address) { + memcpy(m_address, address, ESP_BD_ADDR_LEN); +} // BTAddress + +BTAddress::BTAddress() { + bzero(m_address, ESP_BD_ADDR_LEN); +} // BTAddress + +/** + * @brief Create an address from a hex string + * + * A hex string is of the format: + * ``` + * 00:00:00:00:00:00 + * ``` + * which is 17 characters in length. + * + * @param [in] stringAddress The hex representation of the address. + */ +BTAddress::BTAddress(String stringAddress) { + if (stringAddress.length() != 17) return; + + int data[6]; + sscanf(stringAddress.c_str(), "%x:%x:%x:%x:%x:%x", &data[0], &data[1], &data[2], &data[3], &data[4], &data[5]); + m_address[0] = (uint8_t) data[0]; + m_address[1] = (uint8_t) data[1]; + m_address[2] = (uint8_t) data[2]; + m_address[3] = (uint8_t) data[3]; + m_address[4] = (uint8_t) data[4]; + m_address[5] = (uint8_t) data[5]; +} // BTAddress + + +/** + * @brief Determine if this address equals another. + * @param [in] otherAddress The other address to compare against. + * @return True if the addresses are equal. + */ +bool BTAddress::equals(BTAddress otherAddress) { + return memcmp(otherAddress.getNative(), m_address, 6) == 0; +} // equals + +BTAddress::operator bool () const { + for(int i = 0; i < ESP_BD_ADDR_LEN; i++){ + if(this->m_address[i]) + return true; + } + return false; +} // operator () + +/** + * @brief Return the native representation of the address. + * @return The native representation of the address. + */ +esp_bd_addr_t *BTAddress::getNative() const { + return const_cast(&m_address); +} // getNative + + +/** + * @brief Convert a BT address to a string. + * @param [in] capital changes the letter size + * By default the parameter `capital` == false and the string representation of an address is in the format: + * ``` + * xx:xx:xx:xx:xx:xx + * ``` + * When the parameter `capital` == true the format uses capital letters: + * ``` + * XX:XX:XX:XX:XX:XX + * ``` + * @return The string representation of the address. + */ +String BTAddress::toString(bool capital) const { + auto size = 18; + char *res = (char*)malloc(size); + if(capital){ + snprintf(res, size, "%02X:%02X:%02X:%02X:%02X:%02X", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]); + }else{ + snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]); + } + String ret(res); + free(res); + return ret; +} // toString +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAddress.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAddress.h new file mode 100644 index 0000000..a173a29 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAddress.h @@ -0,0 +1,39 @@ +/* + * BTAddress.h + * + * Created on: Jul 2, 2017 + * Author: kolban + * Ported on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#ifndef COMPONENTS_CPP_UTILS_BTADDRESS_H_ +#define COMPONENTS_CPP_UTILS_BTADDRESS_H_ +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) +#include // ESP32 BT +#include + + +/** + * @brief A %BT device address. + * + * Every %BT device has a unique address which can be used to identify it and form connections. + */ +class BTAddress { +public: + BTAddress(); + BTAddress(esp_bd_addr_t address); + BTAddress(String stringAddress); + bool equals(BTAddress otherAddress); + operator bool () const; + + esp_bd_addr_t* getNative() const; + String toString(bool capital = false) const; + +private: + esp_bd_addr_t m_address; +}; + +#endif /* CONFIG_BT_ENABLED */ +#endif /* COMPONENTS_CPP_UTILS_BTADDRESS_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAdvertisedDevice.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAdvertisedDevice.h new file mode 100644 index 0000000..a0cb877 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAdvertisedDevice.h @@ -0,0 +1,65 @@ +/* + * BTAdvertisedDevice.h + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#ifndef __BTADVERTISEDDEVICE_H__ +#define __BTADVERTISEDDEVICE_H__ + +#include "BTAddress.h" +#include + +class BTAdvertisedDevice { +public: + virtual ~BTAdvertisedDevice() = default; + + virtual BTAddress getAddress(); + virtual uint32_t getCOD() const; + virtual std::string getName() const; + virtual int8_t getRSSI() const; + + + virtual bool haveCOD() const; + virtual bool haveName() const; + virtual bool haveRSSI() const; + + virtual std::string toString(); +}; + +class BTAdvertisedDeviceSet : public virtual BTAdvertisedDevice { +public: + BTAdvertisedDeviceSet(); + //~BTAdvertisedDeviceSet() = default; + + + BTAddress getAddress(); + uint32_t getCOD() const; + std::string getName() const; + int8_t getRSSI() const; + + + bool haveCOD() const; + bool haveName() const; + bool haveRSSI() const; + + std::string toString(); + + void setAddress(BTAddress address); + void setCOD(uint32_t cod); + void setName(std::string name); + void setRSSI(int8_t rssi); + + bool m_haveCOD; + bool m_haveName; + bool m_haveRSSI; + + + BTAddress m_address = BTAddress((uint8_t*)"\0\0\0\0\0\0"); + uint32_t m_cod; + std::string m_name; + int8_t m_rssi; +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp new file mode 100644 index 0000000..fecc5f7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTAdvertisedDeviceSet.cpp @@ -0,0 +1,78 @@ +/* + * BTAdvertisedDeviceSet.cpp + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) + +//#include + +#include "BTAdvertisedDevice.h" +//#include "BTScan.h" + + +BTAdvertisedDeviceSet::BTAdvertisedDeviceSet() { + m_cod = 0; + m_name = ""; + m_rssi = 0; + + m_haveCOD = false; + m_haveName = false; + m_haveRSSI = false; +} // BTAdvertisedDeviceSet + +BTAddress BTAdvertisedDeviceSet::getAddress() { return m_address; } +uint32_t BTAdvertisedDeviceSet::getCOD() const { return m_cod; } +std::string BTAdvertisedDeviceSet::getName() const { return m_name; } +int8_t BTAdvertisedDeviceSet::getRSSI() const { return m_rssi; } + + +bool BTAdvertisedDeviceSet::haveCOD() const { return m_haveCOD; } +bool BTAdvertisedDeviceSet::haveName() const { return m_haveName; } +bool BTAdvertisedDeviceSet::haveRSSI() const { return m_haveRSSI; } + +/** + * @brief Create a string representation of this device. + * @return A string representation of this device. + */ +std::string BTAdvertisedDeviceSet::toString() { + std::string res = "Name: " + getName() + ", Address: " + std::string(getAddress().toString().c_str(), getAddress().toString().length()); + if (haveCOD()) { + char val[7]; //6 hex digits + null + snprintf(val, sizeof(val), "%06lx", getCOD() & 0xFFFFFF); + res += ", cod: 0x"; + res += val; + } + if (haveRSSI()) { + char val[6]; + snprintf(val, sizeof(val), "%d", (int8_t)getRSSI()); + res += ", rssi: "; + res += val; + } + return res; +} // toString + + +void BTAdvertisedDeviceSet::setAddress(BTAddress address) { + m_address = address; +} + +void BTAdvertisedDeviceSet::setCOD(uint32_t cod) { + m_cod = cod; + m_haveCOD = true; +} + +void BTAdvertisedDeviceSet::setName(std::string name) { + m_name = name; + m_haveName = true; +} + +void BTAdvertisedDeviceSet::setRSSI(int8_t rssi) { + m_rssi = rssi; + m_haveRSSI = true; +} + +#endif /* CONFIG_BT_ENABLED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTScan.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTScan.h new file mode 100644 index 0000000..2fa1b65 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTScan.h @@ -0,0 +1,42 @@ +/* + * BTScan.h + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#ifndef __BTSCAN_H__ +#define __BTSCAN_H__ + +#include +#include +#include +#include "BTAddress.h" +#include "BTAdvertisedDevice.h" + +class BTAdvertisedDevice; +class BTAdvertisedDeviceSet; + + +class BTScanResults { +public: + virtual ~BTScanResults() = default; + + virtual void dump(Print *print = nullptr); + virtual int getCount(); + virtual BTAdvertisedDevice* getDevice(int i); +}; + +class BTScanResultsSet : public BTScanResults { +public: + void dump(Print *print = nullptr); + int getCount(); + BTAdvertisedDevice* getDevice(int i); + + bool add(BTAdvertisedDeviceSet advertisedDevice, bool unique = true); + void clear(); + + std::map m_vectorAdvertisedDevices; +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTScanResultsSet.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTScanResultsSet.cpp new file mode 100644 index 0000000..e7745e4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BTScanResultsSet.cpp @@ -0,0 +1,95 @@ +/* + * BTScanResultsSet.cpp + * + * Created on: Feb 5, 2021 + * Author: Thomas M. (ArcticSnowSky) + */ + +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) + + +#include + +#include "BTAdvertisedDevice.h" +#include "BTScan.h" +//#include "GeneralUtils.h" +#include "esp32-hal-log.h" + + +class BTAdvertisedDevice; + +/** + * @brief Dump the scan results to the log. + */ +void BTScanResultsSet::dump(Print *print) { + int cnt = getCount(); + if (print == nullptr) { + log_v(">> Dump scan results : %d", cnt); + for (int i=0; i < cnt; i++) { + BTAdvertisedDevice* dev = getDevice(i); + if (dev) + log_d("- %d: %s\n", i+1, dev->toString().c_str()); + else + log_d("- %d is null\n", i+1); + } + log_v("-- dump finished --"); + } else { + print->printf(">> Dump scan results: %d\n", cnt); + for (int i=0; i < cnt; i++) { + BTAdvertisedDevice* dev = getDevice(i); + if (dev) + print->printf("- %d: %s\n", i+1, dev->toString().c_str()); + else + print->printf("- %d is null\n", i+1); + } + print->println("-- Dump finished --"); + } +} // dump + + +/** + * @brief Return the count of devices found in the last scan. + * @return The number of devices found in the last scan. + */ +int BTScanResultsSet::getCount() { + return m_vectorAdvertisedDevices.size(); +} // getCount + + +/** + * @brief Return the specified device at the given index. + * The index should be between 0 and getCount()-1. + * @param [in] i The index of the device. + * @return The device at the specified index. + */ +BTAdvertisedDevice* BTScanResultsSet::getDevice(int i) { + if (i < 0) + return nullptr; + + int x = 0; + BTAdvertisedDeviceSet* pDev = &m_vectorAdvertisedDevices.begin()->second; + for (auto it = m_vectorAdvertisedDevices.begin(); it != m_vectorAdvertisedDevices.end(); it++) { + pDev = &it->second; + if (x==i) break; + x++; + } + return x==i ? pDev : nullptr; +} + +void BTScanResultsSet::clear() { + //for(auto _dev : m_vectorAdvertisedDevices) + // delete _dev.second; + m_vectorAdvertisedDevices.clear(); +} + +bool BTScanResultsSet::add(BTAdvertisedDeviceSet advertisedDevice, bool unique) { + std::string key = std::string(advertisedDevice.getAddress().toString().c_str(), advertisedDevice.getAddress().toString().length()); + if (!unique || m_vectorAdvertisedDevices.count(key) == 0) { + m_vectorAdvertisedDevices.insert(std::pair(key, advertisedDevice)); + return true; + } else + return false; +} + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BluetoothSerial.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BluetoothSerial.cpp new file mode 100644 index 0000000..419809d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/BluetoothSerial/src/BluetoothSerial.cpp @@ -0,0 +1,1394 @@ +// Copyright 2018 Evandro Luis Copercini +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + + +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) + +#ifdef ARDUINO_ARCH_ESP32 + #include "esp32-hal-log.h" +#endif + +#include "BluetoothSerial.h" +#include "BTAdvertisedDevice.h" + +#include "esp_bt.h" +#include "esp_bt_main.h" +#include "esp_gap_bt_api.h" +#include "esp_bt_device.h" +#include "esp_spp_api.h" +#include + +#include "esp32-hal-log.h" + +const char * _spp_server_name = "ESP32SPP"; + +#define RX_QUEUE_SIZE 512 +#define TX_QUEUE_SIZE 32 +#define SPP_TX_QUEUE_TIMEOUT 1000 +#define SPP_TX_DONE_TIMEOUT 1000 +#define SPP_CONGESTED_TIMEOUT 1000 + +static uint32_t _spp_client = 0; +static QueueHandle_t _spp_rx_queue = NULL; +static QueueHandle_t _spp_tx_queue = NULL; +static SemaphoreHandle_t _spp_tx_done = NULL; +static TaskHandle_t _spp_task_handle = NULL; +static EventGroupHandle_t _spp_event_group = NULL; +static EventGroupHandle_t _bt_event_group = NULL; +static boolean secondConnectionAttempt; +static esp_spp_cb_t * custom_spp_callback = NULL; +static BluetoothSerialDataCb custom_data_callback = NULL; +static esp_bd_addr_t current_bd_addr; +static ConfirmRequestCb confirm_request_callback = NULL; +static KeyRequestCb key_request_callback = NULL; +static AuthCompleteCb auth_complete_callback = NULL; +static bool _rmt_name_valid = false; +static uint8_t _rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1] = {0}; + +#define INQ_LEN 0x10 +#define INQ_NUM_RSPS 20 +#define READY_TIMEOUT (10 * 1000) +#define SCAN_TIMEOUT (INQ_LEN * 2 * 1000) +static esp_bd_addr_t _peer_bd_addr; +static char _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]; +static bool _isRemoteAddressSet; +static bool _isMaster; +#ifdef CONFIG_BT_SSP_ENABLED + static bool _enableSSP; + static bool _IO_CAP_INPUT; + static bool _IO_CAP_OUTPUT; +#endif +esp_bt_pin_code_t _pin_code = {0}; +uint8_t _pin_code_len = 0; // Number of valid Bytes in the esp_bt_pin_code_t array +static esp_spp_sec_t _sec_mask; +static esp_spp_role_t _role; +// start connect on ESP_SPP_DISCOVERY_COMP_EVT or save entry for getChannels +static bool _doConnect; +static std::map sdpRecords; + +static BTScanResultsSet scanResults; +static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr; + +// _spp_event_group +#define SPP_RUNNING 0x01 +#define SPP_CONNECTED 0x02 +#define SPP_CONGESTED 0x04 +// true until OPEN successful, changes to false on CLOSE +#define SPP_DISCONNECTED 0x08 +// true until connect(), changes to true on CLOSE +#define SPP_CLOSED 0x10 + +// _bt_event_group +#define BT_DISCOVERY_RUNNING 0x01 +#define BT_DISCOVERY_COMPLETED 0x02 + +#define BT_SDP_RUNNING 0x04 +#define BT_SDP_COMPLETED 0x08 + +typedef struct { + size_t len; + uint8_t data[]; +} spp_packet_t; + +#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) +static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) +{ + if (bda == NULL || str == NULL || size < 18) { + return NULL; + } + + uint8_t *p = bda; + snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x", + p[0], p[1], p[2], p[3], p[4], p[5]); + return str; +} +#endif + +static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len) +{ + if (!eir || !bdname || !bdname_len) { + return false; + } + + uint8_t *rmt_bdname, rmt_bdname_len; + *bdname = *bdname_len = rmt_bdname_len = 0; + + rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len); + if (!rmt_bdname) { + rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len); + } + if (rmt_bdname) { + rmt_bdname_len = rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN ? ESP_BT_GAP_MAX_BDNAME_LEN : rmt_bdname_len; + memcpy(bdname, rmt_bdname, rmt_bdname_len); + bdname[rmt_bdname_len] = 0; + *bdname_len = rmt_bdname_len; + return true; + } + return false; +} + +static esp_err_t _spp_queue_packet(uint8_t *data, size_t len){ + if(!data || !len){ + log_w("No data provided"); + return ESP_OK; + } + spp_packet_t * packet = (spp_packet_t*)malloc(sizeof(spp_packet_t) + len); + if(!packet){ + log_e("SPP TX Packet Malloc Failed!"); + return ESP_FAIL; + } + packet->len = len; + memcpy(packet->data, data, len); + if (!_spp_tx_queue || xQueueSend(_spp_tx_queue, &packet, SPP_TX_QUEUE_TIMEOUT) != pdPASS) { + log_e("SPP TX Queue Send Failed!"); + free(packet); + return ESP_FAIL; + } + return ESP_OK; +} + +const uint16_t SPP_TX_MAX = 330; +static uint8_t _spp_tx_buffer[SPP_TX_MAX]; +static uint16_t _spp_tx_buffer_len = 0; + +static bool _spp_send_buffer(){ + if((xEventGroupWaitBits(_spp_event_group, SPP_CONGESTED, pdFALSE, pdTRUE, SPP_CONGESTED_TIMEOUT) & SPP_CONGESTED) != 0){ + if(!_spp_client){ + log_v("SPP Client Gone!"); + return false; + } + log_v("SPP Write %u", _spp_tx_buffer_len); + esp_err_t err = esp_spp_write(_spp_client, _spp_tx_buffer_len, _spp_tx_buffer); + if(err != ESP_OK){ + log_e("SPP Write Failed! [0x%X]", err); + return false; + } + _spp_tx_buffer_len = 0; + if(xSemaphoreTake(_spp_tx_done, SPP_TX_DONE_TIMEOUT) != pdTRUE){ + log_e("SPP Ack Failed!"); + return false; + } + return true; + } + log_e("SPP Write Congested!"); + return false; +} + +static void _spp_tx_task(void * arg){ + spp_packet_t *packet = NULL; + size_t len = 0, to_send = 0; + uint8_t * data = NULL; + for (;;) { + if(_spp_tx_queue && xQueueReceive(_spp_tx_queue, &packet, portMAX_DELAY) == pdTRUE && packet){ + if(packet->len <= (SPP_TX_MAX - _spp_tx_buffer_len)){ + memcpy(_spp_tx_buffer+_spp_tx_buffer_len, packet->data, packet->len); + _spp_tx_buffer_len+=packet->len; + free(packet); + packet = NULL; + if(SPP_TX_MAX == _spp_tx_buffer_len || uxQueueMessagesWaiting(_spp_tx_queue) == 0){ + _spp_send_buffer(); + } + } else { + len = packet->len; + data = packet->data; + to_send = SPP_TX_MAX - _spp_tx_buffer_len; + memcpy(_spp_tx_buffer+_spp_tx_buffer_len, data, to_send); + _spp_tx_buffer_len = SPP_TX_MAX; + data += to_send; + len -= to_send; + if(!_spp_send_buffer()){ + len = 0; + } + while(len >= SPP_TX_MAX){ + memcpy(_spp_tx_buffer, data, SPP_TX_MAX); + _spp_tx_buffer_len = SPP_TX_MAX; + data += SPP_TX_MAX; + len -= SPP_TX_MAX; + if(!_spp_send_buffer()){ + len = 0; + break; + } + } + if(len){ + memcpy(_spp_tx_buffer, data, len); + _spp_tx_buffer_len += len; + if(uxQueueMessagesWaiting(_spp_tx_queue) == 0){ + _spp_send_buffer(); + } + } + free(packet); + packet = NULL; + } + } else { + log_e("Something went horribly wrong"); + } + } + vTaskDelete(NULL); + _spp_task_handle = NULL; +} + +static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) +{ + switch (event) + { + case ESP_SPP_INIT_EVT: // Enum 0 - When SPP is initialized + log_i("ESP_SPP_INIT_EVT"); +#ifdef ESP_IDF_VERSION_MAJOR + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); +#else + esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); +#endif + if (!_isMaster) { + log_i("ESP_SPP_INIT_EVT: slave: start"); + esp_spp_start_srv(ESP_SPP_SEC_NONE, ESP_SPP_ROLE_SLAVE, 0, _spp_server_name); + } + xEventGroupSetBits(_spp_event_group, SPP_RUNNING); + break; + + case ESP_SPP_UNINIT_EVT: // Enum 1 - When SPP is deinitialized + log_i("ESP_SPP_UNINIT_EVT: SPP is deinitialized"); + break; + + case ESP_SPP_DISCOVERY_COMP_EVT: // Enum 8 - When SDP discovery complete + log_i("ESP_SPP_DISCOVERY_COMP_EVT num=%d", param->disc_comp.scn_num); + if (param->disc_comp.status == ESP_SPP_SUCCESS) { + for(int i=0; i < param->disc_comp.scn_num; i++) { + log_d("ESP_SPP_DISCOVERY_COMP_EVT: spp [%d] channel: %d service name:%s", i, param->disc_comp.scn[i], param->disc_comp.service_name[0]); + } + if(_doConnect) { + if(param->disc_comp.scn_num > 0) { +#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) + char bda_str[18]; + log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote %s channel %d", + bda2str(_peer_bd_addr, bda_str, sizeof(bda_str)), + param->disc_comp.scn[0]); +#endif + xEventGroupClearBits(_spp_event_group, SPP_CLOSED); + if(esp_spp_connect(_sec_mask, _role, param->disc_comp.scn[0], _peer_bd_addr) != ESP_OK) { + log_e("ESP_SPP_DISCOVERY_COMP_EVT connect failed"); + xEventGroupSetBits(_spp_event_group, SPP_CLOSED); + } + } else { + log_e("ESP_SPP_DISCOVERY_COMP_EVT remote doesn't offer an SPP channel"); + xEventGroupSetBits(_spp_event_group, SPP_CLOSED); + } + } else { + for(int i=0; i < param->disc_comp.scn_num; i++) { + sdpRecords[param->disc_comp.scn[i]] = param->disc_comp.service_name[0]; + } + } + } else { + log_e("ESP_SPP_DISCOVERY_COMP_EVT failed!, status:%d", param->disc_comp.status); + } + xEventGroupSetBits(_bt_event_group, BT_SDP_COMPLETED); + break; + + case ESP_SPP_OPEN_EVT: // Enum 26 - When SPP Client connection open + log_i("ESP_SPP_OPEN_EVT"); + if (!_spp_client){ + _spp_client = param->open.handle; + } else { + secondConnectionAttempt = true; + esp_spp_disconnect(param->open.handle); + } + xEventGroupClearBits(_spp_event_group, SPP_DISCONNECTED); + xEventGroupSetBits(_spp_event_group, SPP_CONNECTED); + xEventGroupSetBits(_spp_event_group, SPP_CONGESTED); + break; + + case ESP_SPP_CLOSE_EVT: // Enum 27 - When SPP connection closed + if ((param->close.async == false && param->close.status == ESP_SPP_SUCCESS) || param->close.async) { + log_i("ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d attempt %u", param->close.status, + param->close.handle, param->close.async, secondConnectionAttempt); + if(secondConnectionAttempt) { + secondConnectionAttempt = false; + } else { + _spp_client = 0; + xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED); + xEventGroupSetBits(_spp_event_group, SPP_CONGESTED); + xEventGroupSetBits(_spp_event_group, SPP_CLOSED); + xEventGroupClearBits(_spp_event_group, SPP_CONNECTED); + } + } else { + log_e("ESP_SPP_CLOSE_EVT failed!, status:%d", param->close.status); + } + break; + + case ESP_SPP_START_EVT: // Enum 28 - When SPP server started + log_i("ESP_SPP_START_EVT"); + break; + + case ESP_SPP_CL_INIT_EVT: // Enum 29 - When SPP client initiated a connection + if (param->cl_init.status == ESP_SPP_SUCCESS) { + log_i("ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id); + } else { + log_i("ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status); + } + break; + + case ESP_SPP_DATA_IND_EVT: // Enum 30 - When SPP connection received data, only for ESP_SPP_MODE_CB + log_v("ESP_SPP_DATA_IND_EVT len=%d handle=%d", param->data_ind.len, param->data_ind.handle); + //esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len); //for low level debug + //ets_printf("r:%u\n", param->data_ind.len); + + if(custom_data_callback){ + custom_data_callback(param->data_ind.data, param->data_ind.len); + } else if (_spp_rx_queue != NULL){ + for (int i = 0; i < param->data_ind.len; i++){ + if(xQueueSend(_spp_rx_queue, param->data_ind.data + i, (TickType_t)0) != pdTRUE){ + log_e("RX Full! Discarding %u bytes", param->data_ind.len - i); + break; + } + } + } + break; + + case ESP_SPP_CONG_EVT: // Enum 31 - When SPP connection congestion status changed, only for ESP_SPP_MODE_CB + if(param->cong.cong){ + xEventGroupClearBits(_spp_event_group, SPP_CONGESTED); + } else { + xEventGroupSetBits(_spp_event_group, SPP_CONGESTED); + } + log_v("ESP_SPP_CONG_EVT: %s", param->cong.cong?"CONGESTED":"FREE"); + break; + + case ESP_SPP_WRITE_EVT: // Enum 33 - When SPP write operation completes, only for ESP_SPP_MODE_CB + if (param->write.status == ESP_SPP_SUCCESS) { + if(param->write.cong){ + xEventGroupClearBits(_spp_event_group, SPP_CONGESTED); + } + log_v("ESP_SPP_WRITE_EVT: %u %s", param->write.len, param->write.cong?"CONGESTED":""); + } else { + log_e("ESP_SPP_WRITE_EVT failed!, status:%d", param->write.status); + } + xSemaphoreGive(_spp_tx_done);//we can try to send another packet + break; + + case ESP_SPP_SRV_OPEN_EVT: // Enum 34 - When SPP Server connection open + if (param->srv_open.status == ESP_SPP_SUCCESS) { + log_i("ESP_SPP_SRV_OPEN_EVT: %u", _spp_client); + if (!_spp_client){ + _spp_client = param->srv_open.handle; + _spp_tx_buffer_len = 0; + } else { + secondConnectionAttempt = true; + esp_spp_disconnect(param->srv_open.handle); + } + xEventGroupClearBits(_spp_event_group, SPP_DISCONNECTED); + xEventGroupSetBits(_spp_event_group, SPP_CONNECTED); + } else { + log_e("ESP_SPP_SRV_OPEN_EVT Failed!, status:%d", param->srv_open.status); + } + break; + + case ESP_SPP_SRV_STOP_EVT: // Enum 35 - When SPP server stopped + log_i("ESP_SPP_SRV_STOP_EVT"); + break; + + case ESP_SPP_VFS_REGISTER_EVT: // Enum 36 - When SPP VFS register + log_i("ESP_SPP_VFS_REGISTER_EVT"); + break; + + case ESP_SPP_VFS_UNREGISTER_EVT: // Enum 37 - When SPP VFS unregister + log_i("ESP_SPP_VFS_UNREGISTER_EVT"); + break; + + default: + log_i("ESP_SPP_* event #%d unhandled", event); + break; + } + if(custom_spp_callback)(*custom_spp_callback)(event, param); +} + +void BluetoothSerial::onData(BluetoothSerialDataCb cb){ + custom_data_callback = cb; +} + + +static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) +{ + switch(event){ + case ESP_BT_GAP_DISC_RES_EVT: { // Enum 0 - Device discovery result event + log_i("ESP_BT_GAP_DISC_RES_EVT properties=%d", param->disc_res.num_prop); +#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) + char bda_str[18]; + log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18)); +#endif + BTAdvertisedDeviceSet advertisedDevice; + uint8_t peer_bdname_len = 0; + char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1]; + for (int i = 0; i < param->disc_res.num_prop; i++) { + switch(param->disc_res.prop[i].type) { + case ESP_BT_GAP_DEV_PROP_BDNAME: // Enum 1 - Bluetooth device name, value type is int8_t [] + peer_bdname_len = param->disc_res.prop[i].len; + memcpy(peer_bdname, param->disc_res.prop[i].val, peer_bdname_len); + peer_bdname_len--; // len includes 0 terminator + log_v("ESP_BT_GAP_DISC_RES_EVT : BDNAME : %s : %d", peer_bdname, peer_bdname_len); + if (strlen(_remote_name) == peer_bdname_len + && strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) { + log_i("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_BDNAME : %s", peer_bdname); + _isRemoteAddressSet = true; + memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN); + esp_bt_gap_cancel_discovery(); + esp_spp_start_discovery(_peer_bd_addr); + } + break; + + case ESP_BT_GAP_DEV_PROP_COD: // Enum 2 - Class of Device, value type is uint32_t + if (param->disc_res.prop[i].len <= sizeof(int)) { + uint32_t cod = 0; + memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len); + advertisedDevice.setCOD(cod); + log_d("ESP_BT_GAP_DEV_PROP_COD 0x%x", cod); + } else { + log_d("ESP_BT_GAP_DEV_PROP_COD invalid COD: Value size larger than integer"); + } + break; + + case ESP_BT_GAP_DEV_PROP_RSSI: // Enum 3 - Received Signal strength Indication, value type is int8_t, ranging from -128 to 127 + if (param->disc_res.prop[i].len <= sizeof(int)) { + uint8_t rssi = 0; + memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len); + log_d("ESP_BT_GAP_DEV_PROP_RSSI %d", rssi); + advertisedDevice.setRSSI(rssi); + } else { + log_d("ESP_BT_GAP_DEV_PROP_RSSI invalid RSSI: Value size larger than integer"); + } + break; + + case ESP_BT_GAP_DEV_PROP_EIR: // Enum 4 - Extended Inquiry Response, value type is uint8_t [] + if (get_name_from_eir((uint8_t*)param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)) { + log_i("ESP_BT_GAP_DISC_RES_EVT : EIR : %s : %d", peer_bdname, peer_bdname_len); + if (strlen(_remote_name) == peer_bdname_len + && strncmp(peer_bdname, _remote_name, peer_bdname_len) == 0) { + log_v("ESP_BT_GAP_DISC_RES_EVT : SPP_START_DISCOVERY_EIR : %s", peer_bdname, peer_bdname_len); + _isRemoteAddressSet = true; + memcpy(_peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN); + esp_bt_gap_cancel_discovery(); + esp_spp_start_discovery(_peer_bd_addr); + } + } + break; + + default: + log_i("ESP_BT_GAP_DISC_RES_EVT unknown property [%d]:type:%d", i, param->disc_res.prop[i].type); + break; + } + if (_isRemoteAddressSet) + break; + } + if (peer_bdname_len) + advertisedDevice.setName(peer_bdname); + esp_bd_addr_t addr; + memcpy(addr, param->disc_res.bda, ESP_BD_ADDR_LEN); + advertisedDevice.setAddress(BTAddress(addr)); + if (scanResults.add(advertisedDevice) && advertisedDeviceCb) + advertisedDeviceCb(&advertisedDevice); + } + break; + + case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: // Enum 1 - Discovery state changed event + if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) { + log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT stopped"); + xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING); + xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_COMPLETED); + } else { // ESP_BT_GAP_DISCOVERY_STARTED + log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT started"); + xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_COMPLETED); + xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_RUNNING); + } + break; + + case ESP_BT_GAP_RMT_SRVCS_EVT: // Enum 2 - Get remote services event + log_i( "ESP_BT_GAP_RMT_SRVCS_EVT: status = %d, num_uuids = %d", param->rmt_srvcs.stat, param->rmt_srvcs.num_uuids); + break; + + case ESP_BT_GAP_RMT_SRVC_REC_EVT: // Enum 3 - Get remote service record event + log_i("ESP_BT_GAP_RMT_SRVC_REC_EVT: status = %d", param->rmt_srvc_rec.stat); + break; + + case ESP_BT_GAP_AUTH_CMPL_EVT: // Enum 4 - Authentication complete event + if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) { + log_v("authentication success: %s", param->auth_cmpl.device_name); + if (auth_complete_callback) { + auth_complete_callback(true); + } + } else { + log_e("authentication failed, status:%d", param->auth_cmpl.stat); + if (auth_complete_callback) { + auth_complete_callback(false); + } + } + break; + case ESP_BT_GAP_PIN_REQ_EVT: // Enum 5 - Legacy Pairing Pin code request + log_i("ESP_BT_GAP_PIN_REQ_EVT (min_16_digit=%d)", param->pin_req.min_16_digit); + if (param->pin_req.min_16_digit && _pin_code_len < 16) { + esp_bt_gap_pin_reply(param->pin_req.bda, false, 0, NULL); + } else { + //log_i("Input pin code: \"%s\"=0x%x", _pin_code); + log_i("Input pin code: \"%.*s\"=0x%x", _pin_code_len, _pin_code, *(int*)_pin_code); + esp_bt_gap_pin_reply(param->pin_req.bda, true, _pin_code_len, _pin_code); + } + break; +#ifdef CONFIG_BT_SSP_ENABLED + case ESP_BT_GAP_CFM_REQ_EVT: // Enum 6 - Security Simple Pairing User Confirmation request. + log_i("ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val); + if (confirm_request_callback) { + memcpy(current_bd_addr, param->cfm_req.bda, sizeof(esp_bd_addr_t)); + confirm_request_callback(param->cfm_req.num_val); + } + else { + log_w("ESP_BT_GAP_CFM_REQ_EVT: confirm_request_callback does not exist - refusing pairing"); + esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false); + } + break; +#endif + + case ESP_BT_GAP_KEY_NOTIF_EVT: // Enum 7 - Security Simple Pairing Passkey Notification + log_i("ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey); + break; + +#ifdef CONFIG_BT_SSP_ENABLED + case ESP_BT_GAP_KEY_REQ_EVT: // Enum 8 - Security Simple Pairing Passkey request + log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!"); + if (key_request_callback) { + memcpy(current_bd_addr, param->cfm_req.bda, sizeof(esp_bd_addr_t)); + key_request_callback(); + } else { + log_w("ESP_BT_GAP_KEY_REQ_EVT: key_request_callback does not exist - refuseing pairing"); + esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, false); + } + break; +#endif + + case ESP_BT_GAP_READ_RSSI_DELTA_EVT: // Enum 9 - Read rssi event + log_i("ESP_BT_GAP_READ_RSSI_DELTA_EVT Read rssi event"); + break; + case ESP_BT_GAP_CONFIG_EIR_DATA_EVT: // Enum 10 - Config EIR data event + log_i("ESP_BT_GAP_CONFIG_EIR_DATA_EVT: stat:%d num:%d", param->config_eir_data.stat, param->config_eir_data.eir_type_num); + break; + + case ESP_BT_GAP_SET_AFH_CHANNELS_EVT: // Enum 11 - Set AFH channels event + log_i("ESP_BT_GAP_SET_AFH_CHANNELS_EVT Set AFH channels event"); + break; + + case ESP_BT_GAP_READ_REMOTE_NAME_EVT: // Enum 12 - Read Remote Name event + if (param->read_rmt_name.stat == ESP_BT_STATUS_SUCCESS ) { + log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: %s", param->read_rmt_name.rmt_name); + memcpy(_rmt_name, param->read_rmt_name.rmt_name, ESP_BT_GAP_MAX_BDNAME_LEN + 1); + _rmt_name_valid = true; + } else { + log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: no success stat:%d", param->read_rmt_name.stat); + } + break; + + + case ESP_BT_GAP_MODE_CHG_EVT: // Enum 13 + log_i("ESP_BT_GAP_MODE_CHG_EVT: mode: %d", param->mode_chg.mode); + break; + + case ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT: // Enum - 14 remove bond device complete event + log_i("ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT remove bond device complete event"); + break; + + case ESP_BT_GAP_QOS_CMPL_EVT: // Enum 15 - QOS complete event + log_i("ESP_BT_GAP_QOS_CMPL_EVT QOS complete event"); + break; + + case ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT: // Enum 16 - ACL connection complete status event + log_i("ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT ACL connection complete status event"); + break; + + case ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT: // Enum 17 - ACL disconnection complete status event + log_i("ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT ACL disconnection complete status event: reason %d, handle %d", param->acl_disconn_cmpl_stat.reason, param->acl_disconn_cmpl_stat.handle); + break; + + default: + log_i("ESP-BT_GAP_* unknown message: %d", event); + break; + } +} + +static bool _init_bt(const char *deviceName) +{ + if(!_bt_event_group){ + _bt_event_group = xEventGroupCreate(); + if(!_bt_event_group){ + log_e("BT Event Group Create Failed!"); + return false; + } + xEventGroupClearBits(_bt_event_group, 0xFFFFFF); + } + if(!_spp_event_group){ + _spp_event_group = xEventGroupCreate(); + if(!_spp_event_group){ + log_e("SPP Event Group Create Failed!"); + return false; + } + xEventGroupClearBits(_spp_event_group, 0xFFFFFF); + xEventGroupSetBits(_spp_event_group, SPP_CONGESTED); + xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED); + xEventGroupSetBits(_spp_event_group, SPP_CLOSED); + } + if (_spp_rx_queue == NULL){ + _spp_rx_queue = xQueueCreate(RX_QUEUE_SIZE, sizeof(uint8_t)); //initialize the queue + if (_spp_rx_queue == NULL){ + log_e("RX Queue Create Failed"); + return false; + } + } + if (_spp_tx_queue == NULL){ + _spp_tx_queue = xQueueCreate(TX_QUEUE_SIZE, sizeof(spp_packet_t*)); //initialize the queue + if (_spp_tx_queue == NULL){ + log_e("TX Queue Create Failed"); + return false; + } + } + if(_spp_tx_done == NULL){ + _spp_tx_done = xSemaphoreCreateBinary(); + if (_spp_tx_done == NULL){ + log_e("TX Semaphore Create Failed"); + return false; + } + xSemaphoreTake(_spp_tx_done, 0); + } + + if(!_spp_task_handle){ + xTaskCreatePinnedToCore(_spp_tx_task, "spp_tx", 4096, NULL, 10, &_spp_task_handle, 0); + if(!_spp_task_handle){ + log_e("Network Event Task Start Failed!"); + return false; + } + } + + if (!btStarted() && !btStart()){ + log_e("initialize controller failed"); + return false; + } + + esp_bluedroid_status_t bt_state = esp_bluedroid_get_status(); + if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){ + if (esp_bluedroid_init()) { + log_e("initialize bluedroid failed"); + return false; + } + } + + if (bt_state != ESP_BLUEDROID_STATUS_ENABLED){ + if (esp_bluedroid_enable()) { + log_e("enable bluedroid failed"); + return false; + } + } + + if (esp_bt_gap_register_callback(esp_bt_gap_cb) != ESP_OK) { + log_e("gap register failed"); + return false; + } + + if (esp_spp_register_callback(esp_spp_cb) != ESP_OK){ + log_e("spp register failed"); + return false; + } + + esp_spp_cfg_t cfg = BT_SPP_DEFAULT_CONFIG(); + cfg.mode = ESP_SPP_MODE_CB; + if (esp_spp_enhanced_init(&cfg) != ESP_OK){ + log_e("spp init failed"); + return false; + } + + log_i("device name set"); + esp_bt_dev_set_device_name(deviceName); + +#ifdef CONFIG_BT_SSP_ENABLED + if (_enableSSP) { + log_i("Simple Secure Pairing"); + esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE; + esp_bt_io_cap_t iocap; + if(_IO_CAP_INPUT && _IO_CAP_OUTPUT){ + iocap = ESP_BT_IO_CAP_IO; // Display with prompt + }else if(!_IO_CAP_INPUT && _IO_CAP_OUTPUT){ + iocap = ESP_BT_IO_CAP_OUT; // DisplayOnly + }else if(_IO_CAP_INPUT && !_IO_CAP_OUTPUT){ + iocap = ESP_BT_IO_CAP_IN; // Input only + }else if(!_IO_CAP_INPUT && !_IO_CAP_OUTPUT){ + iocap = ESP_BT_IO_CAP_NONE; // No input/output + } + esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t)); + } +#endif + + // the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack + esp_bt_cod_t cod; + cod.major = 0b00001; + cod.minor = 0b000100; + cod.service = 0b00000010110; + if (esp_bt_gap_set_cod(cod, ESP_BT_INIT_COD) != ESP_OK) { + log_e("set cod failed"); + return false; + } + return true; +} + +static bool _stop_bt() +{ + if (btStarted()){ + if(_spp_client) + esp_spp_disconnect(_spp_client); + esp_spp_deinit(); + esp_bluedroid_disable(); + esp_bluedroid_deinit(); + btStop(); + } + _spp_client = 0; + if(_spp_task_handle){ + vTaskDelete(_spp_task_handle); + _spp_task_handle = NULL; + } + if(_spp_event_group){ + vEventGroupDelete(_spp_event_group); + _spp_event_group = NULL; + } + if(_spp_rx_queue){ + vQueueDelete(_spp_rx_queue); + //ToDo: clear RX queue when in packet mode + _spp_rx_queue = NULL; + } + if(_spp_tx_queue){ + spp_packet_t *packet = NULL; + while(xQueueReceive(_spp_tx_queue, &packet, 0) == pdTRUE){ + free(packet); + } + vQueueDelete(_spp_tx_queue); + _spp_tx_queue = NULL; + } + if (_spp_tx_done) { + vSemaphoreDelete(_spp_tx_done); + _spp_tx_done = NULL; + } + if (_bt_event_group) { + vEventGroupDelete(_bt_event_group); + _bt_event_group = NULL; + } + return true; +} + +static bool waitForConnect(int timeout) { + TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS; + // wait for connected or closed + EventBits_t rc = xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED | SPP_CLOSED, pdFALSE, pdFALSE, xTicksToWait); + if((rc & SPP_CONNECTED) != 0) + return true; + else if((rc & SPP_CLOSED) != 0) { + log_d("connection closed!"); + return false; + } + log_d("timeout"); + return false; +} + +static bool waitForDiscovered(int timeout) { + TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS; + return (xEventGroupWaitBits(_spp_event_group, BT_DISCOVERY_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_DISCOVERY_COMPLETED) != 0; +} + +static bool waitForSDPRecord(int timeout) { + TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS; + return (xEventGroupWaitBits(_bt_event_group, BT_SDP_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_SDP_COMPLETED) != 0; +} + +/* + * Serial Bluetooth Arduino + * + * */ + +BluetoothSerial::BluetoothSerial() +{ + local_name = "ESP32"; //default bluetooth name +} + +BluetoothSerial::~BluetoothSerial(void) +{ + _stop_bt(); +} + +/** + * @Param isMaster set to true if you want to connect to an other device + */ +bool BluetoothSerial::begin(String localName, bool isMaster) +{ + _isMaster = isMaster; + if (localName.length()){ + local_name = localName; + } + return _init_bt(local_name.c_str()); +} + +int BluetoothSerial::available(void) +{ + if (_spp_rx_queue == NULL){ + return 0; + } + return uxQueueMessagesWaiting(_spp_rx_queue); +} + +int BluetoothSerial::peek(void) +{ + uint8_t c; + if (_spp_rx_queue && xQueuePeek(_spp_rx_queue, &c, this->timeoutTicks)){ + return c; + } + return -1; +} + +bool BluetoothSerial::hasClient(void) +{ + return _spp_client > 0; +} + +int BluetoothSerial::read() +{ + + uint8_t c = 0; + if (_spp_rx_queue && xQueueReceive(_spp_rx_queue, &c, this->timeoutTicks)){ + return c; + } + return -1; +} + +/** + * Set timeout for read / peek + */ +void BluetoothSerial::setTimeout(int timeoutMS) +{ + Stream::setTimeout(timeoutMS); + this->timeoutTicks=timeoutMS / portTICK_PERIOD_MS; +} + +size_t BluetoothSerial::write(uint8_t c) +{ + return write(&c, 1); +} + +size_t BluetoothSerial::write(const uint8_t *buffer, size_t size) +{ + if (!_spp_client){ + return 0; + } + return (_spp_queue_packet((uint8_t *)buffer, size) == ESP_OK) ? size : 0; +} + +void BluetoothSerial::flush() +{ + if (_spp_tx_queue != NULL){ + while(uxQueueMessagesWaiting(_spp_tx_queue) > 0){ + delay(100); + } + } +} + +void BluetoothSerial::end() +{ + _stop_bt(); +} + +#ifdef CONFIG_BT_SSP_ENABLED +void BluetoothSerial::onConfirmRequest(ConfirmRequestCb cb) +{ + confirm_request_callback = cb; +} + +void BluetoothSerial::onKeyRequest(KeyRequestCb cb) +{ + key_request_callback = cb; +} + +void BluetoothSerial::respondPasskey(uint32_t passkey){ + esp_bt_gap_ssp_passkey_reply(current_bd_addr, true, passkey); +} +#endif + +void BluetoothSerial::onAuthComplete(AuthCompleteCb cb) +{ + auth_complete_callback = cb; +} + +void BluetoothSerial::confirmReply(boolean confirm) +{ + esp_bt_gap_ssp_confirm_reply(current_bd_addr, confirm); +} + + +esp_err_t BluetoothSerial::register_callback(esp_spp_cb_t * callback) +{ + custom_spp_callback = callback; + return ESP_OK; +} + +#ifdef CONFIG_BT_SSP_ENABLED +// Enable Simple Secure Pairing (using generated PIN) +// This must be called before calling begin, otherwise has no effect! +void BluetoothSerial::enableSSP() { + if(isReady(false, READY_TIMEOUT)){ + log_i("Attempted to enable SSP for already initialized driver. Restart to take effect with end() followed by begin()"); + return; + } + _enableSSP = true; + _IO_CAP_INPUT = true; + _IO_CAP_OUTPUT = true; +} + +// Enable Simple Secure Pairing (using generated PIN) +// This must be called before calling begin, otherwise has no effect! +// Behavior description: +// When both Input and Output are false only the other device authenticates pairing without any pin. +// When Output is true and Input is false only the other device authenticates pairing without any pin. +// When both Input and Output are true both devices display randomly generated code and if they match authenticate pairing on both devices +// - This must be implemented by registering callback via onConfirmRequest() and in this callback request user input and call confirmReply(true); if the authenticated +// otherwise call `confirmReply(false)` to reject the pairing. +// When Input is true and Output is false User will be required to input the passkey to the ESP32 device to authenticate. +// - This must be implemented by registering callback via onKeyRequest() and in this callback the entered passkey will be responded via respondPasskey(passkey); +void BluetoothSerial::enableSSP(bool inputCpability, bool outputCapability) { + log_i("Enabling SSP: input capability=%d; output capability=%d", inputCpability, outputCapability); + _enableSSP = true; + _IO_CAP_INPUT = inputCpability; + _IO_CAP_OUTPUT = outputCapability; +} + +// Disable Simple Secure Pairing (using generated PIN) +// This must be called before calling begin, otherwise has no effect! +void BluetoothSerial::disableSSP() { + _enableSSP = false; +} + +#else + +bool BluetoothSerial::setPin(const char *pin, uint8_t pin_code_len){ + if(pin_code_len == 0 || pin_code_len > 16){ + log_e("PIN code must be 1-16 Bytes long! Called with length %d", pin_code_len); + return false; + } + _pin_code_len = pin_code_len; + memcpy(_pin_code, pin, pin_code_len); + return (esp_bt_gap_set_pin(ESP_BT_PIN_TYPE_FIXED, _pin_code_len, _pin_code) == ESP_OK); +} +#endif + +bool BluetoothSerial::connect(String remoteName) +{ + bool retval = false; + + if (!isReady(true, READY_TIMEOUT)) return false; + if (remoteName && remoteName.length() < 1) { + log_e("No remote name is provided"); + return false; + } + disconnect(); + _doConnect = true; + _isRemoteAddressSet = true; + _sec_mask = ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE; + _role = ESP_SPP_ROLE_MASTER; + strncpy(_remote_name, remoteName.c_str(), ESP_BT_GAP_MAX_BDNAME_LEN); + _remote_name[ESP_BT_GAP_MAX_BDNAME_LEN] = 0; + log_i("master : remoteName"); + // will first resolve name to address +#ifdef ESP_IDF_VERSION_MAJOR + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); +#else + esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); +#endif + xEventGroupClearBits(_spp_event_group, SPP_CLOSED); + if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, INQ_LEN, INQ_NUM_RSPS) == ESP_OK) { + retval = waitForConnect(SCAN_TIMEOUT); + } + if (retval == false) { + _isRemoteAddressSet = false; + } + return retval; +} + +/** + * @Param channel: specify channel or 0 for auto-detect + * @Param sec_mask: + * ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE + * ESP_SPP_SEC_NONE + * @Param role: + * ESP_SPP_ROLE_MASTER master can handle up to 7 connections to slaves + * ESP_SPP_ROLE_SLAVE can only have one connection to a master + */ +bool BluetoothSerial::connect(uint8_t remoteAddress[], int channel, esp_spp_sec_t sec_mask, esp_spp_role_t role) +{ + bool retval = false; + if (!isReady(true, READY_TIMEOUT)) return false; + if (!remoteAddress) { + log_e("No remote address is provided"); + return false; + } + disconnect(); + _doConnect = true; + _remote_name[0] = 0; + _isRemoteAddressSet = true; + _sec_mask = sec_mask; + _role = role; + memcpy(_peer_bd_addr, remoteAddress, ESP_BD_ADDR_LEN); + log_i("master : remoteAddress"); + xEventGroupClearBits(_spp_event_group, SPP_CLOSED); + if (channel > 0) { +#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) + char bda_str[18]; + log_i("spp connect to remote %s channel %d", + bda2str(_peer_bd_addr, bda_str, sizeof(bda_str)), + channel); +#endif + if(esp_spp_connect(sec_mask, role, channel, _peer_bd_addr) != ESP_OK ) { + log_e("spp connect failed"); + retval = false; + } else { + retval = waitForConnect(READY_TIMEOUT); + if(retval) { + log_i("connected"); + } else { + if(this->isClosed()) { + log_e("connect failed"); + } else { + log_e("connect timed out after %dms", READY_TIMEOUT); + } + } + } + } else if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) { + retval = waitForConnect(READY_TIMEOUT); + } + + if (!retval) { + _isRemoteAddressSet = false; + } + return retval; +} + +bool BluetoothSerial::connect() +{ + if (!isReady(true, READY_TIMEOUT)) return false; + _doConnect = true; + if (_isRemoteAddressSet){ + disconnect(); + // use resolved or set address first + log_i("master : remoteAddress"); + if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) { + return waitForConnect(READY_TIMEOUT); + } + return false; + } else if (_remote_name[0]) { + disconnect(); + log_i("master : remoteName"); + // will resolve name to address first - it may take a while +#ifdef ESP_IDF_VERSION_MAJOR + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); +#else + esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); +#endif + if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, INQ_LEN, INQ_NUM_RSPS) == ESP_OK) { + return waitForConnect(SCAN_TIMEOUT); + } + return false; + } + log_e("Neither Remote name nor address was provided"); + return false; +} + +bool BluetoothSerial::disconnect() { + if (_spp_client) { + flush(); + log_i("disconnecting"); + if (esp_spp_disconnect(_spp_client) == ESP_OK) { + TickType_t xTicksToWait = READY_TIMEOUT / portTICK_PERIOD_MS; + return (xEventGroupWaitBits(_spp_event_group, SPP_DISCONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_DISCONNECTED) != 0; + } + } + return false; +} + +bool BluetoothSerial::unpairDevice(uint8_t remoteAddress[]) { + if (isReady(false, READY_TIMEOUT)) { + log_i("removing bonded device"); + return (esp_bt_gap_remove_bond_device(remoteAddress) == ESP_OK); + } + return false; +} + +bool BluetoothSerial::connected(int timeout) { + return waitForConnect(timeout); +} + +/** + * true if a connection terminated or a connection attempt failed + */ +bool BluetoothSerial::isClosed() { + return xEventGroupGetBits(_spp_event_group) & SPP_CLOSED; +} + +bool BluetoothSerial::isReady(bool checkMaster, int timeout) { + if (checkMaster && !_isMaster) { + log_e("Master mode is not active. Call begin(localName, true) to enable Master mode"); + return false; + } + if (!btStarted()) { + log_e("BT is not initialized. Call begin() first"); + return false; + } + TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS; + return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) & SPP_RUNNING) != 0; +} + + +/** + * @brief RemoteName or address are not allowed to be set during discovery + * (otherwise it might connect automatically and stop discovery) + * @param[in] timeoutMs can range from MIN_INQ_TIME to MAX_INQ_TIME + * @return in case of Error immediately Empty ScanResults. + */ +BTScanResults* BluetoothSerial::discover(int timeoutMs) { + scanResults.clear(); + if (timeoutMs < MIN_INQ_TIME || timeoutMs > MAX_INQ_TIME){ + log_e("Timeout out of bounds: MIN=%d; MAX=%d; requested=%d", MIN_INQ_TIME, MAX_INQ_TIME, timeoutMs); + return nullptr; + } + int timeout = timeoutMs / INQ_TIME; + log_i("discover::disconnect"); + disconnect(); + log_i("discovering"); + // will resolve name to address first - it may take a while + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); + if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK) { + waitForDiscovered(timeoutMs); + log_i("gap_cancel_discovery()"); + esp_bt_gap_cancel_discovery(); + } + return &scanResults; +} + +/** + * @brief RemoteName or address are not allowed to be set during discovery + * (otherwise it might connect automatically and stop discovery) + * @param[in] cb called when a [b]new[/b] device has been discovered + * @param[in] timeoutMs can be 0 or range from MIN_INQ_TIME to MAX_INQ_TIME + * + * @return Whether start was successful or problems with params + */ +bool BluetoothSerial::discoverAsync(BTAdvertisedDeviceCb cb, int timeoutMs) { + scanResults.clear(); + if (strlen(_remote_name) || _isRemoteAddressSet) + return false; + int timeout = timeoutMs / INQ_TIME; + disconnect(); + advertisedDeviceCb = cb; + log_i("discovering"); + // will resolve name to address first - it may take a while + esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); + if (timeout > 0) + return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK; + else return esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, ESP_BT_GAP_MAX_INQ_LEN, 0) == ESP_OK; +} + +/** @brief Stops the asynchronous discovery and clears the callback */ +void BluetoothSerial::discoverAsyncStop() { + esp_bt_gap_cancel_discovery(); + advertisedDeviceCb = nullptr; +} + +/** @brief Clears scanResult entries */ +void BluetoothSerial::discoverClear() { + scanResults.clear(); +} + +/** @brief Can be used while discovering asynchronously + * Will be returned also on synchronous discovery. + * + * @return BTScanResults contains several information of found devices + */ +BTScanResults* BluetoothSerial::getScanResults() { + return &scanResults; +} + +BluetoothSerial::operator bool() const +{ + return true; +} + +/** + * SDP scan address + * esp_spp_start_discovery doesn't tell us the btAddress in the callback, so we have to wait until it's finished + */ +std::map BluetoothSerial::getChannels(const BTAddress &remoteAddress) { + if(xEventGroupGetBits(_bt_event_group) & BT_SDP_RUNNING) { + log_e("getChannels failed - already running"); + } + xEventGroupSetBits(_bt_event_group, BT_SDP_RUNNING); + xEventGroupClearBits(_bt_event_group, BT_SDP_COMPLETED); + _doConnect = false; + sdpRecords.clear(); + log_d("esp_spp_start_discovery"); + if (esp_spp_start_discovery(*remoteAddress.getNative()) != ESP_OK) { + log_e("esp_spp_start_discovery failed"); + } else { + if(! waitForSDPRecord(READY_TIMEOUT)) { + log_e("getChannels failed timeout"); + } + log_d("esp_spp_start_discovery wait for BT_SDP_COMPLETED done (%dms)", READY_TIMEOUT); + } + log_d("esp_spp_start_discovery done, found %d services", sdpRecords.size()); + xEventGroupClearBits(_bt_event_group, BT_SDP_RUNNING); + return sdpRecords; +} + +/** + * @brief Gets the MAC address of local BT device in byte array. + * + * @param mac [out] The mac + */ +void BluetoothSerial::getBtAddress(uint8_t *mac) { + const uint8_t *dev_mac = esp_bt_dev_get_address(); + memcpy(mac, dev_mac, ESP_BD_ADDR_LEN); +} +/** + * @brief Gets the MAC address of local BT device as BTAddress object. + * + * @return The BTAddress object. + */ +BTAddress BluetoothSerial::getBtAddressObject() { + uint8_t mac_arr[ESP_BD_ADDR_LEN]; + getBtAddress(mac_arr); + return BTAddress(mac_arr); +} +/** + * @brief Gets the MAC address of local BT device as string. + * + * @return The BT MAC address string. + */ +String BluetoothSerial::getBtAddressString() { + return getBtAddressObject().toString(true); +} + +// Send a request to the remote device defined by the remoteAddress to send back its name. +// The name will be read by background task and stored. It can be later read with radRemoteName() +void BluetoothSerial::requestRemoteName(uint8_t remoteAddress[]){ + if(isReady(false, READY_TIMEOUT)){ + esp_bt_gap_read_remote_name(remoteAddress); + } +} + +// If remote name is valid (was already received) this function will copy the name to the aprameter rmt_name +// The buffer must have size at least ESP_BT_GAP_MAX_BDNAME_LEN + 1 +// If the name is valid the function will return true +// If the name is not valid (was not read yet) returns false +bool BluetoothSerial::readRemoteName(char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]){ + if(_rmt_name_valid){ + memcpy(rmt_name, _rmt_name, ESP_BT_GAP_MAX_BDNAME_LEN + 1); + return true; + } + return false; +} + +// Set validity of remote name before reading name from different device +void BluetoothSerial::invalidateRemoteName(){ + _rmt_name_valid = false; +} + +int BluetoothSerial::getNumberOfBondedDevices(){ + return esp_bt_gap_get_bond_device_num(); +} + +// Accepts the maximum number of devices that can fit in given array dev_list. +// Create you list this way: esp_bd_addr_t dev_list[dev_num]; +// Returns number of retrieved devices (on error returns 0) +int BluetoothSerial::getBondedDevices(uint dev_num, esp_bd_addr_t *dev_list){ + // typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN] + if(dev_list == NULL){ + log_e("Device list is NULL"); + return 0; + } + if(dev_num == 0){ + log_e("Device number must be larger than 0!"); + return 0; + } + int _dev_num = dev_num; + esp_bt_gap_get_bond_device_list(&_dev_num, dev_list); + return _dev_num; +} + +bool BluetoothSerial::deleteBondedDevice(uint8_t *remoteAddress){ + esp_err_t ret = esp_bt_gap_remove_bond_device(remoteAddress); + if(ret == ESP_OK){ + return true; + }else{ + return false; + } +} + +void BluetoothSerial::deleteAllBondedDevices(){ + if(!isReady(false, READY_TIMEOUT)){ + log_w("Attempted to drop cache for uninitialized driver. First call begin()"); + return; + } + + int expected_dev_num = esp_bt_gap_get_bond_device_num(); + if(expected_dev_num == 0){ + log_i("No devices in cache."); + return; + } else { + log_d("Found %d bonded devices", expected_dev_num); + } + esp_err_t ret; + + // typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN] // ESP_BD_ADDR_LEN = 6 + esp_bd_addr_t *dev_list = NULL; + log_d("Allocate buffer: sizeof(esp_bd_addr_t)=%d * expected_dev_num=%d", sizeof(esp_bd_addr_t), expected_dev_num); + dev_list = (esp_bd_addr_t*) malloc(sizeof(esp_bd_addr_t) * expected_dev_num); + if(dev_list == NULL){ + log_e("Could not allocated BT device buffer!"); + return; + } + //uint8_t dev_list [20][6]; + + int dev_num; + ret = esp_bt_gap_get_bond_device_list(&dev_num, dev_list); + log_d("esp_bt_gap_get_bond_device_list ret = %d", ret); + if(ret == ESP_OK){ + if(dev_num != expected_dev_num){ + log_w("Inconsistent number of bonded devices. Expected %d; returned %d",expected_dev_num, dev_num); + } + for(int i=0; i +#include +#include +#include +#include "BTScan.h" +#include "BTAdvertisedDevice.h" + + +typedef std::function BluetoothSerialDataCb; +typedef std::function ConfirmRequestCb; +typedef std::function KeyRequestCb; +typedef std::function AuthCompleteCb; +typedef std::function BTAdvertisedDeviceCb; + +class BluetoothSerial: public Stream +{ + public: + + BluetoothSerial(void); + ~BluetoothSerial(void); + + bool begin(String localName=String(), bool isMaster=false); + bool begin(unsigned long baud){//compatibility + return begin(); + } + int available(void); + int peek(void); + bool hasClient(void); + int read(void); + size_t write(uint8_t c); + size_t write(const uint8_t *buffer, size_t size); + void flush(); + void end(void); + void setTimeout(int timeoutMS); + void onData(BluetoothSerialDataCb cb); + esp_err_t register_callback(esp_spp_cb_t * callback); + +#ifdef CONFIG_BT_SSP_ENABLED + void onConfirmRequest(ConfirmRequestCb cb); + void onKeyRequest(KeyRequestCb cb); + void respondPasskey(uint32_t passkey); +#endif + void onAuthComplete(AuthCompleteCb cb); + void confirmReply(boolean confirm); + +#ifdef CONFIG_BT_SSP_ENABLED + void enableSSP(); + void enableSSP(bool inputCapability, bool outputCapability); + void disableSSP(); +#else + bool setPin(const char *pin, uint8_t pin_code_len); +#endif + bool connect(String remoteName); + bool connect(uint8_t remoteAddress[], int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER); + bool connect(const BTAddress &remoteAddress, int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER) { + return connect(*remoteAddress.getNative(), channel, sec_mask); }; + bool connect(); + bool connected(int timeout=0); + bool isClosed(); + bool isReady(bool checkMaster=false, int timeout=0); + bool disconnect(); + bool unpairDevice(uint8_t remoteAddress[]); + + BTScanResults* discover(int timeout=0x30*1280); + bool discoverAsync(BTAdvertisedDeviceCb cb, int timeout=0x30*1280); + void discoverAsyncStop(); + void discoverClear(); + BTScanResults* getScanResults(); + + std::map getChannels(const BTAddress &remoteAddress); + + const int INQ_TIME = 1280; // Inquire Time unit 1280 ms + const int MIN_INQ_TIME = (ESP_BT_GAP_MIN_INQ_LEN * INQ_TIME); + const int MAX_INQ_TIME = (ESP_BT_GAP_MAX_INQ_LEN * INQ_TIME); + + operator bool() const; + void getBtAddress(uint8_t *mac); + BTAddress getBtAddressObject(); + String getBtAddressString(); + //void dropCache(); // To be replaced + void requestRemoteName(uint8_t *remoteAddress); + bool readRemoteName(char rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1]); + void invalidateRemoteName(); + int getNumberOfBondedDevices(); + int getBondedDevices(uint dev_num, esp_bd_addr_t *dev_list); + bool deleteBondedDevice(uint8_t *remoteAddress); + void deleteAllBondedDevices(); + private: + String local_name; + int timeoutTicks=0; +}; + +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/examples/CaptivePortal/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/examples/CaptivePortal/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino new file mode 100644 index 0000000..9221af1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/examples/CaptivePortal/CaptivePortal.ino @@ -0,0 +1,52 @@ +#include +#include + +const byte DNS_PORT = 53; +IPAddress apIP(8,8,4,4); // The default android DNS +DNSServer dnsServer; +WiFiServer server(80); + +String responseHTML = "" + "CaptivePortal" + "

Hello World!

This is a captive portal example. All requests will " + "be redirected here.

"; + +void setup() { + WiFi.mode(WIFI_AP); + WiFi.softAP("ESP32-DNSServer"); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + + // if DNSServer is started with "*" for domain name, it will reply with + // provided IP to all DNS request + dnsServer.start(DNS_PORT, "*", apIP); + + server.begin(); +} + +void loop() { + dnsServer.processNextRequest(); + WiFiClient client = server.available(); // listen for incoming clients + + if (client) { + String currentLine = ""; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + if (c == '\n') { + if (currentLine.length() == 0) { + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + client.print(responseHTML); + break; + } else { + currentLine = ""; + } + } else if (c != '\r') { + currentLine += c; + } + } + } + client.stop(); + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/library.properties new file mode 100644 index 0000000..bbeb7ad --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/library.properties @@ -0,0 +1,9 @@ +name=DNSServer +version=2.0.0 +author=Kristijan Novoselić +maintainer=Kristijan Novoselić, +sentence=A simple DNS server for ESP32. +paragraph=This library implements a simple DNS server. +category=Communication +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/src/DNSServer.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/src/DNSServer.cpp new file mode 100644 index 0000000..aaa3d33 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/src/DNSServer.cpp @@ -0,0 +1,223 @@ +#include "DNSServer.h" +#include +#include + +// #define DEBUG_ESP_DNS +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serial +#endif + +DNSServer::DNSServer() +{ + _ttl = htonl(DNS_DEFAULT_TTL); + _errorReplyCode = DNSReplyCode::NonExistentDomain; + _dnsHeader = (DNSHeader*) malloc( sizeof(DNSHeader) ) ; + _dnsQuestion = (DNSQuestion*) malloc( sizeof(DNSQuestion) ) ; + _buffer = NULL; + _currentPacketSize = 0; + _port = 0; +} + +DNSServer::~DNSServer() +{ + if (_dnsHeader) { + free(_dnsHeader); + _dnsHeader = NULL; + } + if (_dnsQuestion) { + free(_dnsQuestion); + _dnsQuestion = NULL; + } + if (_buffer) { + free(_buffer); + _buffer = NULL; + } +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _buffer = NULL; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); + free(_buffer); + _buffer = NULL; +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + // Allocate buffer for the DNS query + if (_buffer != NULL) + free(_buffer); + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + if (_buffer == NULL) + return; + + // Put the packet received in the buffer and get DNS header (beginning of message) + // and the question + _udp.read(_buffer, _currentPacketSize); + memcpy( _dnsHeader, _buffer, DNS_HEADER_SIZE ) ; + if ( requestIncludesOnlyOneQuestion() ) + { + // The QName has a variable length, maximum 255 bytes and is comprised of multiple labels. + // Each label contains a byte to describe its length and the label itself. The list of + // labels terminates with a zero-valued byte. In "github.com", we have two labels "github" & "com" + // Iterate through the labels and copy them as they come into a single buffer (for simplicity's sake) + _dnsQuestion->QNameLength = 0 ; + while ( _buffer[ DNS_HEADER_SIZE + _dnsQuestion->QNameLength ] != 0 ) + { + memcpy( (void*) &_dnsQuestion->QName[_dnsQuestion->QNameLength], (void*) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength], _buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength] + 1 ) ; + _dnsQuestion->QNameLength += _buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength] + 1 ; + } + _dnsQuestion->QName[_dnsQuestion->QNameLength] = 0 ; + _dnsQuestion->QNameLength++ ; + + // Copy the QType and QClass + memcpy( &_dnsQuestion->QType, (void*) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength], sizeof(_dnsQuestion->QType) ) ; + memcpy( &_dnsQuestion->QClass, (void*) &_buffer[DNS_HEADER_SIZE + _dnsQuestion->QNameLength + sizeof(_dnsQuestion->QType)], sizeof(_dnsQuestion->QClass) ) ; + } + + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + _buffer = NULL; + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + // Error checking : if the buffer containing the DNS request is a null pointer, return an empty domain + String parsedDomainName = ""; + if (_buffer == NULL) + return parsedDomainName; + + // Set the start of the domain just after the header (12 bytes). If equal to null character, return an empty domain + unsigned char *start = _buffer + DNS_OFFSET_DOMAIN_NAME; + if (*start == 0) + { + return parsedDomainName; + } + + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + + // Change the type of message to a response and set the number of answers equal to + // the number of questions in the header + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _udp.write( (unsigned char*) _dnsHeader, DNS_HEADER_SIZE ) ; + + // Write the question + _udp.write(_dnsQuestion->QName, _dnsQuestion->QNameLength) ; + _udp.write( (unsigned char*) &_dnsQuestion->QType, 2 ) ; + _udp.write( (unsigned char*) &_dnsQuestion->QClass, 2 ) ; + + // Write the answer + // Use DNS name compression : instead of repeating the name in this RNAME occurence, + // set the two MSB of the byte corresponding normally to the length to 1. The following + // 14 bits must be used to specify the offset of the domain name in the message + // (<255 here so the first byte has the 6 LSB at 0) + _udp.write((uint8_t) 0xC0); + _udp.write((uint8_t) DNS_OFFSET_DOMAIN_NAME); + + // DNS type A : host address, DNS class IN for INternet, returning an IPv4 address + uint16_t answerType = htons(DNS_TYPE_A), answerClass = htons(DNS_CLASS_IN), answerIPv4 = htons(DNS_RDLENGTH_IPV4) ; + _udp.write((unsigned char*) &answerType, 2 ); + _udp.write((unsigned char*) &answerClass, 2 ); + _udp.write((unsigned char*) &_ttl, 4); // DNS Time To Live + _udp.write((unsigned char*) &answerIPv4, 2 ); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); // The IP address to return + _udp.endPacket(); + + #ifdef DEBUG_ESP_DNS + DEBUG_OUTPUT.printf("DNS responds: %s for %s\n", + IPAddress(_resolvedIP).toString().c_str(), getDomainNameWithoutWwwPrefix().c_str() ); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write((unsigned char*)_dnsHeader, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/src/DNSServer.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/src/DNSServer.h new file mode 100644 index 0000000..1250f5c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/DNSServer/src/DNSServer.h @@ -0,0 +1,110 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 +#define DNS_DEFAULT_TTL 60 // Default Time To Live : time interval in seconds that the resource record should be cached before being discarded +#define DNS_OFFSET_DOMAIN_NAME 12 // Offset in bytes to reach the domain name in the DNS message +#define DNS_HEADER_SIZE 12 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +enum DNSType +{ + DNS_TYPE_A = 1, // Host Address + DNS_TYPE_AAAA = 28, // IPv6 Address + DNS_TYPE_SOA = 6, // Start Of a zone of Authority + DNS_TYPE_PTR = 12, // Domain name PoinTeR + DNS_TYPE_DNAME = 39 // Delegation Name +} ; + +enum DNSClass +{ + DNS_CLASS_IN = 1, // INternet + DNS_CLASS_CH = 3 // CHaos +} ; + +enum DNSRDLength +{ + DNS_RDLENGTH_IPV4 = 4 // 4 bytes for an IPv4 address +} ; + +struct DNSHeader +{ + uint16_t ID; // identification number + union { + struct { + uint16_t RD : 1; // recursion desired + uint16_t TC : 1; // truncated message + uint16_t AA : 1; // authoritive answer + uint16_t OPCode : 4; // message_type + uint16_t QR : 1; // query/response flag + uint16_t RCode : 4; // response code + uint16_t Z : 3; // its z! reserved + uint16_t RA : 1; // recursion available + }; + uint16_t Flags; + }; + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +struct DNSQuestion +{ + uint8_t QName[256] ; //need 1 Byte for zero termination! + uint16_t QNameLength ; + uint16_t QType ; + uint16_t QClass ; +} ; + +class DNSServer +{ + public: + DNSServer(); + ~DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + DNSQuestion* _dnsQuestion ; + + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/README.md new file mode 100644 index 0000000..896ca5b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/README.md @@ -0,0 +1,4 @@ +## EEPROM + +EEPROM is deprecated. For new applications on ESP32, use Preferences. EEPROM is provided for backwards compatibility with existing Arduino applications. +EEPROM is implemented using a single blob within NVS, so it is a container within a container. As such, it is not going to be a high performance storage method. Preferences will directly use nvs, and store each entry as a single object therein. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_class/eeprom_class.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_class/eeprom_class.ino new file mode 100644 index 0000000..5d2961e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_class/eeprom_class.ino @@ -0,0 +1,77 @@ +/* + ESP32 eeprom_class example with EEPROM library + This simple example demonstrates using EEPROM library to store different data in + ESP32 Flash memory in a multiple user-defined EEPROM class objects. + + Created for arduino-esp32 on 25 Dec, 2017 + by Elochukwu Ifediora (fedy0) + converted to nvs by lbernstone - 06/22/2019 +*/ + +#include "EEPROM.h" + +// Instantiate eeprom objects with parameter/argument names and sizes +EEPROMClass NAMES("eeprom0"); +EEPROMClass HEIGHT("eeprom1"); +EEPROMClass AGE("eeprom2"); + +void setup() { + Serial.begin(115200); + delay(1000); + Serial.println("Testing EEPROMClass\n"); + if (!NAMES.begin(0x500)) { + Serial.println("Failed to initialise NAMES"); + Serial.println("Restarting..."); + delay(1000); + ESP.restart(); + } + if (!HEIGHT.begin(0x200)) { + Serial.println("Failed to initialise HEIGHT"); + Serial.println("Restarting..."); + delay(1000); + ESP.restart(); + } + if (!AGE.begin(0x100)) { + Serial.println("Failed to initialise AGE"); + Serial.println("Restarting..."); + delay(1000); + ESP.restart(); + } + + const char* name = "Teo Swee Ann"; + char rname[32]; + double height = 5.8; + uint32_t age = 47; + + // Write: Variables ---> EEPROM stores + NAMES.writeString(0, name); + HEIGHT.put(0, height); + AGE.put(0, age); + Serial.print("name: "); Serial.println(name); + Serial.print("height: "); Serial.println(height); + Serial.print("age: "); Serial.println(age); + Serial.println("------------------------------------\n"); + + // Clear variables + rname[0] = '\0'; + height = 0; + age = 0; + Serial.print("name: "); Serial.println(rname); + Serial.print("height: "); Serial.println(height); + Serial.print("age: "); Serial.println(age); + Serial.println("------------------------------------\n"); + + // Read: Variables <--- EEPROM stores + NAMES.get(0, rname); + HEIGHT.get(0, height); + AGE.get(0, age); + Serial.print("name: "); Serial.println(rname); + Serial.print("height: "); Serial.println(height); + Serial.print("age: "); Serial.println(age); + + Serial.println("Done!"); +} + +void loop() { + delay(0xFFFFFFFF); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_extra/eeprom_extra.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_extra/eeprom_extra.ino new file mode 100644 index 0000000..ba062bc --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_extra/eeprom_extra.ino @@ -0,0 +1,139 @@ +/* + ESP32 eeprom_extra example with EEPROM library + + This simple example demonstrates using other EEPROM library resources + + Created for arduino-esp32 on 25 Dec, 2017 + by Elochukwu Ifediora (fedy0) +*/ + +#include "EEPROM.h" + +void setup() { + // put your setup code here, to run once: + Serial.begin(115200); + Serial.println("\nTesting EEPROM Library\n"); + if (!EEPROM.begin(1000)) { + Serial.println("Failed to initialise EEPROM"); + Serial.println("Restarting..."); + delay(1000); + ESP.restart(); + } + + int address = 0; + + EEPROM.writeByte(address, -128); // -2^7 + address += sizeof(byte); + + EEPROM.writeChar(address, 'A'); // Same as writyByte and readByte + address += sizeof(char); + + EEPROM.writeUChar(address, 255); // 2^8 - 1 + address += sizeof(unsigned char); + + EEPROM.writeShort(address, -32768); // -2^15 + address += sizeof(short); + + EEPROM.writeUShort(address, 65535); // 2^16 - 1 + address += sizeof(unsigned short); + + EEPROM.writeInt(address, -2147483648); // -2^31 + address += sizeof(int); + + EEPROM.writeUInt(address, 4294967295); // 2^32 - 1 + address += sizeof(unsigned int); + + EEPROM.writeLong(address, -2147483648); // Same as writeInt and readInt + address += sizeof(long); + + EEPROM.writeULong(address, 4294967295); // Same as writeUInt and readUInt + address += sizeof(unsigned long); + + int64_t value = -1223372036854775808LL; // -2^63 + EEPROM.writeLong64(address, value); + address += sizeof(int64_t); + + uint64_t Value = 18446744073709551615ULL; // 2^64 - 1 + EEPROM.writeULong64(address, Value); + address += sizeof(uint64_t); + + EEPROM.writeFloat(address, 1234.1234); + address += sizeof(float); + + EEPROM.writeDouble(address, 123456789.123456789); + address += sizeof(double); + + EEPROM.writeBool(address, true); + address += sizeof(bool); + + String sentence = "I love ESP32."; + EEPROM.writeString(address, sentence); + address += sentence.length() + 1; + + char gratitude[21] = "Thank You Espressif!"; + EEPROM.writeString(address, gratitude); + address += 21; + + // See also the general purpose writeBytes() and readBytes() for BLOB in EEPROM library + EEPROM.commit(); + address = 0; + + Serial.println(EEPROM.readByte(address)); + address += sizeof(byte); + + Serial.println((char)EEPROM.readChar(address)); + address += sizeof(char); + + Serial.println(EEPROM.readUChar(address)); + address += sizeof(unsigned char); + + Serial.println(EEPROM.readShort(address)); + address += sizeof(short); + + Serial.println(EEPROM.readUShort(address)); + address += sizeof(unsigned short); + + Serial.println(EEPROM.readInt(address)); + address += sizeof(int); + + Serial.println(EEPROM.readUInt(address)); + address += sizeof(unsigned int); + + Serial.println(EEPROM.readLong(address)); + address += sizeof(long); + + Serial.println(EEPROM.readULong(address)); + address += sizeof(unsigned long); + + value = 0; + value = EEPROM.readLong64(value); + Serial.printf("0x%08lX", (uint32_t)(value >> 32)); // Print High 4 bytes in HEX + Serial.printf("%08lX\n", (uint32_t)value); // Print Low 4 bytes in HEX + address += sizeof(int64_t); + + Value = 0; // Clear Value + Value = EEPROM.readULong64(Value); + Serial.printf("0x%08lX", (uint32_t)(Value >> 32)); // Print High 4 bytes in HEX + Serial.printf("%08lX\n", (uint32_t)Value); // Print Low 4 bytes in HEX + address += sizeof(uint64_t); + + Serial.println(EEPROM.readFloat(address), 4); + address += sizeof(float); + + Serial.println(EEPROM.readDouble(address), 8); + address += sizeof(double); + + Serial.println(EEPROM.readBool(address)); + address += sizeof(bool); + + Serial.println(EEPROM.readString(address)); + address += sentence.length() + 1; + + Serial.println(EEPROM.readString(address)); + address += 21; +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 0000000..a4dbb8c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,63 @@ +/* + EEPROM Write + + Stores random values into the EEPROM. + These values will stay in the EEPROM when the board is + turned off and may be retrieved later by another sketch. +*/ + +#include "EEPROM.h" + +// the current address in the EEPROM (i.e. which byte +// we're going to write to next) +int addr = 0; +#define EEPROM_SIZE 64 +void setup() +{ + Serial.begin(115200); + Serial.println("start..."); + if (!EEPROM.begin(EEPROM_SIZE)) + { + Serial.println("failed to initialise EEPROM"); delay(1000000); + } + Serial.println(" bytes read from Flash . Values are:"); + for (int i = 0; i < EEPROM_SIZE; i++) + { + Serial.print(byte(EEPROM.read(i))); Serial.print(" "); + } + Serial.println(); + Serial.println("writing random n. in memory"); +} + +void loop() +{ + // need to divide by 4 because analog inputs range from + // 0 to 1023 and each byte of the EEPROM can only hold a + // value from 0 to 255. + // int val = analogRead(10) / 4; + int val = byte(random(10020)); + // write the value to the appropriate byte of the EEPROM. + // these values will remain there when the board is + // turned off. + EEPROM.write(addr, val); + Serial.print(val); Serial.print(" "); + // advance to the next address. there are 512 bytes in + // the EEPROM, so go back to 0 when we hit 512. + // save all changes to the flash. + addr = addr + 1; + if (addr == EEPROM_SIZE) + { + Serial.println(); + addr = 0; + EEPROM.commit(); + Serial.print(EEPROM_SIZE); + Serial.println(" bytes written on Flash . Values are:"); + for (int i = 0; i < EEPROM_SIZE; i++) + { + Serial.print(byte(EEPROM.read(i))); Serial.print(" "); + } + Serial.println(); Serial.println("----------------------------------"); + } + + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/keywords.txt new file mode 100644 index 0000000..0e2552e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/keywords.txt @@ -0,0 +1,19 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +EEPROM KEYWORD1 +EEPROMClass KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/library.properties new file mode 100644 index 0000000..459c068 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/library.properties @@ -0,0 +1,9 @@ +name=EEPROM +version=2.0.0 +author=Ivan Grokhotkov +maintainer=Paolo Becchi +sentence=Enables reading and writing data a sequential, addressable FLASH storage +paragraph= +category=Data Storage +url=http://arduino.cc/en/Reference/EEPROM +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/src/EEPROM.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/src/EEPROM.cpp new file mode 100644 index 0000000..356255c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/src/EEPROM.cpp @@ -0,0 +1,558 @@ +/* + EEPROM.h -ported by Paolo Becchi to Esp32 from esp8266 EEPROM + -Modified by Elochukwu Ifediora + -Converted to nvs lbernstone@gmail.com + + Uses a nvs byte array to emulate EEPROM + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "EEPROM.h" +#include +#include +#include + +EEPROMClass::EEPROMClass(void) + : _handle(0) + , _data(0) + , _size(0) + , _dirty(false) + , _name("eeprom") +{ +} + +EEPROMClass::EEPROMClass(uint32_t sector) +// Only for compatiility, no sectors in nvs! + : _handle(0) + , _data(0) + , _size(0) + , _dirty(false) + , _name("eeprom") +{ +} + +EEPROMClass::EEPROMClass(const char* name) + : _handle(0) + , _data(0) + , _size(0) + , _dirty(false) + , _name(name) +{ +} + +EEPROMClass::~EEPROMClass() { + end(); +} + +bool EEPROMClass::begin(size_t size) { + if (!size) { + return false; + } + + esp_err_t res = nvs_open(_name, NVS_READWRITE, &_handle); + if (res != ESP_OK) { + log_e("Unable to open NVS namespace: %d", res); + return false; + } + + size_t key_size = 0; + res = nvs_get_blob(_handle, _name, NULL, &key_size); + if(res != ESP_OK && res != ESP_ERR_NVS_NOT_FOUND) { + log_e("Unable to read NVS key: %d", res); + return false; + } + if (size < key_size) { // truncate + log_w("truncating EEPROM from %d to %d", key_size, size); + uint8_t* key_data = (uint8_t*) malloc(key_size); + if(!key_data) { + log_e("Not enough memory to truncate EEPROM!"); + return false; + } + nvs_get_blob(_handle, _name, key_data, &key_size); + nvs_set_blob(_handle, _name, key_data, size); + nvs_commit(_handle); + free(key_data); + } + else if (size > key_size) { // expand or new + size_t expand_size = size - key_size; + uint8_t* expand_key = (uint8_t*) malloc(expand_size); + if(!expand_key) { + log_e("Not enough memory to expand EEPROM!"); + return false; + } + // check for adequate free space + if(nvs_set_blob(_handle, "expand", expand_key, expand_size)) { + log_e("Not enough space to expand EEPROM from %d to %d", key_size, size); + free(expand_key); + return false; + } + free(expand_key); + nvs_erase_key(_handle, "expand"); + uint8_t* key_data = (uint8_t*) malloc(size); + if(!key_data) { + log_e("Not enough memory to expand EEPROM!"); + return false; + } + memset(key_data, 0xFF, size); + if(key_size) { + log_i("Expanding EEPROM from %d to %d", key_size, size); + // hold data while key is deleted + nvs_get_blob(_handle, _name, key_data, &key_size); + nvs_erase_key(_handle, _name); + } else { + log_i("New EEPROM of %d bytes", size); + } + nvs_commit(_handle); + nvs_set_blob(_handle, _name, key_data, size); + free(key_data); + nvs_commit(_handle); + } + + if (_data) { + delete[] _data; + } + + _data = (uint8_t*) malloc(size); + if(!_data) { + log_e("Not enough memory for %d bytes in EEPROM", size); + return false; + } + _size = size; + nvs_get_blob(_handle, _name, _data, &_size); + return true; +} + +void EEPROMClass::end() { + if (!_size) { + return; + } + + commit(); + if (_data) { + delete[] _data; + } + _data = 0; + _size = 0; + + nvs_close(_handle); + _handle = 0; +} + +uint8_t EEPROMClass::read(int address) { + if (address < 0 || (size_t)address >= _size) { + return 0; + } + if (!_data) { + return 0; + } + + return _data[address]; +} + +void EEPROMClass::write(int address, uint8_t value) { + if (address < 0 || (size_t)address >= _size) + return; + if (!_data) + return; + + // Optimise _dirty. Only flagged if data written is different. + uint8_t* pData = &_data[address]; + if (*pData != value) + { + *pData = value; + _dirty = true; + } +} + +bool EEPROMClass::commit() { + bool ret = false; + if (!_size) { + return false; + } + if (!_data) { + return false; + } + if (!_dirty) { + return true; + } + + esp_err_t err = nvs_set_blob(_handle, _name, _data, _size); + if (err != ESP_OK) { + log_e("error in write: %s", esp_err_to_name(err)); + } else { + _dirty = false; + ret = true; + } + + return ret; +} + +uint8_t * EEPROMClass::getDataPtr() { + _dirty = true; + return &_data[0]; +} + +/* + Get EEPROM total size in byte defined by the user +*/ +uint16_t EEPROMClass::length () +{ + return _size; +} + +/* + Convert EEPROM partition into nvs blob + Call convert before you call begin +*/ +uint16_t EEPROMClass::convert (bool clear, const char* EEPROMname, const char* nvsname) +{ + uint16_t result = 0; + const esp_partition_t* mypart = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, EEPROMname); + if (mypart == NULL) { + log_i("EEPROM partition not found for conversion"); + return result; + } + + size_t size = mypart->size; + uint8_t* data = (uint8_t*) malloc(size); + if (!data) { + log_e("Not enough memory to convert EEPROM!"); + goto exit; + } + + if (esp_partition_read (mypart, 0, (void *) data, size) != ESP_OK) { + log_e("Unable to read EEPROM partition"); + goto exit; + } + + bool empty; + empty = true; + for (int x=0; x _size) + return 0; + + uint16_t len; + for (len = 0; len <= _size; len++) + if (_data[address + len] == 0) + break; + + if (address + len > _size) + return 0; + + if (len > maxLen) + return 0; //Maybe return part of the string instead? + + memcpy((uint8_t*) value, _data + address, len); + value[len] = 0; + return len; +} + +String EEPROMClass::readString (int address) +{ + if (address < 0 || address > _size) + return String(); + + uint16_t len; + for (len = 0; len <= _size; len++) + if (_data[address + len] == 0) + break; + + if (address + len > _size) + return String(); + + char value[len+1]; + memcpy((uint8_t*) value, _data + address, len); + value[len] = 0; + return String(value); +} + +size_t EEPROMClass::readBytes (int address, void* value, size_t maxLen) +{ + if (!value || !maxLen) + return 0; + + if (address < 0 || address + maxLen > _size) + return 0; + + memcpy((void*) value, _data + address, maxLen); + return maxLen; +} + +template T EEPROMClass::readAll (int address, T &value) +{ + if (address < 0 || address + sizeof(T) > _size) + return value; + + memcpy((uint8_t*) &value, _data + address, sizeof(T)); + return value; +} + +/* + Write 'value' to 'address' +*/ +size_t EEPROMClass::writeByte (int address, uint8_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeChar (int address, int8_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeUChar (int address, uint8_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeShort (int address, int16_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeUShort (int address, uint16_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeInt (int address, int32_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeUInt (int address, uint32_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeLong (int address, int32_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeULong (int address, uint32_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeLong64 (int address, int64_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeULong64 (int address, uint64_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeFloat (int address, float_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeDouble (int address, double_t value) +{ + return EEPROMClass::writeAll (address, value); +} + +size_t EEPROMClass::writeBool (int address, bool value) +{ + int8_t Bool; + value ? Bool = 1 : Bool = 0; + return EEPROMClass::writeAll (address, Bool); +} + +size_t EEPROMClass::writeString (int address, const char* value) +{ + if (!value) + return 0; + + if (address < 0 || address > _size) + return 0; + + uint16_t len; + for (len = 0; len <= _size; len++) + if (value[len] == 0) + break; + + if (address + len > _size) + return 0; + + memcpy(_data + address, (const uint8_t*) value, len + 1); + _dirty = true; + return strlen(value); +} + +size_t EEPROMClass::writeString (int address, String value) +{ + return EEPROMClass::writeString (address, value.c_str()); +} + +size_t EEPROMClass::writeBytes (int address, const void* value, size_t len) +{ + if (!value || !len) + return 0; + + if (address < 0 || address + len > _size) + return 0; + + memcpy(_data + address, (const void*) value, len); + _dirty = true; + return len; +} + +template T EEPROMClass::writeAll (int address, const T &value) +{ + if (address < 0 || address + sizeof(T) > _size) + return value; + + memcpy(_data + address, (const uint8_t*) &value, sizeof(T)); + _dirty = true; + + return sizeof (value); +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) +EEPROMClass EEPROM; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/src/EEPROM.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/src/EEPROM.h new file mode 100644 index 0000000..b4e849f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/EEPROM/src/EEPROM.h @@ -0,0 +1,121 @@ +/* + EEPROM.h -ported by Paolo Becchi to Esp32 from esp8266 EEPROM + -Modified by Elochukwu Ifediora + -Converted to nvs lbernstone@gmail.com + + Uses a nvs byte array to emulate EEPROM + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h +#ifndef EEPROM_FLASH_PARTITION_NAME +#define EEPROM_FLASH_PARTITION_NAME "eeprom" +#endif +#include + +typedef uint32_t nvs_handle; + +class EEPROMClass { + public: + EEPROMClass(uint32_t sector); + EEPROMClass(const char* name); + EEPROMClass(void); + ~EEPROMClass(void); + + bool begin(size_t size); + uint8_t read(int address); + void write(int address, uint8_t val); + uint16_t length(); + bool commit(); + void end(); + + uint8_t * getDataPtr(); + uint16_t convert(bool clear, const char* EEPROMname = "eeprom", const char* nvsname = "eeprom"); + + template + T &get(int address, T &t) { + if (address < 0 || address + sizeof(T) > _size) + return t; + + memcpy((uint8_t*) &t, _data + address, sizeof(T)); + return t; + } + + template + const T &put(int address, const T &t) { + if (address < 0 || address + sizeof(T) > _size) + return t; + + memcpy(_data + address, (const uint8_t*) &t, sizeof(T)); + _dirty = true; + return t; + } + + uint8_t readByte(int address); + int8_t readChar(int address); + uint8_t readUChar(int address); + int16_t readShort(int address); + uint16_t readUShort(int address); + int32_t readInt(int address); + uint32_t readUInt(int address); + int32_t readLong(int address); + uint32_t readULong(int address); + int64_t readLong64(int address); + uint64_t readULong64(int address); + float_t readFloat(int address); + double_t readDouble(int address); + bool readBool(int address); + size_t readString(int address, char* value, size_t maxLen); + String readString(int address); + size_t readBytes(int address, void * value, size_t maxLen); + template T readAll (int address, T &); + + size_t writeByte(int address, uint8_t value); + size_t writeChar(int address, int8_t value); + size_t writeUChar(int address, uint8_t value); + size_t writeShort(int address, int16_t value); + size_t writeUShort(int address, uint16_t value); + size_t writeInt(int address, int32_t value); + size_t writeUInt(int address, uint32_t value); + size_t writeLong(int address, int32_t value); + size_t writeULong(int address, uint32_t value); + size_t writeLong64(int address, int64_t value); + size_t writeULong64(int address, uint64_t value); + size_t writeFloat(int address, float_t value); + size_t writeDouble(int address, double_t value); + size_t writeBool(int address, bool value); + size_t writeString(int address, const char* value); + size_t writeString(int address, String value); + size_t writeBytes(int address, const void* value, size_t len); + template T writeAll (int address, const T &); + + protected: + nvs_handle _handle; + uint8_t* _data; + size_t _size; + bool _dirty; + const char* _name; +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM) +extern EEPROMClass EEPROM; +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino new file mode 100644 index 0000000..002df74 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/LEDCFade/LEDCFade.ino @@ -0,0 +1,69 @@ +/* LEDC Fade Arduino Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +// use 12 bit precission for LEDC timer +#define LEDC_TIMER_12_BIT 12 + +// use 5000 Hz as a LEDC base frequency +#define LEDC_BASE_FREQ 5000 + +// fade LED PIN (replace with LED_BUILTIN constant for built-in LED) +#define LED_PIN 4 + +// define starting duty, target duty and maximum fade time +#define LEDC_START_DUTY (0) +#define LEDC_TARGET_DUTY (4095) +#define LEDC_FADE_TIME (3000) + +bool fade_ended = false; // status of LED fade +bool fade_on = true; + +void ARDUINO_ISR_ATTR LED_FADE_ISR() +{ + fade_ended = true; +} + +void setup() { + // Initialize serial communication at 115200 bits per second: + Serial.begin(115200); + while(!Serial) delay(10); + + // Setup timer and attach timer to a led pins + ledcAttach(LED_PIN, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT); + + // Setup and start fade on led (duty from 0 to 4095) + ledcFade(LED_PIN, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME); + Serial.println("LED Fade on started."); + + // Wait for fade to end + delay(LEDC_FADE_TIME); + + // Setup and start fade off led and use ISR (duty from 4095 to 0) + ledcFadeWithInterrupt(LED_PIN, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR); + Serial.println("LED Fade off started."); +} + +void loop() { + // Check if fade_ended flag was set to true in ISR + if(fade_ended){ + Serial.println("LED fade ended"); + fade_ended = false; + + // Check if last fade was fade on + if(fade_on){ + ledcFadeWithInterrupt(LED_PIN, LEDC_START_DUTY, LEDC_TARGET_DUTY, LEDC_FADE_TIME, LED_FADE_ISR); + Serial.println("LED Fade off started."); + fade_on = false; + } + else { + ledcFadeWithInterrupt(LED_PIN, LEDC_TARGET_DUTY, LEDC_START_DUTY, LEDC_FADE_TIME, LED_FADE_ISR); + Serial.println("LED Fade on started."); + fade_on = true; + } + } +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino new file mode 100644 index 0000000..239e37f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/LEDCSoftwareFade/LEDCSoftwareFade.ino @@ -0,0 +1,53 @@ +/* + LEDC Software Fade + + This example shows how to software fade LED + using the ledcWrite function. + + Code adapted from original Arduino Fade example: + https://www.arduino.cc/en/Tutorial/Fade + + This example code is in the public domain. + */ + +// use 12 bit precission for LEDC timer +#define LEDC_TIMER_12_BIT 12 + +// use 5000 Hz as a LEDC base frequency +#define LEDC_BASE_FREQ 5000 + +// fade LED PIN (replace with LED_BUILTIN constant for built-in LED) +#define LED_PIN 5 + +int brightness = 0; // how bright the LED is +int fadeAmount = 5; // how many points to fade the LED by + +// Arduino like analogWrite +// value has to be between 0 and valueMax +void ledcAnalogWrite(uint8_t pin, uint32_t value, uint32_t valueMax = 255) { + // calculate duty, 4095 from 2 ^ 12 - 1 + uint32_t duty = (4095 / valueMax) * min(value, valueMax); + + // write duty to LEDC + ledcWrite(pin, duty); +} + +void setup() { + // Setup timer and attach timer to a led pin + ledcAttach(LED_PIN, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT); +} + +void loop() { + // set the brightness on LEDC channel 0 + ledcAnalogWrite(LED_PIN, brightness); + + // change the brightness for next time through the loop: + brightness = brightness + fadeAmount; + + // reverse the direction of the fading at the ends of the fade: + if (brightness <= 0 || brightness >= 255) { + fadeAmount = -fadeAmount; + } + // wait for 30 milliseconds to see the dimming effect + delay(30); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/SigmaDelta/SigmaDelta.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/SigmaDelta/SigmaDelta.ino new file mode 100644 index 0000000..261263f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/SigmaDelta/SigmaDelta.ino @@ -0,0 +1,16 @@ +void setup() +{ + //setup on pin 18 with frequency 312500 Hz + sigmaDeltaAttach(18, 312500); + //set pin 18 to off + sigmaDeltaWrite(18, 0); +} + +void loop() +{ + //slowly ramp-up the value + //will overflow at 256 + static uint8_t i = 0; + sigmaDeltaWrite(18, i++); + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/ledcFrequency/ledcFrequency.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/ledcFrequency/ledcFrequency.ino new file mode 100644 index 0000000..772e5da --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/ledcFrequency/ledcFrequency.ino @@ -0,0 +1,79 @@ +/* + * This sketch will map the maximum frequency depending on the bit resolution for the current SoC. + * Run the sketch and wait for the Final report. + * Ignore the error messages from incorrect settings such as these: + * "E (4190) ledc: requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=255" + * + * Date: 11 Nov 2022 + * Author: Tomas Pilny + */ + +#include "soc/soc_caps.h" +#include + +#define PIN 2 + +void setup() { + ledcAttach(PIN,1000,8); + + uint32_t min_frequency; + uint32_t max_frequency; + uint32_t frequency; + uint32_t successful_frequency; + uint32_t max_freq_array[SOC_LEDC_TIMER_BIT_WIDTH]; + uint32_t min_freq_array[SOC_LEDC_TIMER_BIT_WIDTH]; + + // Find Max Frequency + for(uint8_t resolution = 1; resolution <= SOC_LEDC_TIMER_BIT_WIDTH; ++resolution){ + max_freq_array[resolution-1] = 0; + min_frequency = 0; + max_frequency = UINT32_MAX; + successful_frequency = 0; + while(min_frequency != max_frequency && min_frequency+1 != max_frequency){ + frequency = min_frequency + ((max_frequency-min_frequency)/2); + if(ledcChangeFrequency(PIN, frequency, resolution)){ + min_frequency = frequency; + successful_frequency = frequency; + }else{ + max_frequency = frequency; + } + } // while not found the maximum + max_freq_array[resolution-1] = successful_frequency; + } // for all resolutions + + // Find Min Frequency + for(uint8_t resolution = 1; resolution <= SOC_LEDC_TIMER_BIT_WIDTH; ++resolution){ + min_freq_array[resolution-1] = 0; + min_frequency = 0; + max_frequency = max_freq_array[resolution-1]; + successful_frequency = max_frequency; + while(min_frequency != max_frequency && min_frequency+1 != max_frequency){ + frequency = min_frequency + ((max_frequency-min_frequency)/2); + if(ledcChangeFrequency(PIN, frequency, resolution)){ + max_frequency = frequency; + successful_frequency = frequency; + }else{ + min_frequency = frequency; + } + } // while not found the maximum + min_freq_array[resolution-1] = successful_frequency; + } // for all resolutions + + printf("Bit resolution | Min Frequency [Hz] | Max Frequency [Hz]\n"); + for(uint8_t r = 1; r <= SOC_LEDC_TIMER_BIT_WIDTH; ++r){ + size_t max_len = std::to_string(UINT32_MAX).length(); + printf(" %s%d | %s%lu | %s%lu\n", + std::string (2 - std::to_string(r).length(), ' ').c_str(), r, + std::string (max_len - std::to_string(min_freq_array[r-1]).length(), ' ').c_str(), + min_freq_array[r-1], + std::string (max_len - std::to_string(max_freq_array[r-1]).length(), ' ').c_str(), + max_freq_array[r-1]); + } + + ledcDetach(PIN); +} + +void loop() +{ + delay(1000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino new file mode 100644 index 0000000..1104a6b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogOut/ledcWrite_RGB/ledcWrite_RGB.ino @@ -0,0 +1,123 @@ +/* + ledcWrite_RGB.ino + Runs through the full 255 color spectrum for an rgb led + Demonstrate ledcWrite functionality for driving leds with PWM on ESP32 + + This example code is in the public domain. + + Some basic modifications were made by vseven, mostly commenting. + */ + +// Set up the rgb led names +uint8_t ledR = 0; +uint8_t ledG = 2; +uint8_t ledB = 4; + +const boolean invert = true; // set true if common anode, false if common cathode + +uint8_t color = 0; // a value from 0 to 255 representing the hue +uint32_t R, G, B; // the Red Green and Blue color components +uint8_t brightness = 255; // 255 is maximum brightness, but can be changed. Might need 256 for common anode to fully turn off. + +// the setup routine runs once when you press reset: +void setup() +{ + Serial.begin(115200); + delay(10); + + // Initialize pins as LEDC channels + // resolution 1-16 bits, freq limits depend on resolution + ledcAttach(ledR, 12000, 8); // 12 kHz PWM, 8-bit resolution + ledcAttach(ledG, 12000, 8); + ledcAttach(ledB, 12000, 8); +} + +// void loop runs over and over again +void loop() +{ + Serial.println("Send all LEDs a 255 and wait 2 seconds."); + // If your RGB LED turns off instead of on here you should check if the LED is common anode or cathode. + // If it doesn't fully turn off and is common anode try using 256. + ledcWrite(ledR, 255); + ledcWrite(ledG, 255); + ledcWrite(ledB, 255); + delay(2000); + Serial.println("Send all LEDs a 0 and wait 2 seconds."); + ledcWrite(ledR, 0); + ledcWrite(ledG, 0); + ledcWrite(ledB, 0); + delay(2000); + + Serial.println("Starting color fade loop."); + + for (color = 0; color < 255; color++) { // Slew through the color spectrum + + hueToRGB(color, brightness); // call function to convert hue to RGB + + // write the RGB values to the pins + ledcWrite(ledR, R); // write red component to channel 1, etc. + ledcWrite(ledG, G); + ledcWrite(ledB, B); + + delay(100); // full cycle of rgb over 256 colors takes 26 seconds + } + +} + +// Courtesy http://www.instructables.com/id/How-to-Use-an-RGB-LED/?ALLSTEPS +// function to convert a color to its Red, Green, and Blue components. + +void hueToRGB(uint8_t hue, uint8_t brightness) +{ + uint16_t scaledHue = (hue * 6); + uint8_t segment = scaledHue / 256; // segment 0 to 5 around the + // color wheel + uint16_t segmentOffset = + scaledHue - (segment * 256); // position within the segment + + uint8_t complement = 0; + uint16_t prev = (brightness * ( 255 - segmentOffset)) / 256; + uint16_t next = (brightness * segmentOffset) / 256; + + if(invert) + { + brightness = 255 - brightness; + complement = 255; + prev = 255 - prev; + next = 255 - next; + } + + switch(segment ) { + case 0: // red + R = brightness; + G = next; + B = complement; + break; + case 1: // yellow + R = prev; + G = brightness; + B = complement; + break; + case 2: // green + R = complement; + G = brightness; + B = next; + break; + case 3: // cyan + R = complement; + G = prev; + B = brightness; + break; + case 4: // blue + R = next; + G = complement; + B = brightness; + break; + case 5: // magenta + default: + R = brightness; + G = complement; + B = prev; + break; + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogRead/AnalogRead.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogRead/AnalogRead.ino new file mode 100644 index 0000000..c238517 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogRead/AnalogRead.ino @@ -0,0 +1,19 @@ +void setup() { + // initialize serial communication at 115200 bits per second: + Serial.begin(115200); + + //set the resolution to 12 bits (0-4096) + analogReadResolution(12); +} + +void loop() { + // read the analog / millivolts value for pin 2: + int analogValue = analogRead(2); + int analogVolts = analogReadMilliVolts(2); + + // print out the values you read: + Serial.printf("ADC analog value = %d\n",analogValue); + Serial.printf("ADC millivolts value = %d\n",analogVolts); + + delay(100); // delay in between reads for clear read from serial +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino new file mode 100644 index 0000000..c092831 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/AnalogReadContinuous/AnalogReadContinuous.ino @@ -0,0 +1,71 @@ +// Define how many conversion per pin will happen and reading the data will be and average of all conversions +#define CONVERSIONS_PER_PIN 5 + +// Declare array of ADC pins that will be used for ADC Continuous mode - ONLY ADC1 pins are supported +// Number of selected pins can be from 1 to ALL ADC1 pins. +#ifdef CONFIG_IDF_TARGET_ESP32 +uint8_t adc_pins[] = {36, 39, 34, 35}; //some of ADC1 pins for ESP32 +#else +uint8_t adc_pins[] = {1, 2, 3, 4}; //ADC1 common pins for ESP32S2/S3 + ESP32C3/C6 + ESP32H2 +#endif + +// Calculate how many pins are declared in the array - needed as input for the setup function of ADC Continuous +uint8_t adc_pins_count = sizeof(adc_pins) / sizeof(uint8_t); + +// Flag which will be set in ISR when conversion is done +volatile bool adc_coversion_done = false; + +// Result structure for ADC Continuous reading +adc_continuos_data_t * result = NULL; + +// ISR Function that will be triggered when ADC conversion is done +void ARDUINO_ISR_ATTR adcComplete() { + adc_coversion_done = true; +} + +void setup() { + // Initialize serial communication at 115200 bits per second: + Serial.begin(115200); + + // Optional for ESP32: Set the resolution to 9-12 bits (default is 12 bits) + analogContinuousSetWidth(12); + + // Optional: Set different attenaution (default is ADC_11db) + analogContinuousSetAtten(ADC_11db); + + // Setup ADC Continuous with following input: + // array of pins, count of the pins, how many conversions per pin in one cycle will happen, sampling frequency, callback function + analogContinuous(adc_pins, adc_pins_count, CONVERSIONS_PER_PIN, 20000, &adcComplete); + + // Start ADC Continuous conversions + analogContinuousStart(); +} + +void loop() { + // Check if conversion is done and try to read data + if (adc_coversion_done == true) { + // Set ISR flag back to false + adc_coversion_done = false; + // Read data from ADC + if (analogContinuousRead(&result, 0)) { + + // Optional: Stop ADC Continuous conversions to have more time to process (print) the data + analogContinuousStop(); + + for (int i = 0; i < adc_pins_count; i++) { + Serial.printf("\nADC PIN %d data:", result[i].pin); + Serial.printf("\n Avg raw value = %d", result[i].avg_read_raw); + Serial.printf("\n Avg milivolts value = %d", result[i].avg_read_mvolts); + } + + // Delay for better readability of ADC data + delay(1000); + + // Optional: If ADC was stopped, start ADC conversions and wait for callback function to set adc_coversion_done flag to true + analogContinuousStart(); + } + else { + Serial.println("Error occured during reading data. Set Core Debug Level to error or lower for more informations."); + } + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ArduinoStackSize/ArduinoStackSize.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ArduinoStackSize/ArduinoStackSize.ino new file mode 100644 index 0000000..73c4202 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ArduinoStackSize/ArduinoStackSize.ino @@ -0,0 +1,36 @@ +/* + ESP32 Arduino creates a task to run setup() and then to execute loop() continuously + This task can be found at https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/main.cpp + + By default "loopTask" will be created with a stack size of 8KB. + This should be plenty for most general sketches. + + There is a way to change the stack size of this task by using + SET_LOOP_TASK_STACK_SIZE(size); + It will bypass the default stack size of 8KB and allow the user to define a new size. + + It is recommend this value to be higher than 8KB, for instance 16KB. + This increasing may be necessary for the sketches that use deep recursion for instance. + + In this example, you can verify it by changing or just commenting out SET_LOOP_TASK_STACK_SIZE(); +*/ + + +// This sets Arduino Stack Size - comment this line to use default 8K stack size +SET_LOOP_TASK_STACK_SIZE(16*1024); // 16KB + +void setup() { + Serial.begin(115200); + + Serial.printf("Arduino Stack was set to %d bytes", getArduinoLoopTaskStackSize()); + + // Print unused stack for the task that is running setup() + Serial.printf("\nSetup() - Free Stack Space: %d", uxTaskGetStackHighWaterMark(NULL)); +} + +void loop() { + delay(1000); + + // Print unused stack for the task that is running loop() - the same as for setup() + Serial.printf("\nLoop() - Free Stack Space: %d", uxTaskGetStackHighWaterMark(NULL)); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino new file mode 100644 index 0000000..6b2faa8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/CI/CIBoardsTest/CIBoardsTest.ino @@ -0,0 +1,45 @@ +#include +#include + +void setup() { + // UART initialization + Serial.begin(9600); + + // I2C initialization + Wire.begin(); + + // SPI initialization + SPI.begin(); +} + +void loop() { + // UART echo + if (Serial.available()) { + Serial.write(Serial.read()); + } + + // I2C read/write + Wire.beginTransmission(0x68); // I2C address of device + Wire.write(0x00); // register to read/write + Wire.write(0xFF); // data to write (if writing) + Wire.endTransmission(); + + Wire.requestFrom(0x68, 1); // number of bytes to read + + while (Wire.available()) { + Serial.println(Wire.read()); + } + + // SPI read/write + digitalWrite(SS, LOW); // select slave device + SPI.transfer(0x01); // data to write + digitalWrite(SS, HIGH); // deselect slave device + + digitalWrite(SS, LOW); // select slave device + byte data = SPI.transfer(0x00);// data to read + digitalWrite(SS, HIGH); // deselect slave device + + Serial.println(data); + + delay(1000); // wait for 1 second before repeating loop +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino new file mode 100644 index 0000000..354ae68 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino @@ -0,0 +1,155 @@ +#include "esp_camera.h" +#include + +// +// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality +// Ensure ESP32 Wrover Module or other board with PSRAM is selected +// Partial images will be transmitted if image exceeds buffer size +// +// You must select partition scheme from the board menu that has at least 3MB APP space. +// Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15 +// seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well + +// =================== +// Select camera model +// =================== +//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM +#define CAMERA_MODEL_ESP_EYE // Has PSRAM +//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM +//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM +//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM +//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM +//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM +//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM +//#define CAMERA_MODEL_AI_THINKER // Has PSRAM +//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM +//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM +// ** Espressif Internal Boards ** +//#define CAMERA_MODEL_ESP32_CAM_BOARD +//#define CAMERA_MODEL_ESP32S2_CAM_BOARD +//#define CAMERA_MODEL_ESP32S3_CAM_LCD +//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM +//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM +#include "camera_pins.h" + +// =========================== +// Enter your WiFi credentials +// =========================== +const char* ssid = "**********"; +const char* password = "**********"; + +void startCameraServer(); +void setupLedFlash(int pin); + +void setup() { + Serial.begin(115200); + Serial.setDebugOutput(true); + Serial.println(); + + camera_config_t config; + config.ledc_channel = LEDC_CHANNEL_0; + config.ledc_timer = LEDC_TIMER_0; + config.pin_d0 = Y2_GPIO_NUM; + config.pin_d1 = Y3_GPIO_NUM; + config.pin_d2 = Y4_GPIO_NUM; + config.pin_d3 = Y5_GPIO_NUM; + config.pin_d4 = Y6_GPIO_NUM; + config.pin_d5 = Y7_GPIO_NUM; + config.pin_d6 = Y8_GPIO_NUM; + config.pin_d7 = Y9_GPIO_NUM; + config.pin_xclk = XCLK_GPIO_NUM; + config.pin_pclk = PCLK_GPIO_NUM; + config.pin_vsync = VSYNC_GPIO_NUM; + config.pin_href = HREF_GPIO_NUM; + config.pin_sccb_sda = SIOD_GPIO_NUM; + config.pin_sccb_scl = SIOC_GPIO_NUM; + config.pin_pwdn = PWDN_GPIO_NUM; + config.pin_reset = RESET_GPIO_NUM; + config.xclk_freq_hz = 20000000; + config.frame_size = FRAMESIZE_UXGA; + config.pixel_format = PIXFORMAT_JPEG; // for streaming + //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition + config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; + config.fb_location = CAMERA_FB_IN_PSRAM; + config.jpeg_quality = 12; + config.fb_count = 1; + + // if PSRAM IC present, init with UXGA resolution and higher JPEG quality + // for larger pre-allocated frame buffer. + if(config.pixel_format == PIXFORMAT_JPEG){ + if(psramFound()){ + config.jpeg_quality = 10; + config.fb_count = 2; + config.grab_mode = CAMERA_GRAB_LATEST; + } else { + // Limit the frame size when PSRAM is not available + config.frame_size = FRAMESIZE_SVGA; + config.fb_location = CAMERA_FB_IN_DRAM; + } + } else { + // Best option for face detection/recognition + config.frame_size = FRAMESIZE_240X240; +#if CONFIG_IDF_TARGET_ESP32S3 + config.fb_count = 2; +#endif + } + +#if defined(CAMERA_MODEL_ESP_EYE) + pinMode(13, INPUT_PULLUP); + pinMode(14, INPUT_PULLUP); +#endif + + // camera init + esp_err_t err = esp_camera_init(&config); + if (err != ESP_OK) { + Serial.printf("Camera init failed with error 0x%x", err); + return; + } + + sensor_t * s = esp_camera_sensor_get(); + // initial sensors are flipped vertically and colors are a bit saturated + if (s->id.PID == OV3660_PID) { + s->set_vflip(s, 1); // flip it back + s->set_brightness(s, 1); // up the brightness just a bit + s->set_saturation(s, -2); // lower the saturation + } + // drop down frame size for higher initial frame rate + if(config.pixel_format == PIXFORMAT_JPEG){ + s->set_framesize(s, FRAMESIZE_QVGA); + } + +#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM) + s->set_vflip(s, 1); + s->set_hmirror(s, 1); +#endif + +#if defined(CAMERA_MODEL_ESP32S3_EYE) + s->set_vflip(s, 1); +#endif + +// Setup LED FLash if LED pin is defined in camera_pins.h +#if defined(LED_GPIO_NUM) + setupLedFlash(LED_GPIO_NUM); +#endif + + WiFi.begin(ssid, password); + WiFi.setSleep(false); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + + startCameraServer(); + + Serial.print("Camera Ready! Use 'http://"); + Serial.print(WiFi.localIP()); + Serial.println("' to connect"); +} + +void loop() { + // Do nothing. Everything is done in another task by the web server + delay(10000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp new file mode 100644 index 0000000..ff02152 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/app_httpd.cpp @@ -0,0 +1,1397 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "esp_http_server.h" +#include "esp_timer.h" +#include "esp_camera.h" +#include "img_converters.h" +#include "fb_gfx.h" +#include "esp32-hal-ledc.h" +#include "sdkconfig.h" +#include "camera_index.h" + +#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) +#include "esp32-hal-log.h" +#endif + +// Face Detection will not work on boards without (or with disabled) PSRAM +#ifdef BOARD_HAS_PSRAM +#define CONFIG_ESP_FACE_DETECT_ENABLED 1 +// Face Recognition takes upward from 15 seconds per frame on chips other than ESP32S3 +// Makes no sense to have it enabled for them +#if CONFIG_IDF_TARGET_ESP32S3 +#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 1 +#else +#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0 +#endif +#else +#define CONFIG_ESP_FACE_DETECT_ENABLED 0 +#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0 +#endif + +#if CONFIG_ESP_FACE_DETECT_ENABLED + +#include +#include "human_face_detect_msr01.hpp" +#include "human_face_detect_mnp01.hpp" + +#define TWO_STAGE 1 /* very large firmware, very slow, reboots when streaming... + +#define FACE_ID_SAVE_NUMBER 7 +#endif + +#define FACE_COLOR_WHITE 0x00FFFFFF +#define FACE_COLOR_BLACK 0x00000000 +#define FACE_COLOR_RED 0x000000FF +#define FACE_COLOR_GREEN 0x0000FF00 +#define FACE_COLOR_BLUE 0x00FF0000 +#define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN) +#define FACE_COLOR_CYAN (FACE_COLOR_BLUE | FACE_COLOR_GREEN) +#define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED) +#endif + +// Enable LED FLASH setting +#define CONFIG_LED_ILLUMINATOR_ENABLED 1 + +// LED FLASH setup +#if CONFIG_LED_ILLUMINATOR_ENABLED + +#define LED_LEDC_GPIO 22 //configure LED pin +#define CONFIG_LED_MAX_INTENSITY 255 + +int led_duty = 0; +bool isStreaming = false; + +#endif + +typedef struct +{ + httpd_req_t *req; + size_t len; +} jpg_chunking_t; + +#define PART_BOUNDARY "123456789000000000000987654321" +static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; +static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; +static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %d.%06d\r\n\r\n"; + +httpd_handle_t stream_httpd = NULL; +httpd_handle_t camera_httpd = NULL; + +#if CONFIG_ESP_FACE_DETECT_ENABLED + +static int8_t detection_enabled = 0; + +// #if TWO_STAGE +// static HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); +// static HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); +// #else +// static HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); +// #endif + +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED +static int8_t recognition_enabled = 0; +static int8_t is_enrolling = 0; + +#if QUANT_TYPE + // S16 model + FaceRecognition112V1S16 recognizer; +#else + // S8 model + FaceRecognition112V1S8 recognizer; +#endif +#endif + +#endif + +typedef struct +{ + size_t size; //number of values used for filtering + size_t index; //current value index + size_t count; //value count + int sum; + int *values; //array to be filled with values +} ra_filter_t; + +static ra_filter_t ra_filter; + +static ra_filter_t *ra_filter_init(ra_filter_t *filter, size_t sample_size) +{ + memset(filter, 0, sizeof(ra_filter_t)); + + filter->values = (int *)malloc(sample_size * sizeof(int)); + if (!filter->values) + { + return NULL; + } + memset(filter->values, 0, sample_size * sizeof(int)); + + filter->size = sample_size; + return filter; +} + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO +static int ra_filter_run(ra_filter_t *filter, int value) +{ + if (!filter->values) + { + return value; + } + filter->sum -= filter->values[filter->index]; + filter->values[filter->index] = value; + filter->sum += filter->values[filter->index]; + filter->index++; + filter->index = filter->index % filter->size; + if (filter->count < filter->size) + { + filter->count++; + } + return filter->sum / filter->count; +} +#endif + +#if CONFIG_ESP_FACE_DETECT_ENABLED +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED +static void rgb_print(fb_data_t *fb, uint32_t color, const char *str) +{ + fb_gfx_print(fb, (fb->width - (strlen(str) * 14)) / 2, 10, color, str); +} + +static int rgb_printf(fb_data_t *fb, uint32_t color, const char *format, ...) +{ + char loc_buf[64]; + char *temp = loc_buf; + int len; + va_list arg; + va_list copy; + va_start(arg, format); + va_copy(copy, arg); + len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg); + va_end(copy); + if (len >= sizeof(loc_buf)) + { + temp = (char *)malloc(len + 1); + if (temp == NULL) + { + return 0; + } + } + vsnprintf(temp, len + 1, format, arg); + va_end(arg); + rgb_print(fb, color, temp); + if (len > 64) + { + free(temp); + } + return len; +} +#endif +static void draw_face_boxes(fb_data_t *fb, std::list *results, int face_id) +{ + int x, y, w, h; + uint32_t color = FACE_COLOR_YELLOW; + if (face_id < 0) + { + color = FACE_COLOR_RED; + } + else if (face_id > 0) + { + color = FACE_COLOR_GREEN; + } + if(fb->bytes_per_pixel == 2){ + //color = ((color >> 8) & 0xF800) | ((color >> 3) & 0x07E0) | (color & 0x001F); + color = ((color >> 16) & 0x001F) | ((color >> 3) & 0x07E0) | ((color << 8) & 0xF800); + } + int i = 0; + for (std::list::iterator prediction = results->begin(); prediction != results->end(); prediction++, i++) + { + // rectangle box + x = (int)prediction->box[0]; + y = (int)prediction->box[1]; + w = (int)prediction->box[2] - x + 1; + h = (int)prediction->box[3] - y + 1; + if((x + w) > fb->width){ + w = fb->width - x; + } + if((y + h) > fb->height){ + h = fb->height - y; + } + fb_gfx_drawFastHLine(fb, x, y, w, color); + fb_gfx_drawFastHLine(fb, x, y + h - 1, w, color); + fb_gfx_drawFastVLine(fb, x, y, h, color); + fb_gfx_drawFastVLine(fb, x + w - 1, y, h, color); +#if TWO_STAGE + // landmarks (left eye, mouth left, nose, right eye, mouth right) + int x0, y0, j; + for (j = 0; j < 10; j+=2) { + x0 = (int)prediction->keypoint[j]; + y0 = (int)prediction->keypoint[j+1]; + fb_gfx_fillRect(fb, x0, y0, 3, 3, color); + } +#endif + } +} + +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED +static int run_face_recognition(fb_data_t *fb, std::list *results) +{ + std::vector landmarks = results->front().keypoint; + int id = -1; + + Tensor tensor; + tensor.set_element((uint8_t *)fb->data).set_shape({fb->height, fb->width, 3}).set_auto_free(false); + + int enrolled_count = recognizer.get_enrolled_id_num(); + + if (enrolled_count < FACE_ID_SAVE_NUMBER && is_enrolling){ + id = recognizer.enroll_id(tensor, landmarks, "", true); + log_i("Enrolled ID: %d", id); + rgb_printf(fb, FACE_COLOR_CYAN, "ID[%u]", id); + } + + face_info_t recognize = recognizer.recognize(tensor, landmarks); + if(recognize.id >= 0){ + rgb_printf(fb, FACE_COLOR_GREEN, "ID[%u]: %.2f", recognize.id, recognize.similarity); + } else { + rgb_print(fb, FACE_COLOR_RED, "Intruder Alert!"); + } + return recognize.id; +} +#endif +#endif + +#if CONFIG_LED_ILLUMINATOR_ENABLED +void enable_led(bool en) +{ // Turn LED On or Off + int duty = en ? led_duty : 0; + if (en && isStreaming && (led_duty > CONFIG_LED_MAX_INTENSITY)) + { + duty = CONFIG_LED_MAX_INTENSITY; + } + ledcWrite(LED_LEDC_GPIO, duty); + //ledc_set_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL, duty); + //ledc_update_duty(CONFIG_LED_LEDC_SPEED_MODE, CONFIG_LED_LEDC_CHANNEL); + log_i("Set LED intensity to %d", duty); +} +#endif + +static esp_err_t bmp_handler(httpd_req_t *req) +{ + camera_fb_t *fb = NULL; + esp_err_t res = ESP_OK; +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + uint64_t fr_start = esp_timer_get_time(); +#endif + fb = esp_camera_fb_get(); + if (!fb) + { + log_e("Camera capture failed"); + httpd_resp_send_500(req); + return ESP_FAIL; + } + + httpd_resp_set_type(req, "image/x-windows-bmp"); + httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.bmp"); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + char ts[32]; + snprintf(ts, 32, "%lld.%06ld", fb->timestamp.tv_sec, fb->timestamp.tv_usec); + httpd_resp_set_hdr(req, "X-Timestamp", (const char *)ts); + + + uint8_t * buf = NULL; + size_t buf_len = 0; + bool converted = frame2bmp(fb, &buf, &buf_len); + esp_camera_fb_return(fb); + if(!converted){ + log_e("BMP Conversion failed"); + httpd_resp_send_500(req); + return ESP_FAIL; + } + res = httpd_resp_send(req, (const char *)buf, buf_len); + free(buf); +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + uint64_t fr_end = esp_timer_get_time(); +#endif + log_i("BMP: %llums, %uB", (uint64_t)((fr_end - fr_start) / 1000), buf_len); + return res; +} + +static size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len) +{ + jpg_chunking_t *j = (jpg_chunking_t *)arg; + if (!index) + { + j->len = 0; + } + if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) + { + return 0; + } + j->len += len; + return len; +} + +static esp_err_t capture_handler(httpd_req_t *req) +{ + camera_fb_t *fb = NULL; + esp_err_t res = ESP_OK; +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + int64_t fr_start = esp_timer_get_time(); +#endif + +#if CONFIG_LED_ILLUMINATOR_ENABLED + enable_led(true); + vTaskDelay(150 / portTICK_PERIOD_MS); // The LED needs to be turned on ~150ms before the call to esp_camera_fb_get() + fb = esp_camera_fb_get(); // or it won't be visible in the frame. A better way to do this is needed. + enable_led(false); +#else + fb = esp_camera_fb_get(); +#endif + + if (!fb) + { + log_e("Camera capture failed"); + httpd_resp_send_500(req); + return ESP_FAIL; + } + + httpd_resp_set_type(req, "image/jpeg"); + httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg"); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + + char ts[32]; + snprintf(ts, 32, "%lld.%06ld", fb->timestamp.tv_sec, fb->timestamp.tv_usec); + httpd_resp_set_hdr(req, "X-Timestamp", (const char *)ts); + +#if CONFIG_ESP_FACE_DETECT_ENABLED + size_t out_len, out_width, out_height; + uint8_t *out_buf; + bool s; +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + bool detected = false; +#endif + int face_id = 0; + if (!detection_enabled || fb->width > 400) + { +#endif +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + size_t fb_len = 0; +#endif + if (fb->format == PIXFORMAT_JPEG) + { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fb_len = fb->len; +#endif + res = httpd_resp_send(req, (const char *)fb->buf, fb->len); + } + else + { + jpg_chunking_t jchunk = {req, 0}; + res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL; + httpd_resp_send_chunk(req, NULL, 0); +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fb_len = jchunk.len; +#endif + } + esp_camera_fb_return(fb); +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + int64_t fr_end = esp_timer_get_time(); +#endif + log_i("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000)); + return res; +#if CONFIG_ESP_FACE_DETECT_ENABLED + } + + jpg_chunking_t jchunk = {req, 0}; + + if (fb->format == PIXFORMAT_RGB565 +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + && !recognition_enabled +#endif + ){ +#if TWO_STAGE + HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); + HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); + std::list &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); + std::list &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates); +#else + HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); + std::list &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); +#endif + if (results.size() > 0) { + fb_data_t rfb; + rfb.width = fb->width; + rfb.height = fb->height; + rfb.data = fb->buf; + rfb.bytes_per_pixel = 2; + rfb.format = FB_RGB565; +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + detected = true; +#endif + draw_face_boxes(&rfb, &results, face_id); + } + s = fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 90, jpg_encode_stream, &jchunk); + esp_camera_fb_return(fb); + } else + { + out_len = fb->width * fb->height * 3; + out_width = fb->width; + out_height = fb->height; + out_buf = (uint8_t*)malloc(out_len); + if (!out_buf) { + log_e("out_buf malloc failed"); + httpd_resp_send_500(req); + return ESP_FAIL; + } + s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); + esp_camera_fb_return(fb); + if (!s) { + free(out_buf); + log_e("To rgb888 failed"); + httpd_resp_send_500(req); + return ESP_FAIL; + } + + fb_data_t rfb; + rfb.width = out_width; + rfb.height = out_height; + rfb.data = out_buf; + rfb.bytes_per_pixel = 3; + rfb.format = FB_BGR888; + +#if TWO_STAGE + HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); + HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); + std::list &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); + std::list &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates); +#else + HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); + std::list &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); +#endif + + if (results.size() > 0) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + detected = true; +#endif +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + if (recognition_enabled) { + face_id = run_face_recognition(&rfb, &results); + } +#endif + draw_face_boxes(&rfb, &results, face_id); + } + + s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk); + free(out_buf); + } + + if (!s) { + log_e("JPEG compression failed"); + httpd_resp_send_500(req); + return ESP_FAIL; + } +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + int64_t fr_end = esp_timer_get_time(); +#endif + log_i("FACE: %uB %ums %s%d", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start) / 1000), detected ? "DETECTED " : "", face_id); + return res; +#endif +} + +static esp_err_t stream_handler(httpd_req_t *req) +{ + camera_fb_t *fb = NULL; + struct timeval _timestamp; + esp_err_t res = ESP_OK; + size_t _jpg_buf_len = 0; + uint8_t *_jpg_buf = NULL; + char *part_buf[128]; +#if CONFIG_ESP_FACE_DETECT_ENABLED + #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + bool detected = false; + int64_t fr_ready = 0; + int64_t fr_recognize = 0; + int64_t fr_encode = 0; + int64_t fr_face = 0; + int64_t fr_start = 0; + #endif + int face_id = 0; + size_t out_len = 0, out_width = 0, out_height = 0; + uint8_t *out_buf = NULL; + bool s = false; +#if TWO_STAGE + HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F); + HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5); +#else + HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F); +#endif +#endif + + static int64_t last_frame = 0; + if (!last_frame) + { + last_frame = esp_timer_get_time(); + } + + res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); + if (res != ESP_OK) + { + return res; + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_hdr(req, "X-Framerate", "60"); + +#if CONFIG_LED_ILLUMINATOR_ENABLED + isStreaming = true; + enable_led(true); +#endif + + while (true) + { +#if CONFIG_ESP_FACE_DETECT_ENABLED + #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + detected = false; + #endif + face_id = 0; +#endif + + fb = esp_camera_fb_get(); + if (!fb) + { + log_e("Camera capture failed"); + res = ESP_FAIL; + } + else + { + _timestamp.tv_sec = fb->timestamp.tv_sec; + _timestamp.tv_usec = fb->timestamp.tv_usec; +#if CONFIG_ESP_FACE_DETECT_ENABLED + #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_start = esp_timer_get_time(); + fr_ready = fr_start; + fr_encode = fr_start; + fr_recognize = fr_start; + fr_face = fr_start; + #endif + if (!detection_enabled || fb->width > 400) + { +#endif + if (fb->format != PIXFORMAT_JPEG) + { + bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); + esp_camera_fb_return(fb); + fb = NULL; + if (!jpeg_converted) + { + log_e("JPEG compression failed"); + res = ESP_FAIL; + } + } + else + { + _jpg_buf_len = fb->len; + _jpg_buf = fb->buf; + } +#if CONFIG_ESP_FACE_DETECT_ENABLED + } + else + { + if (fb->format == PIXFORMAT_RGB565 +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + && !recognition_enabled +#endif + ){ +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_ready = esp_timer_get_time(); +#endif +#if TWO_STAGE + std::list &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); + std::list &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates); +#else + std::list &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}); +#endif +#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_face = esp_timer_get_time(); + fr_recognize = fr_face; +#endif + if (results.size() > 0) { + fb_data_t rfb; + rfb.width = fb->width; + rfb.height = fb->height; + rfb.data = fb->buf; + rfb.bytes_per_pixel = 2; + rfb.format = FB_RGB565; +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + detected = true; +#endif + draw_face_boxes(&rfb, &results, face_id); + } + s = fmt2jpg(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 80, &_jpg_buf, &_jpg_buf_len); + esp_camera_fb_return(fb); + fb = NULL; + if (!s) { + log_e("fmt2jpg failed"); + res = ESP_FAIL; + } +#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_encode = esp_timer_get_time(); +#endif + } else + { + out_len = fb->width * fb->height * 3; + out_width = fb->width; + out_height = fb->height; + out_buf = (uint8_t*)malloc(out_len); + if (!out_buf) { + log_e("out_buf malloc failed"); + res = ESP_FAIL; + } else { + s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); + esp_camera_fb_return(fb); + fb = NULL; + if (!s) { + free(out_buf); + log_e("To rgb888 failed"); + res = ESP_FAIL; + } else { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_ready = esp_timer_get_time(); +#endif + + fb_data_t rfb; + rfb.width = out_width; + rfb.height = out_height; + rfb.data = out_buf; + rfb.bytes_per_pixel = 3; + rfb.format = FB_BGR888; + +#if TWO_STAGE + std::list &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); + std::list &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates); +#else + std::list &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}); +#endif + +#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_face = esp_timer_get_time(); + fr_recognize = fr_face; +#endif + + if (results.size() > 0) { +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + detected = true; +#endif +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + if (recognition_enabled) { + face_id = run_face_recognition(&rfb, &results); + #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_recognize = esp_timer_get_time(); + #endif + } +#endif + draw_face_boxes(&rfb, &results, face_id); + } + s = fmt2jpg(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len); + free(out_buf); + if (!s) { + log_e("fmt2jpg failed"); + res = ESP_FAIL; + } +#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + fr_encode = esp_timer_get_time(); +#endif + } + } + } + } +#endif + } + if (res == ESP_OK) + { + res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); + } + if (res == ESP_OK) + { + size_t hlen = snprintf((char *)part_buf, 128, _STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec); + res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); + } + if (res == ESP_OK) + { + res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len); + } + if (fb) + { + esp_camera_fb_return(fb); + fb = NULL; + _jpg_buf = NULL; + } + else if (_jpg_buf) + { + free(_jpg_buf); + _jpg_buf = NULL; + } + if (res != ESP_OK) + { + log_e("Send frame failed"); + break; + } + int64_t fr_end = esp_timer_get_time(); + +#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + int64_t ready_time = (fr_ready - fr_start) / 1000; + int64_t face_time = (fr_face - fr_ready) / 1000; + int64_t recognize_time = (fr_recognize - fr_face) / 1000; + int64_t encode_time = (fr_encode - fr_recognize) / 1000; + int64_t process_time = (fr_encode - fr_start) / 1000; +#endif + + int64_t frame_time = fr_end - last_frame; + frame_time /= 1000; +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO + uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time); +#endif + log_i("MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)" +#if CONFIG_ESP_FACE_DETECT_ENABLED + ", %u+%u+%u+%u=%u %s%d" +#endif + , + (uint32_t)(_jpg_buf_len), + (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, + avg_frame_time, 1000.0 / avg_frame_time +#if CONFIG_ESP_FACE_DETECT_ENABLED + , + (uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time, + (detected) ? "DETECTED " : "", face_id +#endif + ); + } + +#if CONFIG_LED_ILLUMINATOR_ENABLED + isStreaming = false; + enable_led(false); +#endif + + return res; +} + +static esp_err_t parse_get(httpd_req_t *req, char **obuf) +{ + char *buf = NULL; + size_t buf_len = 0; + + buf_len = httpd_req_get_url_query_len(req) + 1; + if (buf_len > 1) { + buf = (char *)malloc(buf_len); + if (!buf) { + httpd_resp_send_500(req); + return ESP_FAIL; + } + if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { + *obuf = buf; + return ESP_OK; + } + free(buf); + } + httpd_resp_send_404(req); + return ESP_FAIL; +} + +static esp_err_t cmd_handler(httpd_req_t *req) +{ + char *buf = NULL; + char variable[32]; + char value[32]; + + if (parse_get(req, &buf) != ESP_OK) { + return ESP_FAIL; + } + if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) != ESP_OK || + httpd_query_key_value(buf, "val", value, sizeof(value)) != ESP_OK) { + free(buf); + httpd_resp_send_404(req); + return ESP_FAIL; + } + free(buf); + + int val = atoi(value); + log_i("%s = %d", variable, val); + sensor_t *s = esp_camera_sensor_get(); + int res = 0; + + if (!strcmp(variable, "framesize")) { + if (s->pixformat == PIXFORMAT_JPEG) { + res = s->set_framesize(s, (framesize_t)val); + } + } + else if (!strcmp(variable, "quality")) + res = s->set_quality(s, val); + else if (!strcmp(variable, "contrast")) + res = s->set_contrast(s, val); + else if (!strcmp(variable, "brightness")) + res = s->set_brightness(s, val); + else if (!strcmp(variable, "saturation")) + res = s->set_saturation(s, val); + else if (!strcmp(variable, "gainceiling")) + res = s->set_gainceiling(s, (gainceiling_t)val); + else if (!strcmp(variable, "colorbar")) + res = s->set_colorbar(s, val); + else if (!strcmp(variable, "awb")) + res = s->set_whitebal(s, val); + else if (!strcmp(variable, "agc")) + res = s->set_gain_ctrl(s, val); + else if (!strcmp(variable, "aec")) + res = s->set_exposure_ctrl(s, val); + else if (!strcmp(variable, "hmirror")) + res = s->set_hmirror(s, val); + else if (!strcmp(variable, "vflip")) + res = s->set_vflip(s, val); + else if (!strcmp(variable, "awb_gain")) + res = s->set_awb_gain(s, val); + else if (!strcmp(variable, "agc_gain")) + res = s->set_agc_gain(s, val); + else if (!strcmp(variable, "aec_value")) + res = s->set_aec_value(s, val); + else if (!strcmp(variable, "aec2")) + res = s->set_aec2(s, val); + else if (!strcmp(variable, "dcw")) + res = s->set_dcw(s, val); + else if (!strcmp(variable, "bpc")) + res = s->set_bpc(s, val); + else if (!strcmp(variable, "wpc")) + res = s->set_wpc(s, val); + else if (!strcmp(variable, "raw_gma")) + res = s->set_raw_gma(s, val); + else if (!strcmp(variable, "lenc")) + res = s->set_lenc(s, val); + else if (!strcmp(variable, "special_effect")) + res = s->set_special_effect(s, val); + else if (!strcmp(variable, "wb_mode")) + res = s->set_wb_mode(s, val); + else if (!strcmp(variable, "ae_level")) + res = s->set_ae_level(s, val); +#if CONFIG_LED_ILLUMINATOR_ENABLED + else if (!strcmp(variable, "led_intensity")) { + led_duty = val; + if (isStreaming) + enable_led(true); + } +#endif + +#if CONFIG_ESP_FACE_DETECT_ENABLED + else if (!strcmp(variable, "face_detect")) { + detection_enabled = val; +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + if (!detection_enabled) { + recognition_enabled = 0; + } +#endif + } +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + else if (!strcmp(variable, "face_enroll")){ + is_enrolling = !is_enrolling; + log_i("Enrolling: %s", is_enrolling?"true":"false"); + } + else if (!strcmp(variable, "face_recognize")) { + recognition_enabled = val; + if (recognition_enabled) { + detection_enabled = val; + } + } +#endif +#endif + else { + log_i("Unknown command: %s", variable); + res = -1; + } + + if (res < 0) { + return httpd_resp_send_500(req); + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, NULL, 0); +} + +static int print_reg(char * p, sensor_t * s, uint16_t reg, uint32_t mask){ + return sprintf(p, "\"0x%x\":%u,", reg, s->get_reg(s, reg, mask)); +} + +static esp_err_t status_handler(httpd_req_t *req) +{ + static char json_response[1024]; + + sensor_t *s = esp_camera_sensor_get(); + char *p = json_response; + *p++ = '{'; + + if(s->id.PID == OV5640_PID || s->id.PID == OV3660_PID){ + for(int reg = 0x3400; reg < 0x3406; reg+=2){ + p+=print_reg(p, s, reg, 0xFFF);//12 bit + } + p+=print_reg(p, s, 0x3406, 0xFF); + + p+=print_reg(p, s, 0x3500, 0xFFFF0);//16 bit + p+=print_reg(p, s, 0x3503, 0xFF); + p+=print_reg(p, s, 0x350a, 0x3FF);//10 bit + p+=print_reg(p, s, 0x350c, 0xFFFF);//16 bit + + for(int reg = 0x5480; reg <= 0x5490; reg++){ + p+=print_reg(p, s, reg, 0xFF); + } + + for(int reg = 0x5380; reg <= 0x538b; reg++){ + p+=print_reg(p, s, reg, 0xFF); + } + + for(int reg = 0x5580; reg < 0x558a; reg++){ + p+=print_reg(p, s, reg, 0xFF); + } + p+=print_reg(p, s, 0x558a, 0x1FF);//9 bit + } else if(s->id.PID == OV2640_PID){ + p+=print_reg(p, s, 0xd3, 0xFF); + p+=print_reg(p, s, 0x111, 0xFF); + p+=print_reg(p, s, 0x132, 0xFF); + } + + p += sprintf(p, "\"xclk\":%u,", s->xclk_freq_hz / 1000000); + p += sprintf(p, "\"pixformat\":%u,", s->pixformat); + p += sprintf(p, "\"framesize\":%u,", s->status.framesize); + p += sprintf(p, "\"quality\":%u,", s->status.quality); + p += sprintf(p, "\"brightness\":%d,", s->status.brightness); + p += sprintf(p, "\"contrast\":%d,", s->status.contrast); + p += sprintf(p, "\"saturation\":%d,", s->status.saturation); + p += sprintf(p, "\"sharpness\":%d,", s->status.sharpness); + p += sprintf(p, "\"special_effect\":%u,", s->status.special_effect); + p += sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode); + p += sprintf(p, "\"awb\":%u,", s->status.awb); + p += sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain); + p += sprintf(p, "\"aec\":%u,", s->status.aec); + p += sprintf(p, "\"aec2\":%u,", s->status.aec2); + p += sprintf(p, "\"ae_level\":%d,", s->status.ae_level); + p += sprintf(p, "\"aec_value\":%u,", s->status.aec_value); + p += sprintf(p, "\"agc\":%u,", s->status.agc); + p += sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain); + p += sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling); + p += sprintf(p, "\"bpc\":%u,", s->status.bpc); + p += sprintf(p, "\"wpc\":%u,", s->status.wpc); + p += sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma); + p += sprintf(p, "\"lenc\":%u,", s->status.lenc); + p += sprintf(p, "\"hmirror\":%u,", s->status.hmirror); + p += sprintf(p, "\"dcw\":%u,", s->status.dcw); + p += sprintf(p, "\"colorbar\":%u", s->status.colorbar); +#if CONFIG_LED_ILLUMINATOR_ENABLED + p += sprintf(p, ",\"led_intensity\":%u", led_duty); +#else + p += sprintf(p, ",\"led_intensity\":%d", -1); +#endif +#if CONFIG_ESP_FACE_DETECT_ENABLED + p += sprintf(p, ",\"face_detect\":%u", detection_enabled); +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + p += sprintf(p, ",\"face_enroll\":%u,", is_enrolling); + p += sprintf(p, "\"face_recognize\":%u", recognition_enabled); +#endif +#endif + *p++ = '}'; + *p++ = 0; + httpd_resp_set_type(req, "application/json"); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, json_response, strlen(json_response)); +} + +static esp_err_t xclk_handler(httpd_req_t *req) +{ + char *buf = NULL; + char _xclk[32]; + + if (parse_get(req, &buf) != ESP_OK) { + return ESP_FAIL; + } + if (httpd_query_key_value(buf, "xclk", _xclk, sizeof(_xclk)) != ESP_OK) { + free(buf); + httpd_resp_send_404(req); + return ESP_FAIL; + } + free(buf); + + int xclk = atoi(_xclk); + log_i("Set XCLK: %d MHz", xclk); + + sensor_t *s = esp_camera_sensor_get(); + int res = s->set_xclk(s, LEDC_TIMER_0, xclk); + if (res) { + return httpd_resp_send_500(req); + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, NULL, 0); +} + +static esp_err_t reg_handler(httpd_req_t *req) +{ + char *buf = NULL; + char _reg[32]; + char _mask[32]; + char _val[32]; + + if (parse_get(req, &buf) != ESP_OK) { + return ESP_FAIL; + } + if (httpd_query_key_value(buf, "reg", _reg, sizeof(_reg)) != ESP_OK || + httpd_query_key_value(buf, "mask", _mask, sizeof(_mask)) != ESP_OK || + httpd_query_key_value(buf, "val", _val, sizeof(_val)) != ESP_OK) { + free(buf); + httpd_resp_send_404(req); + return ESP_FAIL; + } + free(buf); + + int reg = atoi(_reg); + int mask = atoi(_mask); + int val = atoi(_val); + log_i("Set Register: reg: 0x%02x, mask: 0x%02x, value: 0x%02x", reg, mask, val); + + sensor_t *s = esp_camera_sensor_get(); + int res = s->set_reg(s, reg, mask, val); + if (res) { + return httpd_resp_send_500(req); + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, NULL, 0); +} + +static esp_err_t greg_handler(httpd_req_t *req) +{ + char *buf = NULL; + char _reg[32]; + char _mask[32]; + + if (parse_get(req, &buf) != ESP_OK) { + return ESP_FAIL; + } + if (httpd_query_key_value(buf, "reg", _reg, sizeof(_reg)) != ESP_OK || + httpd_query_key_value(buf, "mask", _mask, sizeof(_mask)) != ESP_OK) { + free(buf); + httpd_resp_send_404(req); + return ESP_FAIL; + } + free(buf); + + int reg = atoi(_reg); + int mask = atoi(_mask); + sensor_t *s = esp_camera_sensor_get(); + int res = s->get_reg(s, reg, mask); + if (res < 0) { + return httpd_resp_send_500(req); + } + log_i("Get Register: reg: 0x%02x, mask: 0x%02x, value: 0x%02x", reg, mask, res); + + char buffer[20]; + const char * val = itoa(res, buffer, 10); + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, val, strlen(val)); +} + +static int parse_get_var(char *buf, const char * key, int def) +{ + char _int[16]; + if(httpd_query_key_value(buf, key, _int, sizeof(_int)) != ESP_OK){ + return def; + } + return atoi(_int); +} + +static esp_err_t pll_handler(httpd_req_t *req) +{ + char *buf = NULL; + + if (parse_get(req, &buf) != ESP_OK) { + return ESP_FAIL; + } + + int bypass = parse_get_var(buf, "bypass", 0); + int mul = parse_get_var(buf, "mul", 0); + int sys = parse_get_var(buf, "sys", 0); + int root = parse_get_var(buf, "root", 0); + int pre = parse_get_var(buf, "pre", 0); + int seld5 = parse_get_var(buf, "seld5", 0); + int pclken = parse_get_var(buf, "pclken", 0); + int pclk = parse_get_var(buf, "pclk", 0); + free(buf); + + log_i("Set Pll: bypass: %d, mul: %d, sys: %d, root: %d, pre: %d, seld5: %d, pclken: %d, pclk: %d", bypass, mul, sys, root, pre, seld5, pclken, pclk); + sensor_t *s = esp_camera_sensor_get(); + int res = s->set_pll(s, bypass, mul, sys, root, pre, seld5, pclken, pclk); + if (res) { + return httpd_resp_send_500(req); + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, NULL, 0); +} + +static esp_err_t win_handler(httpd_req_t *req) +{ + char *buf = NULL; + + if (parse_get(req, &buf) != ESP_OK) { + return ESP_FAIL; + } + + int startX = parse_get_var(buf, "sx", 0); + int startY = parse_get_var(buf, "sy", 0); + int endX = parse_get_var(buf, "ex", 0); + int endY = parse_get_var(buf, "ey", 0); + int offsetX = parse_get_var(buf, "offx", 0); + int offsetY = parse_get_var(buf, "offy", 0); + int totalX = parse_get_var(buf, "tx", 0); + int totalY = parse_get_var(buf, "ty", 0); + int outputX = parse_get_var(buf, "ox", 0); + int outputY = parse_get_var(buf, "oy", 0); + bool scale = parse_get_var(buf, "scale", 0) == 1; + bool binning = parse_get_var(buf, "binning", 0) == 1; + free(buf); + + log_i("Set Window: Start: %d %d, End: %d %d, Offset: %d %d, Total: %d %d, Output: %d %d, Scale: %u, Binning: %u", startX, startY, endX, endY, offsetX, offsetY, totalX, totalY, outputX, outputY, scale, binning); + sensor_t *s = esp_camera_sensor_get(); + int res = s->set_res_raw(s, startX, startY, endX, endY, offsetX, offsetY, totalX, totalY, outputX, outputY, scale, binning); + if (res) { + return httpd_resp_send_500(req); + } + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + return httpd_resp_send(req, NULL, 0); +} + +static esp_err_t index_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "text/html"); + httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); + sensor_t *s = esp_camera_sensor_get(); + if (s != NULL) { + if (s->id.PID == OV3660_PID) { + return httpd_resp_send(req, (const char *)index_ov3660_html_gz, index_ov3660_html_gz_len); + } else if (s->id.PID == OV5640_PID) { + return httpd_resp_send(req, (const char *)index_ov5640_html_gz, index_ov5640_html_gz_len); + } else { + return httpd_resp_send(req, (const char *)index_ov2640_html_gz, index_ov2640_html_gz_len); + } + } else { + log_e("Camera sensor not found"); + return httpd_resp_send_500(req); + } +} + +void startCameraServer() +{ + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.max_uri_handlers = 16; + + httpd_uri_t index_uri = { + .uri = "/", + .method = HTTP_GET, + .handler = index_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t status_uri = { + .uri = "/status", + .method = HTTP_GET, + .handler = status_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t cmd_uri = { + .uri = "/control", + .method = HTTP_GET, + .handler = cmd_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t capture_uri = { + .uri = "/capture", + .method = HTTP_GET, + .handler = capture_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t stream_uri = { + .uri = "/stream", + .method = HTTP_GET, + .handler = stream_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t bmp_uri = { + .uri = "/bmp", + .method = HTTP_GET, + .handler = bmp_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t xclk_uri = { + .uri = "/xclk", + .method = HTTP_GET, + .handler = xclk_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t reg_uri = { + .uri = "/reg", + .method = HTTP_GET, + .handler = reg_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t greg_uri = { + .uri = "/greg", + .method = HTTP_GET, + .handler = greg_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t pll_uri = { + .uri = "/pll", + .method = HTTP_GET, + .handler = pll_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + httpd_uri_t win_uri = { + .uri = "/resolution", + .method = HTTP_GET, + .handler = win_handler, + .user_ctx = NULL +#ifdef CONFIG_HTTPD_WS_SUPPORT + , + .is_websocket = true, + .handle_ws_control_frames = false, + .supported_subprotocol = NULL +#endif + }; + + ra_filter_init(&ra_filter, 20); + +#if CONFIG_ESP_FACE_RECOGNITION_ENABLED + recognizer.set_partition(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "fr"); + + // load ids from flash partition + recognizer.set_ids_from_flash(); +#endif + log_i("Starting web server on port: '%d'", config.server_port); + if (httpd_start(&camera_httpd, &config) == ESP_OK) + { + httpd_register_uri_handler(camera_httpd, &index_uri); + httpd_register_uri_handler(camera_httpd, &cmd_uri); + httpd_register_uri_handler(camera_httpd, &status_uri); + httpd_register_uri_handler(camera_httpd, &capture_uri); + httpd_register_uri_handler(camera_httpd, &bmp_uri); + + httpd_register_uri_handler(camera_httpd, &xclk_uri); + httpd_register_uri_handler(camera_httpd, ®_uri); + httpd_register_uri_handler(camera_httpd, &greg_uri); + httpd_register_uri_handler(camera_httpd, &pll_uri); + httpd_register_uri_handler(camera_httpd, &win_uri); + } + + config.server_port += 1; + config.ctrl_port += 1; + log_i("Starting stream server on port: '%d'", config.server_port); + if (httpd_start(&stream_httpd, &config) == ESP_OK) + { + httpd_register_uri_handler(stream_httpd, &stream_uri); + } +} + +void setupLedFlash(int pin) +{ + #if CONFIG_LED_ILLUMINATOR_ENABLED + ledcAttach(pin, 5000, 8); + #else + log_i("LED flash is disabled -> CONFIG_LED_ILLUMINATOR_ENABLED = 0"); + #endif +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h new file mode 100644 index 0000000..fa42e69 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/camera_index.h @@ -0,0 +1,1571 @@ + + +//File: index_ov2640.html.gz, Size: 6787 +#define index_ov2640_html_gz_len 6787 +const uint8_t index_ov2640_html_gz[] = { + 0x1F, 0x8B, 0x08, 0x08, 0x23, 0xFC, 0x69, 0x5E, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, + 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x00, 0xED, 0x3D, 0x6B, 0x73, + 0xDB, 0x46, 0x92, 0xDF, 0xFD, 0x2B, 0x60, 0x24, 0x6B, 0x92, 0x25, 0x92, 0x22, 0x29, 0x4A, 0x96, + 0x15, 0x89, 0x3E, 0x5B, 0x96, 0x1F, 0xB5, 0x76, 0xE2, 0xB5, 0x12, 0xC7, 0x5B, 0xA9, 0x2D, 0x07, + 0x04, 0x86, 0x24, 0x62, 0x10, 0xE0, 0x02, 0xA0, 0x48, 0x26, 0xA5, 0xDF, 0x71, 0x3F, 0xE8, 0xFE, + 0xD8, 0x75, 0xCF, 0x03, 0x18, 0x00, 0x83, 0x07, 0x49, 0x89, 0xF4, 0xFA, 0x8E, 0x4E, 0x45, 0x78, + 0x4C, 0xF7, 0xF4, 0xBB, 0x7B, 0x66, 0x30, 0xC0, 0xF9, 0x43, 0xCB, 0x33, 0xC3, 0xD5, 0x8C, 0x68, + 0x93, 0x70, 0xEA, 0x0C, 0x1E, 0x9C, 0xB3, 0x3F, 0x1A, 0xFC, 0xCE, 0x27, 0xC4, 0xB0, 0xD8, 0x21, + 0x3D, 0x9D, 0x92, 0xD0, 0xD0, 0xCC, 0x89, 0xE1, 0x07, 0x24, 0xBC, 0xD0, 0xE7, 0xE1, 0xA8, 0x75, + 0xAA, 0xA7, 0x6F, 0xBB, 0xC6, 0x94, 0x5C, 0xE8, 0x37, 0x36, 0x59, 0xCC, 0x3C, 0x3F, 0xD4, 0x35, + 0xD3, 0x73, 0x43, 0xE2, 0x42, 0xF3, 0x85, 0x6D, 0x85, 0x93, 0x0B, 0x8B, 0xDC, 0xD8, 0x26, 0x69, + 0xD1, 0x93, 0xA6, 0xED, 0xDA, 0xA1, 0x6D, 0x38, 0xAD, 0xC0, 0x34, 0x1C, 0x72, 0xD1, 0x95, 0x71, + 0x85, 0x76, 0xE8, 0x90, 0xC1, 0xD5, 0xF5, 0xFB, 0xA3, 0x9E, 0xF6, 0xD3, 0xC7, 0x5E, 0xFF, 0xA4, + 0x73, 0x7E, 0xC8, 0xAE, 0xC5, 0x6D, 0x82, 0x70, 0x25, 0x9F, 0xE3, 0x6F, 0xE8, 0x59, 0x2B, 0xED, + 0xAF, 0xC4, 0x25, 0xFC, 0x8D, 0x80, 0x88, 0xD6, 0xC8, 0x98, 0xDA, 0xCE, 0xEA, 0x4C, 0x7B, 0xE6, + 0x43, 0x9F, 0xCD, 0xD7, 0xC4, 0xB9, 0x21, 0xA1, 0x6D, 0x1A, 0xCD, 0xC0, 0x70, 0x83, 0x56, 0x40, + 0x7C, 0x7B, 0xF4, 0x43, 0x06, 0x70, 0x68, 0x98, 0x5F, 0xC6, 0xBE, 0x37, 0x77, 0xAD, 0x33, 0xED, + 0xBB, 0xEE, 0x29, 0xFE, 0xCB, 0x36, 0x32, 0x3D, 0xC7, 0xF3, 0xE1, 0xFE, 0xD5, 0x4B, 0xFC, 0x97, + 0xBD, 0x4F, 0x7B, 0x0F, 0xEC, 0x3F, 0xC9, 0x99, 0xD6, 0x3D, 0x99, 0x2D, 0x13, 0xF7, 0x6F, 0x1F, + 0x24, 0x4E, 0x27, 0xBD, 0x3C, 0xEA, 0x39, 0xFC, 0x69, 0x31, 0x7C, 0x40, 0xCC, 0xD0, 0xF6, 0xDC, + 0xF6, 0xD4, 0xB0, 0x5D, 0x05, 0x26, 0xCB, 0x0E, 0x66, 0x8E, 0x01, 0x32, 0x18, 0x39, 0xA4, 0x10, + 0xCF, 0x77, 0x53, 0xE2, 0xCE, 0x9B, 0x25, 0xD8, 0x10, 0x49, 0xCB, 0xB2, 0x7D, 0xD6, 0xEA, 0x0C, + 0xE5, 0x30, 0x9F, 0xBA, 0xA5, 0x68, 0x8B, 0xE8, 0x72, 0x3D, 0x97, 0x28, 0x04, 0x88, 0x1D, 0x2D, + 0x7C, 0x63, 0x86, 0x0D, 0xF0, 0x6F, 0xB6, 0xC9, 0xD4, 0x76, 0x99, 0x51, 0x9D, 0x69, 0x47, 0xFD, + 0xCE, 0x6C, 0x59, 0xA2, 0xCA, 0xA3, 0x13, 0xFC, 0x97, 0x6D, 0x34, 0x33, 0x2C, 0xCB, 0x76, 0xC7, + 0x67, 0xDA, 0xA9, 0x12, 0x85, 0xE7, 0x5B, 0xC4, 0x6F, 0xF9, 0x86, 0x65, 0xCF, 0x83, 0x33, 0xAD, + 0xAF, 0x6A, 0x33, 0x35, 0xFC, 0x31, 0xD0, 0x12, 0x7A, 0x40, 0x6C, 0xAB, 0xAB, 0xA4, 0x84, 0x37, + 0xF1, 0xED, 0xF1, 0x24, 0x04, 0x95, 0x66, 0xDA, 0xA4, 0x85, 0xC6, 0x5D, 0xA8, 0x4C, 0x9F, 0x85, + 0x72, 0x53, 0x4B, 0xCD, 0x70, 0xEC, 0xB1, 0xDB, 0xB2, 0x43, 0x32, 0x05, 0x76, 0x82, 0xD0, 0x27, + 0xA1, 0x39, 0x29, 0x22, 0x65, 0x64, 0x8F, 0xE7, 0x3E, 0x51, 0x10, 0x12, 0xC9, 0xAD, 0x80, 0x61, + 0xB8, 0x99, 0xBD, 0xD5, 0x5A, 0x90, 0xE1, 0x17, 0x3B, 0x6C, 0x71, 0x99, 0x0C, 0xC9, 0xC8, 0xF3, + 0x89, 0xB2, 0xA5, 0x68, 0xE1, 0x78, 0xE6, 0x97, 0x56, 0x10, 0x1A, 0x7E, 0x58, 0x05, 0xA1, 0x31, + 0x0A, 0x89, 0x5F, 0x8E, 0x8F, 0xA0, 0x55, 0x94, 0x63, 0xCB, 0xEF, 0x96, 0x37, 0xB0, 0x5D, 0xC7, + 0x76, 0x49, 0x75, 0xF2, 0xF2, 0xFA, 0x4D, 0xA2, 0x63, 0xAD, 0x2A, 0x28, 0xC6, 0x9E, 0x8E, 0x8B, + 0xAC, 0x84, 0xF2, 0x9A, 0xED, 0x8C, 0xFB, 0x4D, 0xB7, 0xD3, 0xF9, 0x5B, 0xF6, 0xE6, 0x84, 0x30, + 0x33, 0x35, 0xE6, 0xA1, 0xB7, 0xBD, 0x47, 0x64, 0xDC, 0x2A, 0xC5, 0xC7, 0x7F, 0x4D, 0x89, 0x65, + 0x1B, 0x5A, 0x5D, 0x72, 0xE7, 0xD3, 0x0E, 0xD8, 0x54, 0x43, 0x33, 0x5C, 0x4B, 0xAB, 0x7B, 0xBE, + 0x0D, 0x8E, 0x60, 0xD0, 0x70, 0xE3, 0xC0, 0x15, 0x48, 0x1C, 0x33, 0xD2, 0x50, 0xB0, 0x5C, 0xE0, + 0x33, 0xB2, 0x44, 0xD4, 0x6E, 0x83, 0xBF, 0x0A, 0x21, 0x07, 0x7F, 0xA5, 0x0E, 0xA4, 0xE0, 0x91, + 0xA2, 0x2F, 0xD2, 0x97, 0x4C, 0x61, 0x9E, 0xCE, 0xF0, 0x37, 0x35, 0x96, 0xAD, 0x42, 0xDD, 0x89, + 0x46, 0x42, 0x87, 0x90, 0x66, 0xCD, 0x3A, 0x34, 0xBD, 0x99, 0x68, 0x2D, 0x0D, 0xA3, 0x64, 0x43, + 0x0D, 0xC3, 0x91, 0xAA, 0x55, 0x8E, 0x3F, 0xD9, 0x28, 0xD6, 0x60, 0x57, 0xCD, 0x6A, 0x1C, 0x3B, + 0xD8, 0x3F, 0x95, 0x0D, 0x31, 0x4E, 0x72, 0xA3, 0x08, 0xFE, 0xAA, 0x47, 0x92, 0x18, 0x59, 0x69, + 0x34, 0x51, 0x20, 0xCE, 0x8F, 0x28, 0x19, 0xBC, 0x79, 0xDE, 0xAD, 0xC0, 0x5A, 0x4C, 0x42, 0xD5, + 0xE8, 0xA2, 0x40, 0x5C, 0x44, 0x43, 0x69, 0x94, 0xC1, 0xDF, 0x6D, 0x85, 0x7A, 0xE3, 0xBB, 0xE1, + 0x3C, 0x0C, 0x3D, 0x37, 0xD8, 0x2A, 0x45, 0xE5, 0xF9, 0xD9, 0x1F, 0xF3, 0x20, 0xB4, 0x47, 0xAB, + 0x16, 0x77, 0x69, 0xF0, 0xB3, 0x99, 0x01, 0x25, 0xE4, 0x90, 0x84, 0x0B, 0x42, 0x8A, 0xCB, 0x0D, + 0xD7, 0xB8, 0x81, 0xB8, 0x33, 0x1E, 0x3B, 0x2A, 0xDB, 0x33, 0xE7, 0x7E, 0x80, 0x75, 0xDB, 0xCC, + 0xB3, 0x01, 0xB1, 0x9F, 0xED, 0x38, 0xE9, 0x83, 0x15, 0x3B, 0x6A, 0x99, 0x43, 0x45, 0x5F, 0xDE, + 0x3C, 0x44, 0x19, 0x2B, 0x35, 0xE1, 0x01, 0x3B, 0x76, 0xB8, 0x52, 0xDE, 0xE3, 0x9E, 0xA8, 0xB8, + 0x23, 0x5C, 0xB0, 0x30, 0x2D, 0x24, 0xE9, 0x3A, 0x33, 0x27, 0xC4, 0xFC, 0x42, 0xAC, 0x83, 0xD2, + 0x32, 0xAC, 0xAC, 0x3C, 0x6C, 0xDB, 0xEE, 0x6C, 0x1E, 0xB6, 0xB0, 0x9C, 0x9A, 0xDD, 0x8B, 0xCE, + 0xA9, 0x41, 0x0A, 0x16, 0x7B, 0xBD, 0xA2, 0xA2, 0xE2, 0x78, 0xB6, 0x2C, 0x16, 0x82, 0x4C, 0xEC, + 0xC0, 0x31, 0x86, 0xC4, 0x29, 0x22, 0x99, 0x3B, 0x43, 0x4E, 0xD8, 0xE5, 0xB1, 0x2A, 0xBF, 0x76, + 0xA3, 0x94, 0xC5, 0xC9, 0xAB, 0xFF, 0xF8, 0x6F, 0x95, 0xE5, 0x48, 0x8F, 0x9B, 0x89, 0x4B, 0x01, + 0x71, 0xC0, 0xC1, 0xF2, 0x4A, 0x6F, 0x68, 0xB3, 0x00, 0x1A, 0x0A, 0x3B, 0xF0, 0x0D, 0x77, 0x4C, + 0x20, 0x16, 0x2C, 0x9B, 0xE2, 0xB0, 0x78, 0x60, 0x50, 0x89, 0x7D, 0x0C, 0xD5, 0xC7, 0xC5, 0x03, + 0x11, 0x16, 0x10, 0x9A, 0x5A, 0x9B, 0x1D, 0x6C, 0x50, 0x95, 0x48, 0xFA, 0x2D, 0x24, 0xA4, 0xAB, + 0xB4, 0x0E, 0x56, 0x98, 0x28, 0x3D, 0x27, 0x69, 0x5B, 0xCA, 0x42, 0xBF, 0x34, 0x34, 0x88, 0x21, + 0xDF, 0x68, 0x54, 0x36, 0x68, 0x1C, 0x8D, 0x8E, 0x3A, 0x47, 0xFD, 0xD2, 0xCA, 0x49, 0xC9, 0x65, + 0x6A, 0xE0, 0xA8, 0x08, 0x1D, 0x51, 0x58, 0x29, 0x34, 0x82, 0xC0, 0xB8, 0x51, 0x16, 0xED, 0x5E, + 0x60, 0xB3, 0x91, 0x9B, 0x31, 0x0C, 0x60, 0xEC, 0x16, 0x2A, 0x86, 0x5E, 0xDC, 0xD0, 0x7B, 0x4A, + 0xFA, 0x68, 0x49, 0xA7, 0x74, 0x01, 0x21, 0x5E, 0x35, 0xD9, 0x09, 0x0D, 0xA8, 0x9B, 0x48, 0x0A, + 0x56, 0x16, 0x95, 0x21, 0x59, 0x86, 0x2D, 0x8B, 0x98, 0x9E, 0xCF, 0xAA, 0xC1, 0x9C, 0x91, 0x63, + 0x4A, 0x91, 0xE5, 0x16, 0x7B, 0x36, 0xF1, 0x6E, 0x88, 0xAF, 0x10, 0x56, 0x4A, 0xA9, 0xFD, 0x27, + 0x7D, 0xAB, 0x02, 0x36, 0x03, 0xD2, 0xA3, 0x52, 0xF6, 0x49, 0x74, 0xBD, 0xAE, 0xD9, 0x2B, 0xF4, + 0x63, 0x86, 0xAE, 0x0D, 0x3E, 0x63, 0x0C, 0x1D, 0x62, 0x15, 0x64, 0x33, 0x8B, 0x8C, 0x8C, 0xB9, + 0x13, 0x96, 0x58, 0xA5, 0xD1, 0xC1, 0x7F, 0x45, 0x3D, 0xD2, 0x30, 0xF4, 0x1B, 0xCE, 0x0B, 0x5D, + 0xD0, 0xC0, 0xF1, 0x2F, 0x45, 0x9F, 0xA2, 0xD4, 0x30, 0x66, 0x33, 0x62, 0x40, 0x2B, 0x93, 0xE4, + 0xE9, 0xA1, 0xD2, 0x10, 0x43, 0x1D, 0xE7, 0x2B, 0x8D, 0xDB, 0x4B, 0x1D, 0x36, 0x2A, 0x1E, 0xD7, + 0xE2, 0xF9, 0x6C, 0xE4, 0x99, 0x73, 0x55, 0x55, 0x53, 0xCD, 0xF1, 0xB2, 0xF8, 0xCE, 0x84, 0xC8, + 0x02, 0xC7, 0xA6, 0xEE, 0x3F, 0x77, 0x5D, 0xD4, 0x68, 0x2B, 0xF4, 0x81, 0x4D, 0x45, 0x47, 0xD5, + 0x04, 0xB7, 0x51, 0x0C, 0x4B, 0x08, 0x36, 0x6F, 0xEE, 0x2A, 0x15, 0xA6, 0x14, 0xE1, 0x34, 0x8A, + 0xB4, 0x1A, 0xC4, 0x10, 0xDB, 0x12, 0xA8, 0xB6, 0x93, 0x4B, 0x38, 0x99, 0x4F, 0x55, 0x75, 0x94, + 0xE8, 0xAC, 0x0B, 0x49, 0x9F, 0x75, 0xE7, 0x8F, 0x87, 0x46, 0xBD, 0xD3, 0xEC, 0x34, 0x8F, 0xE0, + 0x7F, 0x8A, 0xF1, 0x4C, 0xB1, 0x71, 0x71, 0xF1, 0xE6, 0x58, 0x5E, 0x2A, 0x44, 0x97, 0x4F, 0x2B, + 0xE5, 0x05, 0xFB, 0x52, 0x5D, 0x54, 0xF7, 0xA4, 0xE4, 0xFC, 0x52, 0xB7, 0x5D, 0x92, 0x87, 0x73, + 0x4C, 0x7A, 0x7D, 0x43, 0x54, 0x58, 0xCB, 0xBA, 0x2A, 0x9E, 0x7A, 0x7F, 0xB6, 0x58, 0x11, 0xF2, + 0x7F, 0xDE, 0xDA, 0x25, 0x51, 0x7C, 0xD3, 0x96, 0xBE, 0xB6, 0x5C, 0x82, 0x7D, 0xDB, 0x46, 0x27, + 0x5F, 0xEB, 0x2D, 0x5E, 0xF5, 0x01, 0x85, 0x2E, 0x8C, 0x41, 0x7D, 0x18, 0x8C, 0xE6, 0x56, 0x86, + 0x52, 0x9B, 0x0D, 0x64, 0x30, 0xB2, 0x1D, 0xA7, 0xE5, 0x78, 0x8B, 0xF2, 0x4A, 0xA4, 0xD8, 0x92, + 0x33, 0x76, 0x5A, 0x6E, 0xF2, 0x9B, 0x52, 0x3B, 0x87, 0xC8, 0xF5, 0x1F, 0x41, 0xED, 0xB7, 0xED, + 0x70, 0x85, 0xAE, 0xB1, 0x59, 0xA2, 0xD8, 0xC0, 0x1E, 0xB7, 0xEB, 0xA8, 0x92, 0x29, 0xB1, 0x4A, + 0xB0, 0x78, 0xD8, 0xB3, 0xB0, 0x43, 0x73, 0xB2, 0xC1, 0xD0, 0x33, 0x1E, 0x18, 0xF9, 0xC4, 0x31, + 0xB0, 0x82, 0xDF, 0x68, 0x86, 0xA2, 0x74, 0xF8, 0x26, 0x83, 0x57, 0xE1, 0x84, 0x8A, 0xEE, 0xEB, + 0x99, 0x5D, 0x6A, 0xB3, 0xDA, 0x21, 0x3F, 0x56, 0xAB, 0xCD, 0xBA, 0xA4, 0xDC, 0x4F, 0x7A, 0x86, + 0xBA, 0xD1, 0x1A, 0x11, 0x5D, 0x04, 0xED, 0xB1, 0x4F, 0x56, 0x15, 0x98, 0x69, 0xF2, 0xBF, 0x67, + 0x6C, 0xFE, 0x78, 0xF3, 0xA9, 0x12, 0x9A, 0x00, 0xB8, 0x15, 0xB5, 0xFB, 0x41, 0x85, 0xAE, 0xF3, + 0xBB, 0xAC, 0x62, 0x8F, 0xD1, 0xEC, 0xA8, 0xAE, 0x57, 0x08, 0x37, 0x05, 0x29, 0x54, 0x6D, 0xAA, + 0x22, 0xFB, 0xAA, 0xC7, 0xF3, 0x64, 0x14, 0xE6, 0x2C, 0xFE, 0xD0, 0x3A, 0xF5, 0xA8, 0x38, 0xBA, + 0xB5, 0xA4, 0xD9, 0x94, 0xD2, 0xC8, 0x11, 0x4D, 0x62, 0xE6, 0x5B, 0x9F, 0x12, 0x33, 0x46, 0xCF, + 0xB5, 0x91, 0xE7, 0xAB, 0x44, 0x94, 0xCF, 0x54, 0xCD, 0xD0, 0x66, 0xCA, 0x53, 0x3E, 0xA8, 0x87, + 0x7C, 0xAA, 0xF7, 0x4E, 0x94, 0x6B, 0x2B, 0x05, 0x8D, 0x8B, 0x48, 0xCB, 0x9D, 0x05, 0xCC, 0xA6, + 0xAC, 0xDC, 0x01, 0xB2, 0x1C, 0x8B, 0x94, 0x8A, 0x2A, 0xF6, 0xCA, 0xA2, 0x08, 0x93, 0x9D, 0xC9, + 0x2A, 0x34, 0x76, 0x7B, 0x6A, 0x40, 0xD9, 0x8B, 0xE6, 0x6A, 0x00, 0x46, 0x95, 0xFE, 0xAA, 0x98, + 0xBB, 0x34, 0xC7, 0xDA, 0x3D, 0xE9, 0x94, 0x74, 0x69, 0x3A, 0x5E, 0xB0, 0xE5, 0x04, 0x58, 0xFE, + 0xFC, 0x97, 0xF2, 0x4E, 0xA5, 0xD4, 0x5D, 0xE8, 0x53, 0xC5, 0xEE, 0x98, 0x92, 0x79, 0xB7, 0xA3, + 0x8C, 0xB4, 0x85, 0xB3, 0x94, 0x74, 0x06, 0x8D, 0xAE, 0x5F, 0x9E, 0x69, 0x26, 0x51, 0x87, 0xD1, + 0xE4, 0x44, 0x5D, 0x95, 0xA9, 0xD2, 0x42, 0x3D, 0x4C, 0x6C, 0xCB, 0x22, 0x85, 0x73, 0xC1, 0x38, + 0xE6, 0xAD, 0x58, 0x3C, 0x20, 0xFD, 0xAA, 0x49, 0xA9, 0x7B, 0x71, 0x8A, 0xC2, 0xC7, 0x1A, 0xBA, + 0xF7, 0xED, 0x31, 0x3C, 0xD1, 0xE4, 0xCD, 0xA4, 0x27, 0x4B, 0x91, 0x42, 0x52, 0x95, 0xCE, 0x1D, + 0xCD, 0xB5, 0xA2, 0xC8, 0x40, 0x0E, 0xD8, 0x2A, 0x1B, 0xCD, 0x53, 0x54, 0xD1, 0x85, 0x94, 0x36, + 0x5F, 0x5B, 0xE2, 0xCB, 0x80, 0xAD, 0xBC, 0xD5, 0x95, 0x3B, 0x5C, 0x6A, 0xA3, 0x16, 0x90, 0xEE, + 0x37, 0x57, 0x34, 0x7B, 0xAA, 0x8C, 0x0A, 0x88, 0x8C, 0x52, 0x8C, 0x78, 0xB8, 0x2A, 0xD9, 0x6A, + 0x53, 0xE7, 0x38, 0x3F, 0x94, 0x9E, 0x86, 0x3B, 0x3F, 0x8C, 0x1F, 0xDC, 0x3B, 0xC7, 0x47, 0xE2, + 0xE4, 0x87, 0xE6, 0x78, 0x3F, 0xA6, 0x63, 0x04, 0xC1, 0x85, 0x8E, 0x8F, 0x76, 0xE9, 0xC9, 0x67, + 0xE8, 0xCE, 0x2D, 0xFB, 0x46, 0xB3, 0xAD, 0x0B, 0xDD, 0xF1, 0xC6, 0x5E, 0xEA, 0x1E, 0xBD, 0xCF, + 0xB4, 0x0C, 0x79, 0xEC, 0x42, 0x4F, 0xAC, 0x2F, 0xEA, 0x14, 0x2A, 0xBE, 0xA4, 0x0F, 0x1E, 0x7D, + 0xF7, 0xE4, 0xF1, 0xE3, 0x93, 0x1F, 0x1E, 0xB9, 0xC3, 0x60, 0xC6, 0xFF, 0xFF, 0x33, 0x5B, 0x8E, + 0xFD, 0xE9, 0x63, 0xEF, 0xA4, 0x0F, 0xC3, 0x3D, 0x12, 0x86, 0x60, 0x7A, 0xC1, 0xF9, 0x21, 0x45, + 0x9A, 0x22, 0xE4, 0x10, 0x28, 0xC9, 0xA1, 0x8D, 0x97, 0x3B, 0x2A, 0xF2, 0x44, 0x93, 0x00, 0x32, + 0xF8, 0xD0, 0xF0, 0x15, 0x4D, 0x68, 0x33, 0x56, 0x4C, 0xD3, 0x50, 0xA2, 0x53, 0x9D, 0x0C, 0xBD, + 0x65, 0x9A, 0x03, 0xCA, 0x14, 0x57, 0x18, 0x6F, 0x45, 0xAC, 0x3C, 0x84, 0x00, 0x46, 0xC1, 0x71, + 0x71, 0x15, 0xDA, 0x28, 0x1B, 0x25, 0x54, 0x80, 0x8D, 0x97, 0xA6, 0xF3, 0x45, 0xE8, 0x5E, 0x17, + 0x4A, 0x71, 0xBD, 0x90, 0x85, 0xCA, 0x9C, 0xAE, 0x12, 0xAC, 0x72, 0x18, 0x69, 0xD9, 0x90, 0x71, + 0x01, 0xA2, 0x6D, 0x51, 0xEC, 0xEC, 0x5A, 0x31, 0x26, 0x8A, 0x4D, 0xD2, 0xAB, 0x00, 0xD6, 0x07, + 0x9F, 0x2E, 0xDF, 0xFE, 0x5D, 0x7B, 0xF7, 0xFA, 0x4F, 0xA5, 0x86, 0xCA, 0x88, 0xC2, 0x18, 0x5D, + 0xA1, 0x67, 0x0A, 0xC6, 0xF4, 0x21, 0x64, 0xA2, 0x73, 0xCD, 0x50, 0x0C, 0x98, 0xED, 0x1D, 0xE2, + 0x8E, 0xC3, 0xC9, 0x85, 0xDE, 0xD5, 0xF1, 0x91, 0x16, 0x71, 0xD6, 0xD3, 0x35, 0x8C, 0xDF, 0xF4, + 0xE0, 0xC6, 0x70, 0xE6, 0x78, 0xD4, 0xA9, 0xC2, 0x6B, 0xD6, 0xB4, 0x94, 0xCD, 0x78, 0x60, 0x89, + 0x64, 0x2C, 0x05, 0xE2, 0xA4, 0x94, 0xF5, 0xC1, 0x35, 0x09, 0xCF, 0x0F, 0xD9, 0xAD, 0x12, 0xAD, + 0x15, 0xF7, 0x0D, 0x9E, 0xCC, 0xCC, 0xA1, 0xC8, 0x84, 0x8A, 0x14, 0x3F, 0xF2, 0x8D, 0x29, 0x41, + 0xA9, 0x54, 0xD2, 0xBC, 0xAC, 0xF5, 0x08, 0x52, 0x1F, 0x7C, 0x20, 0xB4, 0x20, 0x02, 0x32, 0x2A, + 0x29, 0xFE, 0x9C, 0xD7, 0xA8, 0x89, 0xFE, 0x23, 0x7B, 0xE6, 0x6B, 0x52, 0x2D, 0x83, 0x99, 0x79, + 0x05, 0xB9, 0x3F, 0x6C, 0xB5, 0xB4, 0xDE, 0xBB, 0xF7, 0x5A, 0xAB, 0x55, 0xA1, 0xB1, 0x37, 0xA3, + 0xEE, 0xC4, 0xF5, 0xDF, 0x3D, 0xD2, 0x07, 0xBF, 0x7C, 0x7A, 0xF5, 0xAC, 0x0E, 0x75, 0x61, 0x67, + 0xD9, 0xED, 0x75, 0x3A, 0x8D, 0xF3, 0x43, 0xD6, 0x64, 0x7D, 0x5C, 0x3D, 0xD0, 0x2B, 0xC5, 0xD5, + 0x3B, 0x05, 0x5C, 0x9D, 0x5E, 0x7F, 0x0B, 0x5C, 0x5D, 0x7D, 0xF0, 0xFA, 0x05, 0xC3, 0xF4, 0xB8, + 0xB7, 0x0D, 0x51, 0x60, 0xE0, 0x94, 0x26, 0x20, 0x67, 0xF9, 0xF8, 0xE4, 0x74, 0x73, 0x4C, 0x4F, + 0x80, 0xBB, 0x8F, 0x80, 0xE9, 0x14, 0x04, 0x75, 0xB2, 0x8D, 0x9C, 0x4E, 0xF5, 0x01, 0xE2, 0x81, + 0x88, 0xBE, 0xEC, 0x9F, 0x6E, 0x81, 0xE7, 0x31, 0x88, 0x08, 0x11, 0x01, 0x92, 0xE5, 0xD1, 0x36, + 0x32, 0x3A, 0xD1, 0x07, 0x97, 0x6F, 0x5E, 0xD6, 0xFB, 0xC0, 0x58, 0xEF, 0xC9, 0xC9, 0xE6, 0x78, + 0x8E, 0xF5, 0xC1, 0x3F, 0x90, 0x20, 0x20, 0x66, 0xD9, 0xEB, 0x6F, 0x41, 0x50, 0x5F, 0x1F, 0x00, + 0x3C, 0xE2, 0xD8, 0x18, 0x05, 0xD8, 0xF5, 0x6B, 0x4A, 0x0C, 0x22, 0xEA, 0x3E, 0xDE, 0x82, 0x2B, + 0xB0, 0xEA, 0x7F, 0xA0, 0x78, 0x00, 0xC9, 0xB2, 0xDB, 0xDF, 0xC6, 0xA6, 0x01, 0x11, 0x25, 0x09, + 0x7C, 0x0D, 0x5D, 0x6D, 0x73, 0x4C, 0x60, 0xD3, 0x4F, 0x4E, 0x96, 0x4F, 0x4E, 0xAA, 0x21, 0xC0, + 0x18, 0x89, 0xF1, 0xA6, 0x28, 0x8A, 0x16, 0x07, 0xD9, 0xA2, 0x00, 0xFA, 0xEF, 0x39, 0x0C, 0x8B, + 0xC2, 0xD5, 0xDA, 0xE1, 0x93, 0xC3, 0x81, 0x4C, 0xD8, 0x41, 0xB5, 0xC8, 0x29, 0x51, 0x12, 0x3D, + 0xA1, 0xA3, 0x0F, 0xFA, 0x15, 0x32, 0x54, 0xA2, 0x84, 0xA1, 0xB0, 0x09, 0xFA, 0x69, 0xDA, 0x44, + 0xCB, 0xC3, 0x84, 0x09, 0x2E, 0x71, 0xA4, 0x4B, 0x11, 0x64, 0xA3, 0xD0, 0xAC, 0xA0, 0xD5, 0x58, + 0xEA, 0x83, 0x93, 0xA3, 0xD2, 0x94, 0xB6, 0xB9, 0x32, 0x86, 0x74, 0x00, 0xEE, 0x92, 0x20, 0x58, + 0x5B, 0x1F, 0x31, 0xA8, 0x3E, 0x78, 0x1E, 0x1D, 0x6F, 0xA3, 0x95, 0x56, 0x6F, 0x0B, 0xB5, 0x48, + 0xE4, 0x30, 0xCD, 0xB4, 0x7A, 0x5C, 0x35, 0x71, 0xF1, 0x72, 0xB7, 0x8A, 0x29, 0xA3, 0x76, 0x1B, + 0xBD, 0x60, 0x01, 0xEE, 0x1B, 0x41, 0xB8, 0xB6, 0x56, 0x04, 0x20, 0x44, 0x68, 0x7E, 0xB4, 0x37, + 0x8D, 0x44, 0xA4, 0x7C, 0x03, 0xFA, 0x08, 0x8C, 0x70, 0xCE, 0x9E, 0x85, 0x5A, 0x5B, 0x23, 0x31, + 0x28, 0xD4, 0x03, 0xD1, 0xF1, 0xDE, 0xB4, 0x22, 0x91, 0xF3, 0x2D, 0xE8, 0x65, 0x46, 0x4C, 0xDB, + 0x70, 0x3E, 0x93, 0xD1, 0x08, 0x12, 0xD6, 0xFA, 0xBA, 0x49, 0x80, 0x83, 0x7E, 0xD8, 0xB9, 0x76, + 0x45, 0xCF, 0xD7, 0xAE, 0xCD, 0x53, 0xE8, 0x36, 0x2F, 0xD0, 0xD3, 0xD9, 0x9B, 0x4F, 0x52, 0x13, + 0x3A, 0x24, 0x62, 0x47, 0xFA, 0xE0, 0x47, 0x2F, 0xA2, 0x73, 0xF3, 0x02, 0xE3, 0x47, 0x32, 0xA6, + 0x73, 0xC0, 0xDB, 0x54, 0x3B, 0xAF, 0x7C, 0x63, 0x45, 0x37, 0x19, 0x6E, 0x53, 0x7C, 0x7D, 0x20, + 0x96, 0xF6, 0xB3, 0xED, 0x6E, 0xCE, 0x4C, 0x1F, 0x09, 0x21, 0xC4, 0xDD, 0x0E, 0x0B, 0x94, 0xA4, + 0xCF, 0xE1, 0x60, 0x3B, 0x24, 0x27, 0x38, 0x5E, 0x9D, 0xD9, 0xC6, 0xD7, 0x50, 0x6E, 0x19, 0x8B, + 0xE1, 0xDA, 0x6E, 0x01, 0x30, 0xFA, 0xE0, 0xD9, 0xAF, 0xCF, 0xD7, 0x0E, 0x52, 0x6C, 0x25, 0xB5, + 0x8A, 0x85, 0xC7, 0xF3, 0x11, 0xD8, 0x59, 0x66, 0xA2, 0x48, 0xED, 0x39, 0x55, 0x27, 0x8B, 0x14, + 0x7C, 0x09, 0x02, 0xE9, 0xC2, 0x93, 0x2E, 0xB1, 0x59, 0x8D, 0xC7, 0xFB, 0x8B, 0x60, 0x40, 0xC4, + 0xE7, 0xB1, 0x61, 0xAF, 0x9F, 0x57, 0x04, 0x20, 0xD5, 0x94, 0xF6, 0x0A, 0x8E, 0x76, 0xA5, 0x2E, + 0xD6, 0xED, 0xDE, 0x74, 0xC6, 0xB9, 0xDE, 0xB7, 0xE2, 0x80, 0x90, 0xA9, 0x67, 0xAD, 0x3F, 0x0D, + 0xC4, 0xE1, 0xF4, 0x01, 0x68, 0xED, 0x1D, 0x1C, 0xAC, 0x9D, 0x65, 0x04, 0x82, 0x7B, 0x4E, 0x2F, + 0xCF, 0xE6, 0xA1, 0xB7, 0x4D, 0x66, 0xB9, 0x9E, 0xBB, 0xEE, 0x6A, 0x9B, 0xB4, 0x72, 0xE9, 0x78, + 0x73, 0x6B, 0x73, 0x0C, 0x90, 0x53, 0x7E, 0x1A, 0x8D, 0x6C, 0x73, 0xF3, 0xAC, 0x04, 0x19, 0xE5, + 0xB5, 0x37, 0xAD, 0x08, 0x7F, 0xCF, 0x51, 0x9C, 0x98, 0xEB, 0x07, 0x08, 0x62, 0x82, 0x16, 0xAF, + 0x2E, 0xB5, 0xEB, 0xAB, 0x1F, 0xAF, 0x7F, 0xFA, 0xB0, 0x9B, 0xE8, 0x00, 0x7D, 0xEE, 0x29, 0x30, + 0x20, 0xB7, 0xFB, 0x8E, 0x09, 0x40, 0x44, 0x6F, 0x13, 0x3D, 0xF5, 0x98, 0xA2, 0x5E, 0x5C, 0xBF, + 0xDF, 0x95, 0x96, 0x7A, 0xFB, 0x53, 0x53, 0xEF, 0x6B, 0xD0, 0xD3, 0x67, 0x87, 0xDC, 0x10, 0x67, + 0x03, 0x5D, 0x31, 0x40, 0xD4, 0x97, 0xF6, 0x16, 0x8F, 0xF6, 0x36, 0x90, 0x8B, 0x48, 0xF9, 0x06, + 0x86, 0x71, 0x60, 0x15, 0x9F, 0x29, 0xD1, 0x9B, 0x38, 0x0F, 0x83, 0xD4, 0x07, 0x57, 0xCB, 0x99, + 0x17, 0xCC, 0xFD, 0x8A, 0x09, 0x55, 0xAD, 0x91, 0xCE, 0x56, 0x0A, 0x11, 0xA4, 0x30, 0x8D, 0x74, + 0xB8, 0x42, 0x70, 0x91, 0x44, 0x5A, 0x3F, 0xEB, 0xDF, 0xA9, 0x56, 0x10, 0xF9, 0x7D, 0x2A, 0x66, + 0xBC, 0x41, 0xDE, 0x19, 0x63, 0xDE, 0x79, 0x75, 0xB9, 0x9B, 0x50, 0x36, 0xDE, 0x5B, 0xC2, 0x19, + 0xEF, 0x35, 0xE1, 0x68, 0x7C, 0x0D, 0x5B, 0x48, 0x61, 0xC3, 0x41, 0x04, 0x07, 0x84, 0xB1, 0xF3, + 0x26, 0x03, 0x08, 0xC9, 0x73, 0xBA, 0xCB, 0x6D, 0x5C, 0x47, 0x90, 0x91, 0xF4, 0x9C, 0xA3, 0xD8, + 0x6F, 0x8E, 0xEF, 0xD4, 0x6B, 0x8E, 0x4A, 0xA9, 0xDD, 0xC6, 0x69, 0x90, 0x13, 0x93, 0xD8, 0x0E, + 0x6E, 0x65, 0x5E, 0x57, 0x21, 0x12, 0x2C, 0xD3, 0x89, 0x76, 0xC9, 0xCE, 0xB6, 0xD1, 0x4D, 0x6F, + 0x1B, 0xDD, 0xC8, 0x14, 0x25, 0xD5, 0x73, 0x72, 0x4F, 0x99, 0xA6, 0xDB, 0x3B, 0xBD, 0x4F, 0xF5, + 0x0C, 0x67, 0xEB, 0xC7, 0x34, 0x80, 0xD1, 0x07, 0xCF, 0xDF, 0xEF, 0x26, 0xA6, 0x61, 0x67, 0x15, + 0x63, 0xDA, 0x56, 0x11, 0x8C, 0x32, 0xB5, 0xEF, 0x52, 0x6C, 0xB1, 0x81, 0x36, 0x16, 0x48, 0xF8, + 0xAF, 0x3B, 0xD2, 0xC6, 0xA2, 0xBA, 0x36, 0xEE, 0x38, 0xC3, 0x2C, 0xBE, 0x06, 0xFD, 0xF8, 0xC6, + 0xE2, 0xF3, 0x78, 0x6A, 0xAC, 0xAD, 0x23, 0x0E, 0xA7, 0x0F, 0x3E, 0x18, 0x0B, 0xED, 0xD5, 0xBB, + 0x67, 0x3B, 0xD1, 0x95, 0xE8, 0x74, 0x3F, 0xFA, 0x8A, 0x58, 0xDE, 0xB7, 0xCE, 0x1C, 0xE2, 0xAE, + 0xEF, 0x54, 0x08, 0xA4, 0x0F, 0xDE, 0x12, 0x37, 0xD0, 0x2E, 0x3D, 0x9F, 0xBF, 0x76, 0x6E, 0x27, + 0x5A, 0xA3, 0x3D, 0xEF, 0x47, 0x65, 0x8C, 0xE9, 0x7D, 0xEB, 0x6B, 0x32, 0xB5, 0x7D, 0xDF, 0xF3, + 0xD7, 0x56, 0x19, 0x87, 0xD3, 0x07, 0xAF, 0x5B, 0xEF, 0xE8, 0xD1, 0x4E, 0xD4, 0x25, 0x7A, 0xDD, + 0x8F, 0xC6, 0x22, 0x9E, 0xF7, 0xAD, 0xB4, 0x9B, 0x91, 0x63, 0xCF, 0xD6, 0x56, 0x19, 0x85, 0xD2, + 0x07, 0x1F, 0x5B, 0x2F, 0xE1, 0xEF, 0x4E, 0xD4, 0xC5, 0x7A, 0xDC, 0x8F, 0xB2, 0x38, 0xB7, 0xFB, + 0x56, 0x95, 0x65, 0x2E, 0xD6, 0x56, 0x14, 0xC0, 0xE8, 0x83, 0x17, 0x97, 0xBF, 0x6A, 0xF5, 0x17, + 0xDE, 0xC2, 0xC5, 0x07, 0x2E, 0xB5, 0xAB, 0x1F, 0x1B, 0x3B, 0xD1, 0x18, 0x76, 0xBD, 0x1F, 0x7D, + 0x51, 0xA6, 0xF7, 0xAD, 0x2D, 0xBA, 0xAF, 0x66, 0x68, 0xAC, 0x1F, 0x0E, 0x05, 0x20, 0x3E, 0xFB, + 0x02, 0x47, 0xDA, 0x73, 0x63, 0x37, 0x01, 0x31, 0xEA, 0x77, 0x17, 0x45, 0x7B, 0xCC, 0xE4, 0xBE, + 0xF5, 0xE4, 0x10, 0xAB, 0x82, 0x8A, 0x92, 0x25, 0x86, 0xF5, 0x19, 0xB7, 0xA8, 0xE0, 0xD6, 0xCD, + 0x15, 0xD4, 0x1A, 0x57, 0x2F, 0xB4, 0x37, 0xE2, 0xB4, 0x02, 0x37, 0x1B, 0xCF, 0xD9, 0xE5, 0x0D, + 0x6D, 0x93, 0xF4, 0x24, 0x07, 0xB7, 0xBD, 0xE3, 0xE3, 0xED, 0x86, 0xB7, 0x79, 0xD3, 0xA8, 0xC7, + 0xC7, 0xF7, 0xA8, 0x93, 0x91, 0x61, 0x92, 0xCF, 0x16, 0x09, 0x37, 0x79, 0x18, 0x46, 0x82, 0xD5, + 0x07, 0x2F, 0xE1, 0x44, 0x7B, 0x41, 0x4F, 0x76, 0x55, 0x06, 0xCA, 0xFD, 0xEF, 0xC2, 0x93, 0x12, + 0xFC, 0xEE, 0xDB, 0x99, 0x28, 0x31, 0x50, 0x74, 0x7B, 0x63, 0x77, 0xA3, 0xBD, 0x05, 0x09, 0x70, + 0xAE, 0xBE, 0x0F, 0xEC, 0x7C, 0xB7, 0x0A, 0x8C, 0x89, 0xD8, 0x99, 0x0E, 0x25, 0xBE, 0x77, 0xA1, + 0x46, 0x79, 0x83, 0x11, 0x7F, 0x33, 0x67, 0x99, 0xA6, 0xF8, 0x46, 0x17, 0x3A, 0x9D, 0x46, 0xC2, + 0x56, 0x10, 0xDA, 0x8E, 0xA3, 0x0F, 0x5E, 0x91, 0x50, 0xBB, 0xC6, 0xC3, 0x8A, 0x3B, 0x5B, 0x24, + 0x2C, 0x62, 0x5B, 0x5B, 0xE8, 0x13, 0x63, 0xAA, 0x0F, 0xAE, 0xF1, 0x9D, 0xA5, 0x80, 0x0B, 0xCF, + 0xD6, 0x47, 0x46, 0x85, 0x48, 0x5C, 0xDF, 0x03, 0xA2, 0x22, 0x25, 0xF1, 0x77, 0xA1, 0xE9, 0x9A, + 0x38, 0x92, 0xAE, 0x0D, 0xAE, 0x68, 0x63, 0x0D, 0xAD, 0xAC, 0xBC, 0xBB, 0xCA, 0x5B, 0x6E, 0xE8, + 0x1E, 0x3B, 0xDC, 0x34, 0x97, 0x7C, 0xA3, 0x31, 0x68, 0x95, 0xED, 0xA0, 0x1D, 0x9C, 0x07, 0x33, + 0xC3, 0x15, 0xCD, 0xE8, 0xF6, 0xD2, 0x05, 0xDF, 0x2F, 0x38, 0xF4, 0x1C, 0x0B, 0x1A, 0x3E, 0xB3, + 0x6E, 0xF0, 0xED, 0x4E, 0x96, 0x76, 0x1D, 0xED, 0x7C, 0x43, 0x10, 0x30, 0x0B, 0x81, 0xA1, 0x44, + 0xB7, 0x13, 0x5F, 0xA0, 0x67, 0x7B, 0x14, 0xF1, 0x7D, 0x38, 0x05, 0xCA, 0xCD, 0xD9, 0xAC, 0xE7, + 0x93, 0x71, 0x24, 0x48, 0xD5, 0x1E, 0x4E, 0xE5, 0xD6, 0xBD, 0x0F, 0x64, 0x6C, 0x07, 0x40, 0xA3, + 0x06, 0x66, 0x71, 0x48, 0xB7, 0x3B, 0x31, 0x53, 0xAE, 0xB6, 0x95, 0x4E, 0xEE, 0x92, 0x6F, 0x04, + 0x56, 0x6E, 0x90, 0x5C, 0xAB, 0x62, 0x4C, 0x6F, 0x67, 0x4C, 0x62, 0x2C, 0x33, 0xFA, 0x87, 0xAD, + 0xD6, 0xA4, 0x8F, 0x1B, 0xB7, 0x34, 0xC1, 0xDA, 0xF9, 0xE1, 0xA4, 0x5F, 0xB6, 0xE7, 0xA8, 0x74, + 0xD7, 0x1D, 0x70, 0xBA, 0xF1, 0xA6, 0x3B, 0x94, 0xD2, 0x00, 0xA8, 0x69, 0x6A, 0xEF, 0x8C, 0xE0, + 0x4B, 0x53, 0xFB, 0x88, 0xF9, 0x7D, 0x87, 0x7B, 0xEF, 0x90, 0x76, 0xC3, 0xB2, 0xFC, 0xDC, 0xFD, + 0x77, 0xFD, 0xC4, 0xFE, 0xBB, 0x13, 0xB1, 0xFF, 0x4E, 0x9A, 0x69, 0x5F, 0x76, 0xBB, 0xDD, 0x2A, + 0x9C, 0x57, 0xDC, 0x82, 0x77, 0x27, 0x2C, 0x4D, 0x41, 0x98, 0x15, 0x59, 0xEA, 0x0B, 0x96, 0xFA, + 0x12, 0x4B, 0xA7, 0x77, 0xB9, 0xA9, 0xF0, 0x4E, 0x38, 0xE2, 0xEB, 0xB8, 0x5F, 0x09, 0x4B, 0x95, + 0xF6, 0x49, 0x52, 0xDB, 0xBE, 0xAB, 0x6D, 0x92, 0xB4, 0x49, 0x3A, 0x18, 0x1E, 0x17, 0xC6, 0x42, + 0x0A, 0xC2, 0x7C, 0xFE, 0xD5, 0x5D, 0xFA, 0xFC, 0x78, 0x0B, 0x9F, 0x1F, 0x67, 0x7C, 0x7E, 0x87, + 0xCE, 0x2E, 0x08, 0xFF, 0xC6, 0x1C, 0x5E, 0xB0, 0xB5, 0x86, 0xD3, 0x2B, 0xD9, 0xDA, 0xAD, 0x87, + 0x44, 0x96, 0xF0, 0xEA, 0x2E, 0x3D, 0x24, 0xC7, 0x6E, 0x37, 0x32, 0x52, 0x1E, 0x73, 0x06, 0xBB, + 0xC9, 0x49, 0xB4, 0x92, 0x92, 0xD5, 0xC9, 0x7B, 0xC7, 0x8D, 0x86, 0x47, 0x7D, 0x5E, 0x36, 0xDD, + 0x85, 0x7A, 0xAA, 0xEF, 0xC7, 0xCE, 0x6D, 0x72, 0x37, 0x45, 0x19, 0xBE, 0x11, 0x61, 0x26, 0x55, + 0xB8, 0x95, 0x0B, 0xB3, 0xCB, 0xB7, 0x7F, 0x5F, 0xAF, 0x16, 0x4B, 0xF7, 0xB4, 0xBB, 0x7A, 0x6C, + 0x33, 0x6B, 0x95, 0x05, 0xC6, 0x69, 0x87, 0x88, 0x83, 0x6F, 0x26, 0xE8, 0x7D, 0x8A, 0x38, 0x57, + 0x8C, 0x0D, 0xA5, 0xA0, 0x10, 0x81, 0xE5, 0x0D, 0xFA, 0x68, 0x20, 0xE4, 0x73, 0x96, 0x70, 0x2C, + 0xE2, 0x9A, 0xE6, 0x8D, 0x46, 0xF4, 0x73, 0x57, 0x8F, 0x31, 0x60, 0x04, 0x5F, 0xF0, 0x7A, 0xA7, + 0x1B, 0x91, 0xA4, 0x1A, 0xF2, 0xC5, 0x14, 0x46, 0xB4, 0x51, 0x13, 0xE3, 0x86, 0x76, 0x67, 0x22, + 0x38, 0x62, 0x22, 0x78, 0xF1, 0xE6, 0xA3, 0x4A, 0x06, 0xCC, 0xD7, 0x3A, 0x59, 0x11, 0x1C, 0x6D, + 0xFE, 0x6E, 0x85, 0x6E, 0x65, 0x69, 0x75, 0x62, 0x69, 0x1D, 0x8D, 0xE2, 0x2D, 0xA2, 0xDB, 0x84, + 0x2C, 0x85, 0x04, 0x8E, 0xD9, 0x43, 0xE0, 0xDA, 0x7B, 0xD9, 0x03, 0x2A, 0xD9, 0xC1, 0xF1, 0x3A, + 0x76, 0x60, 0x1D, 0x6D, 0x61, 0x06, 0xC7, 0x39, 0x66, 0x70, 0x57, 0x32, 0xE8, 0xEB, 0x83, 0xF7, + 0x9B, 0x98, 0x41, 0xBF, 0xA2, 0x19, 0x1C, 0x09, 0x33, 0x88, 0xF7, 0x0F, 0xF7, 0xAB, 0x0A, 0x4B, + 0xB2, 0x82, 0xC7, 0x23, 0x7C, 0x6C, 0xE6, 0x71, 0x35, 0x4F, 0xD8, 0x5D, 0xCC, 0x5D, 0xD8, 0xEE, + 0xFA, 0xF1, 0xF6, 0x57, 0xDB, 0xB5, 0xBC, 0xC5, 0x7A, 0x21, 0x57, 0xEE, 0xE8, 0x6B, 0x0F, 0xB7, + 0xEB, 0x8D, 0x5A, 0x71, 0x66, 0xA7, 0xB5, 0xC4, 0xCA, 0xDE, 0x0D, 0x3C, 0x5F, 0xCB, 0xBE, 0x39, + 0x24, 0xB1, 0x01, 0x51, 0xB4, 0xAE, 0x56, 0x04, 0x64, 0xB7, 0x5C, 0xBC, 0x79, 0xA9, 0x6D, 0xF0, + 0x5A, 0x07, 0x05, 0xB2, 0x2E, 0x7B, 0xF9, 0x85, 0xB6, 0xC1, 0xDB, 0x2F, 0x14, 0xD8, 0x72, 0xB6, + 0xA8, 0xE0, 0x8B, 0x48, 0xB4, 0xCD, 0xDE, 0x44, 0x52, 0xBA, 0x5B, 0x83, 0xB5, 0xDA, 0x3C, 0xA5, + 0x44, 0xE3, 0x32, 0xE6, 0xAD, 0x50, 0x63, 0x55, 0xDB, 0x62, 0x4F, 0x71, 0x4A, 0x06, 0xC0, 0xC1, + 0x97, 0x74, 0x37, 0x4B, 0x40, 0xAA, 0x6D, 0x4A, 0x4D, 0x13, 0xB6, 0x46, 0x65, 0xF8, 0xE9, 0x4C, + 0x0A, 0x66, 0x51, 0xE7, 0x6B, 0x06, 0xB3, 0xB8, 0xCE, 0x07, 0x63, 0xDA, 0xFB, 0xE0, 0xE5, 0x9F, + 0x0A, 0x96, 0x56, 0x9B, 0xB3, 0x74, 0x74, 0x57, 0x2C, 0x6D, 0x91, 0xAA, 0x22, 0xEB, 0x0A, 0xBD, + 0xD0, 0x70, 0x36, 0x36, 0x2E, 0x06, 0x0D, 0xB6, 0xC5, 0x62, 0xAE, 0x76, 0x0D, 0xAC, 0xEE, 0xD4, + 0xC0, 0x04, 0x01, 0xD5, 0x94, 0xD1, 0xCF, 0x2A, 0xE3, 0xF4, 0x6B, 0xB3, 0x2F, 0xC6, 0x51, 0x55, + 0xF3, 0x52, 0x70, 0x74, 0xF2, 0x35, 0x99, 0x97, 0x37, 0x0F, 0xF1, 0xEA, 0xC6, 0xC1, 0x8B, 0x81, + 0x63, 0xF0, 0xA2, 0x47, 0xBB, 0x37, 0xB0, 0x88, 0x82, 0x8D, 0xF5, 0x71, 0x74, 0xA7, 0xAF, 0x3C, + 0xBB, 0x8B, 0x08, 0xC6, 0x58, 0xDA, 0xC2, 0xC4, 0x7A, 0xFD, 0x1D, 0x9A, 0x98, 0xB4, 0xD0, 0xC4, + 0xF3, 0x20, 0x2F, 0x60, 0x74, 0xBE, 0x36, 0x10, 0x17, 0x34, 0xEB, 0xAC, 0x24, 0xA9, 0xB3, 0xF2, + 0xF9, 0x21, 0x14, 0x85, 0x59, 0x04, 0x39, 0x74, 0x9E, 0xB3, 0x2F, 0x27, 0xAA, 0x3B, 0x8C, 0xDF, + 0x74, 0x48, 0x97, 0xD5, 0xE2, 0x77, 0xEA, 0x46, 0x85, 0x66, 0xFA, 0x5D, 0xBB, 0xA5, 0x6F, 0x15, + 0x3C, 0x37, 0xF8, 0x2B, 0x38, 0x6E, 0x08, 0x5F, 0x03, 0xD4, 0x26, 0x3E, 0x19, 0x5D, 0xE8, 0xDF, + 0x45, 0x38, 0xB9, 0xB4, 0xB0, 0x89, 0xAE, 0x41, 0x48, 0x76, 0x1D, 0xCF, 0xC0, 0x62, 0xD5, 0x98, + 0x85, 0x40, 0x69, 0xFB, 0x8F, 0x19, 0x4E, 0xF2, 0x1A, 0xF8, 0xBE, 0x06, 0xA3, 0xDA, 0x4A, 0x33, + 0x7D, 0x3B, 0x2F, 0x7F, 0xB0, 0x06, 0x0F, 0xA3, 0x35, 0xC3, 0xFF, 0xF9, 0xEF, 0xB2, 0xA9, 0x19, + 0xFC, 0x7E, 0x66, 0x2C, 0x00, 0x30, 0x23, 0xDF, 0xBC, 0xD0, 0x81, 0x52, 0xDF, 0x0B, 0xA0, 0x14, + 0xB5, 0xC7, 0x76, 0x8E, 0xAA, 0xF2, 0xA4, 0x7D, 0xA8, 0x12, 0x77, 0xAA, 0xB1, 0x62, 0x6C, 0x72, + 0x1E, 0x98, 0xBE, 0x3D, 0x83, 0x52, 0xCD, 0xF2, 0xCC, 0xF9, 0x94, 0xB8, 0x61, 0xDB, 0xB0, 0xAC, + 0xAB, 0x1B, 0x38, 0x78, 0x8B, 0x33, 0xCC, 0x20, 0xF9, 0x7A, 0xED, 0xC5, 0x4F, 0xEF, 0x2E, 0xD9, + 0x3B, 0x2B, 0xDF, 0x82, 0xBC, 0x88, 0x55, 0x6B, 0x6A, 0xA3, 0xB9, 0xCB, 0xAA, 0xF7, 0x3A, 0xC1, + 0xB6, 0xEC, 0x3B, 0xA6, 0x37, 0x86, 0xAF, 0x0D, 0x8D, 0x80, 0xBC, 0xF6, 0x82, 0x50, 0xBB, 0xD0, + 0x22, 0x8C, 0x8E, 0x67, 0xD2, 0x77, 0xA2, 0xB4, 0x19, 0x5F, 0xBC, 0x25, 0x63, 0xFC, 0x17, 0xDF, + 0x81, 0xA6, 0x11, 0xD4, 0x81, 0x56, 0x3B, 0x3B, 0xED, 0xD6, 0xD0, 0xFE, 0xA2, 0x2E, 0x46, 0xF8, + 0x65, 0x52, 0x68, 0x57, 0x9F, 0xFB, 0x4E, 0x53, 0x33, 0x87, 0x0D, 0xF6, 0x9E, 0x51, 0x7A, 0x19, + 0xAF, 0x89, 0x17, 0x50, 0xB7, 0xC3, 0x09, 0x71, 0xEB, 0x31, 0x65, 0xE0, 0x0C, 0x33, 0xCF, 0x0D, + 0x12, 0x1F, 0x59, 0xB5, 0x47, 0xF1, 0xF5, 0x36, 0x14, 0xF4, 0xE1, 0x3C, 0xD0, 0x1E, 0x5E, 0x5C, + 0x68, 0x58, 0xE0, 0x26, 0xDE, 0x5F, 0x6A, 0x0E, 0xD3, 0xED, 0x9A, 0x5A, 0xEA, 0xC2, 0xCF, 0x10, + 0x1A, 0xA4, 0x37, 0x65, 0xDF, 0x6A, 0xC4, 0x49, 0xBD, 0xAA, 0x39, 0x02, 0xC0, 0x28, 0x52, 0x6F, + 0x24, 0x09, 0xAC, 0x5B, 0x46, 0x68, 0x34, 0x92, 0xEF, 0x4C, 0x85, 0x5E, 0x81, 0x92, 0xA6, 0x46, + 0x6F, 0xC9, 0x2F, 0x70, 0xBD, 0x6D, 0xB4, 0x41, 0x86, 0xC0, 0x6F, 0x04, 0x4D, 0x7C, 0x3F, 0xFD, + 0xF5, 0x58, 0x80, 0x6E, 0x75, 0x9B, 0x1A, 0xDE, 0x49, 0xC2, 0x4A, 0x44, 0x3E, 0x10, 0xD7, 0x84, + 0xD0, 0x8A, 0xD1, 0x2A, 0x50, 0x32, 0x74, 0xB7, 0x09, 0x15, 0x41, 0xEC, 0xF9, 0x40, 0xC6, 0x20, + 0xB1, 0x71, 0x93, 0x0F, 0xA0, 0x9B, 0x74, 0xF4, 0xDC, 0x64, 0x41, 0x51, 0xD2, 0xDA, 0xE1, 0x21, + 0xB8, 0x34, 0x04, 0x25, 0x02, 0x56, 0x31, 0xAE, 0xD7, 0xF8, 0x02, 0x26, 0x58, 0x54, 0xAD, 0xB3, + 0xAC, 0x1D, 0x00, 0x82, 0x76, 0xE8, 0x5D, 0x87, 0xBE, 0xED, 0x8E, 0x61, 0xE8, 0xD1, 0x88, 0xB1, + 0xD1, 0xDB, 0x88, 0x32, 0x75, 0x9F, 0x5E, 0xA7, 0x9D, 0xA4, 0x6F, 0xD4, 0xF9, 0xF5, 0x83, 0x5A, + 0xA3, 0xC6, 0x89, 0xA7, 0xE7, 0x60, 0x6E, 0x75, 0x76, 0xF0, 0x88, 0xD2, 0xD8, 0xD0, 0xCE, 0xCF, + 0x79, 0x37, 0xAC, 0x15, 0x5E, 0x84, 0x46, 0xF4, 0x4F, 0xEA, 0x56, 0x64, 0x8A, 0xBF, 0x7F, 0xFF, + 0x97, 0xB0, 0xD9, 0xDB, 0x43, 0xA0, 0xFA, 0x29, 0xCE, 0x20, 0x7C, 0xFF, 0x17, 0xFC, 0xFF, 0xF6, + 0x11, 0x9D, 0x36, 0xF8, 0xFE, 0x2F, 0xFC, 0x73, 0xFB, 0x08, 0x7A, 0x82, 0x63, 0xDA, 0xDF, 0xED, + 0xEF, 0x54, 0x0E, 0x59, 0xE9, 0x8D, 0x73, 0xA5, 0x17, 0x89, 0x6D, 0x6D, 0x9A, 0xC6, 0x05, 0x44, + 0xFD, 0x1E, 0xFB, 0x6F, 0xDD, 0xF4, 0x2C, 0x50, 0x4F, 0x08, 0x96, 0x2C, 0x94, 0xEE, 0x80, 0x4A, + 0x84, 0xA0, 0xA2, 0x97, 0x08, 0xDB, 0x23, 0xDA, 0x52, 0xE3, 0xAE, 0x12, 0x1B, 0x88, 0x68, 0x39, + 0x33, 0xFC, 0x80, 0xBC, 0x71, 0xC3, 0x7A, 0x98, 0x70, 0x8A, 0x1C, 0x89, 0x0F, 0x06, 0x09, 0x16, + 0xF0, 0x07, 0x70, 0xD0, 0xAE, 0xC6, 0x95, 0x16, 0x19, 0xDB, 0x83, 0xC8, 0x0E, 0x63, 0x4A, 0xD9, + 0xCD, 0x1C, 0x3B, 0xFC, 0x64, 0x3A, 0x5F, 0xEA, 0xF8, 0x5A, 0xD3, 0x74, 0xA8, 0xC8, 0x88, 0x08, + 0x1B, 0x3D, 0xC5, 0xFF, 0x81, 0x5C, 0xF0, 0x4F, 0xAE, 0x7E, 0x00, 0x2B, 0x2B, 0xE1, 0xEB, 0x74, + 0x0A, 0xE0, 0xF3, 0xB2, 0xA9, 0xB1, 0x83, 0x15, 0x78, 0x86, 0x6B, 0xE1, 0x39, 0xFE, 0x59, 0x09, + 0xED, 0xE1, 0x05, 0x7E, 0x04, 0xD7, 0x68, 0xCD, 0x8A, 0x97, 0xD8, 0x01, 0xB6, 0xA2, 0x35, 0x06, + 0x6D, 0xC5, 0x8E, 0xE0, 0x1A, 0xBE, 0xE2, 0x07, 0x6C, 0xB7, 0xA9, 0x0D, 0x6D, 0xD7, 0xA5, 0x07, + 0x25, 0xD4, 0xC7, 0xA9, 0xFE, 0x69, 0xB0, 0x04, 0x0E, 0x38, 0x69, 0xB7, 0x8F, 0x82, 0x55, 0x74, + 0xB6, 0xBA, 0x7D, 0x44, 0xF0, 0x1E, 0x25, 0x12, 0x8E, 0x57, 0xFC, 0x18, 0xAE, 0x03, 0x7D, 0x78, + 0x47, 0x10, 0x4C, 0x2F, 0xAC, 0xE2, 0x0B, 0xD0, 0x22, 0xC4, 0xFB, 0x9C, 0x78, 0x38, 0x5B, 0x45, + 0x67, 0x08, 0x4D, 0x61, 0x39, 0x1B, 0x70, 0xBA, 0x8A, 0x4F, 0xE1, 0x2E, 0x7D, 0x5D, 0x11, 0x12, + 0xC1, 0x78, 0xBA, 0x7D, 0xC4, 0x79, 0x82, 0x4B, 0xFC, 0x28, 0x2D, 0x6A, 0x8C, 0x09, 0x21, 0x8F, + 0x22, 0xCF, 0x59, 0x92, 0x96, 0xF2, 0x07, 0xF8, 0xC7, 0x95, 0x43, 0xF0, 0xF0, 0xF9, 0xEA, 0x8D, + 0x55, 0xAF, 0xF1, 0x05, 0xD9, 0x1A, 0xC6, 0x30, 0x19, 0xA6, 0xED, 0xB9, 0xA6, 0x63, 0x9B, 0xE8, + 0x28, 0xF5, 0x86, 0x76, 0x31, 0xE0, 0x71, 0x0C, 0x0D, 0x1A, 0x9A, 0xCB, 0x46, 0x9A, 0x8B, 0x5A, + 0x2C, 0x29, 0xD6, 0x1A, 0x6D, 0x6A, 0x87, 0xDC, 0xD6, 0x10, 0x05, 0x77, 0xC1, 0x6A, 0x38, 0xB0, + 0xB1, 0x02, 0x47, 0xC6, 0x5B, 0x0A, 0x91, 0xD0, 0xD6, 0x12, 0x16, 0x8A, 0x46, 0x0E, 0xB5, 0x9D, + 0x54, 0x94, 0x2D, 0xF0, 0x6A, 0xE1, 0xC0, 0x0F, 0xD3, 0x0E, 0x0C, 0xAA, 0xF2, 0xC3, 0x7A, 0xED, + 0x0A, 0x9F, 0xFB, 0xFF, 0xAD, 0x76, 0x80, 0x8D, 0x0E, 0x6A, 0xFF, 0x3A, 0xD3, 0x6A, 0x07, 0xB2, + 0x27, 0xDF, 0xA6, 0x5D, 0x8E, 0x69, 0x6C, 0x5C, 0x51, 0x63, 0x63, 0x49, 0x63, 0xE3, 0xBB, 0xD5, + 0x98, 0xBC, 0x10, 0xBC, 0x8D, 0xD6, 0xE4, 0x95, 0xD7, 0x02, 0xCD, 0x95, 0xC2, 0x73, 0xA5, 0x71, + 0x6D, 0x8D, 0x55, 0xDA, 0xDA, 0x44, 0x4D, 0x2C, 0xC5, 0x81, 0xF7, 0x10, 0xFF, 0xF5, 0xCF, 0xEF, + 0xDE, 0x62, 0xA8, 0x54, 0xAB, 0x2C, 0xD2, 0x58, 0xBA, 0x1C, 0x51, 0x60, 0xC0, 0xDC, 0x99, 0x08, + 0xDC, 0x89, 0x1C, 0x7A, 0x50, 0xD3, 0xEA, 0x14, 0x25, 0x66, 0xD0, 0x12, 0x43, 0xE0, 0x81, 0xB7, + 0x9A, 0xEF, 0x62, 0xB0, 0x15, 0xCE, 0x1B, 0x43, 0x15, 0xD8, 0x02, 0x02, 0x54, 0x52, 0x22, 0xC3, + 0x9C, 0x71, 0x18, 0x29, 0x27, 0xEC, 0xDC, 0x45, 0xA8, 0xBF, 0x06, 0x55, 0x83, 0x9A, 0x88, 0xE9, + 0x71, 0x6C, 0x0B, 0x4A, 0xA5, 0xC3, 0x23, 0x7F, 0x25, 0x01, 0xF1, 0x39, 0x6C, 0x85, 0x81, 0x8B, + 0x4C, 0x50, 0x09, 0x8D, 0x98, 0xBA, 0xCC, 0xC7, 0xB3, 0x5A, 0x07, 0xCF, 0x4A, 0x81, 0x87, 0x67, + 0x9E, 0x4A, 0x68, 0xF8, 0x44, 0x57, 0x2E, 0x96, 0x6A, 0xC4, 0xF0, 0xC9, 0x25, 0x15, 0x4F, 0x3C, + 0xD3, 0x55, 0xE3, 0x89, 0x4F, 0x8A, 0xE4, 0xE3, 0xA9, 0x28, 0x1B, 0x3E, 0x13, 0xA1, 0xB0, 0xE7, + 0x74, 0x35, 0xD2, 0x11, 0xFF, 0x6D, 0x5E, 0x7F, 0x8C, 0x0C, 0x88, 0x16, 0xF1, 0x9F, 0xBD, 0x78, + 0xC9, 0xF8, 0xA3, 0xA8, 0x16, 0x89, 0xA3, 0xCC, 0x06, 0xC4, 0x69, 0x1B, 0x21, 0xC4, 0x27, 0x18, + 0xC7, 0x93, 0xA0, 0x8D, 0x15, 0x6E, 0x24, 0xC6, 0xCC, 0xAD, 0xB6, 0x0B, 0x04, 0x50, 0x84, 0x8D, + 0xB3, 0x4E, 0xDA, 0x3C, 0x33, 0xB8, 0xD8, 0xE5, 0x3C, 0x74, 0xEC, 0x6E, 0x0E, 0x46, 0x9E, 0x61, + 0x92, 0x10, 0x78, 0x31, 0x0F, 0x1B, 0x1D, 0xC5, 0x48, 0xB8, 0x7A, 0xC7, 0xC7, 0xD9, 0x3C, 0xC3, + 0x3B, 0xE0, 0x5F, 0x4F, 0x43, 0x0C, 0x38, 0x1F, 0x15, 0x0F, 0xCD, 0x4C, 0x28, 0x04, 0xB5, 0x9A, + 0x58, 0xB2, 0xAB, 0x9D, 0x65, 0x2A, 0x6E, 0x80, 0xE0, 0x8B, 0x70, 0xDA, 0x53, 0x46, 0x63, 0xE2, + 0x9B, 0x20, 0x43, 0x18, 0x7C, 0x47, 0x9F, 0xFE, 0x62, 0xC8, 0xE8, 0x3E, 0x8A, 0x08, 0x13, 0xBB, + 0x86, 0x03, 0xD7, 0xD4, 0x25, 0xB6, 0xB6, 0xD3, 0xF2, 0x5C, 0xA2, 0xEE, 0x35, 0x51, 0xBF, 0xF3, + 0x8E, 0xF8, 0x19, 0x7F, 0x38, 0x3D, 0x06, 0xF3, 0x49, 0x38, 0xF7, 0x5D, 0x5E, 0xCF, 0x67, 0xEB, + 0x1B, 0xE5, 0x50, 0x72, 0x87, 0xB6, 0x79, 0x78, 0xA8, 0x3D, 0x0B, 0x43, 0x03, 0x14, 0x80, 0xEB, + 0x94, 0x13, 0x94, 0x8F, 0x66, 0xF0, 0x49, 0x09, 0xCF, 0x47, 0xA3, 0x64, 0x0F, 0x15, 0x13, 0xE6, + 0xB7, 0xF8, 0xA5, 0x34, 0xE1, 0xCE, 0x14, 0x55, 0xFB, 0xDF, 0x73, 0xE2, 0xAF, 0xAE, 0xA9, 0xC0, + 0x3C, 0xFF, 0x99, 0xE3, 0xD4, 0x6B, 0xED, 0x78, 0xD9, 0xB9, 0xC6, 0xC6, 0xE0, 0x6D, 0x40, 0x75, + 0x05, 0x7D, 0x80, 0x8E, 0x63, 0x9B, 0x67, 0xDC, 0x44, 0x7A, 0x87, 0x71, 0xD7, 0x05, 0x57, 0x46, + 0x7A, 0xD0, 0x0F, 0x2D, 0x3C, 0xF7, 0x0B, 0x59, 0xCD, 0x67, 0x20, 0xFE, 0x78, 0x18, 0x9F, 0x9A, + 0x58, 0xE0, 0xD2, 0x21, 0x6D, 0x68, 0x79, 0xC9, 0x07, 0x72, 0xDD, 0x23, 0x45, 0xA3, 0x58, 0x05, + 0xD4, 0x3A, 0xD1, 0x13, 0xB3, 0x1F, 0x92, 0xB9, 0x7D, 0xA0, 0x3E, 0x53, 0x4C, 0x81, 0x70, 0x02, + 0xB9, 0xF0, 0x44, 0xF2, 0x4A, 0xF5, 0x90, 0x9A, 0x9E, 0xB8, 0x6D, 0x3C, 0x88, 0x23, 0xC3, 0x7C, + 0x66, 0x19, 0x21, 0x49, 0x06, 0x87, 0xC8, 0x16, 0xC4, 0xCD, 0xA9, 0x17, 0x92, 0x54, 0xC4, 0xB0, + 0x71, 0x6F, 0x86, 0xE1, 0x7C, 0x8C, 0xAD, 0xF1, 0x5E, 0xDD, 0x5F, 0xE1, 0xE3, 0x6B, 0xF8, 0x7F, + 0x66, 0x0E, 0xA2, 0xDA, 0xB8, 0x39, 0x63, 0x21, 0x51, 0x3C, 0x88, 0xAD, 0x44, 0x96, 0x43, 0x22, + 0x2C, 0xF0, 0xFB, 0xA2, 0xA7, 0x87, 0x0F, 0xE9, 0xD1, 0x83, 0x48, 0x69, 0x22, 0x7A, 0x5C, 0x68, + 0xF1, 0x8D, 0x94, 0x82, 0xB3, 0xB8, 0x53, 0x38, 0x04, 0x72, 0x09, 0x03, 0xF3, 0xAD, 0x48, 0xBD, + 0x33, 0xA8, 0x36, 0xD1, 0x16, 0xFE, 0x3F, 0xEA, 0x7F, 0x45, 0x51, 0xFF, 0xFE, 0x42, 0x7C, 0x81, + 0x6D, 0xA7, 0x3C, 0x80, 0xC1, 0xA9, 0xA7, 0x05, 0x0F, 0x6A, 0x50, 0xED, 0x28, 0xE7, 0xFD, 0x78, + 0xE8, 0x8E, 0xED, 0x6B, 0x62, 0x5B, 0x8C, 0xE8, 0xD8, 0xB2, 0x50, 0x46, 0x38, 0x7D, 0x8F, 0x13, + 0xDC, 0x38, 0xDB, 0x5D, 0xAF, 0xB1, 0xB5, 0x05, 0x1A, 0x8F, 0x6F, 0xE3, 0x92, 0x64, 0xE2, 0x2D, + 0x8A, 0x20, 0x7D, 0x88, 0x3A, 0x37, 0x24, 0x05, 0x1C, 0x41, 0xF3, 0xED, 0x3C, 0xA5, 0x5D, 0x8B, + 0x6D, 0x3F, 0x3C, 0x19, 0x40, 0x03, 0x71, 0x05, 0x40, 0x43, 0x9F, 0x7A, 0x8D, 0x84, 0x96, 0xB8, + 0x65, 0x58, 0x05, 0x59, 0x85, 0x88, 0x69, 0x99, 0x97, 0xC4, 0xCC, 0x42, 0xE9, 0x1A, 0x41, 0x56, + 0xBE, 0x0C, 0x10, 0xC9, 0xD3, 0x0B, 0xCD, 0x9D, 0x3B, 0x0E, 0xD8, 0x20, 0xB2, 0x00, 0x36, 0x28, + 0xDF, 0x55, 0x86, 0xE8, 0xFF, 0xDC, 0x78, 0x16, 0x51, 0x9E, 0x90, 0xC0, 0xA3, 0x47, 0x49, 0x6C, + 0xB8, 0xC8, 0xC0, 0xCA, 0xF8, 0xA8, 0x37, 0xD6, 0xFE, 0xD2, 0x73, 0x47, 0xF6, 0x38, 0xCE, 0xB3, + 0x9C, 0x24, 0x48, 0xD6, 0x0F, 0x13, 0x82, 0x97, 0x6A, 0x1C, 0x20, 0xC4, 0xB6, 0xA8, 0x80, 0xE8, + 0x8B, 0x39, 0x33, 0xB3, 0xB1, 0x4F, 0xA9, 0xD5, 0xD7, 0x09, 0x7F, 0x65, 0x5F, 0x03, 0xE4, 0x8F, + 0xC6, 0x1C, 0x5F, 0x10, 0xF5, 0x4E, 0xD4, 0x95, 0x8C, 0x71, 0x9C, 0xC0, 0x88, 0x8C, 0xA5, 0xE8, + 0xC6, 0x1F, 0xC5, 0x87, 0x2F, 0xAF, 0xE2, 0x2F, 0xD0, 0x92, 0x3F, 0x02, 0x4A, 0x3B, 0x07, 0x34, + 0xF8, 0x82, 0x2D, 0x29, 0xB5, 0x67, 0x6B, 0x03, 0xDA, 0x30, 0x07, 0x09, 0xED, 0x20, 0x8B, 0xA4, + 0x90, 0x72, 0xF1, 0xF6, 0x62, 0x85, 0x40, 0x28, 0xBA, 0xC5, 0x10, 0x45, 0x41, 0x7B, 0x85, 0xC3, + 0x22, 0x54, 0xA9, 0x9D, 0x8F, 0x0A, 0x84, 0xCC, 0x11, 0xEB, 0x6C, 0x63, 0x1F, 0x1B, 0xA2, 0x23, + 0x72, 0xEE, 0x63, 0xC9, 0xEB, 0xB9, 0x3D, 0x69, 0xA9, 0x4D, 0xD2, 0x99, 0x7E, 0x06, 0x5A, 0xAB, + 0x2B, 0xA8, 0x87, 0xA6, 0xAF, 0xF0, 0x29, 0x81, 0x88, 0x87, 0xE8, 0x42, 0xB2, 0x7C, 0x15, 0x6E, + 0x1D, 0x4D, 0x5F, 0xCB, 0x76, 0xC6, 0x92, 0x6C, 0x9C, 0x61, 0x63, 0x43, 0xBE, 0xA3, 0x9C, 0xD3, + 0xD5, 0xE4, 0xEF, 0x0B, 0xCA, 0x99, 0x61, 0xCB, 0x74, 0x53, 0x80, 0x93, 0x2D, 0xEB, 0xA6, 0x91, + 0xCE, 0x87, 0x53, 0x3B, 0x54, 0x20, 0xAC, 0x75, 0x6B, 0xEB, 0x64, 0x2E, 0xD9, 0xCB, 0x59, 0xA4, + 0xA4, 0x45, 0x3D, 0x20, 0x4A, 0x4C, 0xC7, 0xD3, 0xEF, 0x71, 0x78, 0xCE, 0xD3, 0x1B, 0xC3, 0xC7, + 0x49, 0x76, 0x54, 0x70, 0x6A, 0xF1, 0x87, 0xA1, 0x60, 0xAB, 0x96, 0x14, 0x45, 0x72, 0xDD, 0x52, + 0xAC, 0x15, 0x26, 0xC7, 0x00, 0xF2, 0x62, 0xD9, 0xEF, 0x3E, 0x01, 0xB8, 0x00, 0x27, 0x35, 0xB4, + 0xEF, 0xFF, 0xA2, 0x28, 0x6E, 0xB5, 0x11, 0x44, 0x99, 0x60, 0x42, 0x2C, 0xBA, 0x24, 0x11, 0xE2, + 0x27, 0x39, 0x71, 0xC1, 0x27, 0xB1, 0x4E, 0x79, 0xFB, 0x7B, 0x64, 0x21, 0x51, 0x92, 0x2A, 0x1D, + 0xA6, 0xD0, 0xE5, 0xEC, 0xE2, 0x11, 0x0A, 0x2B, 0xEC, 0x15, 0x93, 0x52, 0xF8, 0x63, 0x11, 0xC8, + 0x69, 0x43, 0x35, 0x04, 0xDD, 0xFC, 0x08, 0x75, 0x4F, 0xCA, 0x4C, 0x1B, 0x7C, 0x80, 0x05, 0x1A, + 0xB0, 0x44, 0xA8, 0x64, 0x3A, 0xC2, 0x61, 0x14, 0x13, 0x53, 0x42, 0xC2, 0x8C, 0x19, 0xCE, 0x4B, + 0xF9, 0x5A, 0x2F, 0xAF, 0x1F, 0x22, 0x59, 0xFC, 0x11, 0xC0, 0xB0, 0xA8, 0xF1, 0x20, 0x12, 0x43, + 0x16, 0x07, 0x76, 0x20, 0x21, 0x48, 0x88, 0x28, 0x4F, 0x4C, 0xC9, 0xED, 0xD6, 0xB5, 0x38, 0x52, + 0xE5, 0x8E, 0xEA, 0x34, 0x39, 0xD3, 0xD2, 0x34, 0x4B, 0xFB, 0xFD, 0x8D, 0x9A, 0xCC, 0xBF, 0xF8, + 0x0C, 0x8C, 0x14, 0xF1, 0x1A, 0xEB, 0x90, 0x93, 0x19, 0x5C, 0x96, 0x90, 0x72, 0x87, 0x65, 0xB6, + 0xF8, 0x41, 0x78, 0xA3, 0xF8, 0xA0, 0x98, 0xCD, 0x0C, 0x2F, 0xE5, 0x5A, 0x30, 0x62, 0x30, 0x71, + 0x96, 0x1C, 0xED, 0x49, 0xE2, 0x51, 0xD6, 0x81, 0xB9, 0xE2, 0x62, 0xD6, 0xC5, 0xDC, 0xF5, 0xC6, + 0x26, 0x8B, 0xC2, 0x89, 0x57, 0xFA, 0x1C, 0x02, 0x95, 0x57, 0x0C, 0x70, 0x19, 0x3D, 0x77, 0x52, + 0x0A, 0x19, 0x3F, 0xA3, 0x22, 0xE1, 0xA0, 0x0F, 0xA0, 0x54, 0x5B, 0x17, 0xA1, 0x4D, 0x13, 0xA0, + 0x88, 0xB5, 0x1C, 0x36, 0xB1, 0x4B, 0x5D, 0x82, 0x97, 0x53, 0x4F, 0x11, 0xBC, 0xB4, 0x31, 0x5D, + 0x82, 0xA6, 0x7E, 0x5F, 0x0E, 0x2C, 0x3F, 0xED, 0x22, 0xD3, 0x6E, 0xDC, 0x54, 0x00, 0x8E, 0x1F, + 0xD1, 0x91, 0x40, 0x45, 0x36, 0x2B, 0x02, 0x8C, 0x5E, 0x8A, 0x52, 0x93, 0xF4, 0x1B, 0x84, 0xDE, + 0x8C, 0x6D, 0xCE, 0x4F, 0x85, 0xA1, 0x05, 0x9D, 0x25, 0x6D, 0xE3, 0xFD, 0x3A, 0x2F, 0xAE, 0x64, + 0xD9, 0x26, 0x97, 0x42, 0xE4, 0x4D, 0xFE, 0xB5, 0x64, 0x65, 0x4C, 0xA7, 0x59, 0x95, 0x3D, 0xA0, + 0xA5, 0xB4, 0x03, 0xDF, 0x64, 0xC9, 0x20, 0x7A, 0xA0, 0x05, 0x63, 0x15, 0x1E, 0xFE, 0xCE, 0xFA, + 0xC4, 0xE4, 0x9D, 0xB0, 0xA9, 0x46, 0x29, 0x2D, 0xDE, 0x2C, 0x4D, 0x4A, 0x3C, 0x15, 0xC5, 0xFC, + 0x3B, 0xC0, 0x2C, 0xC0, 0x5F, 0x90, 0xF0, 0x40, 0x93, 0xED, 0x2D, 0x27, 0x28, 0xC7, 0x62, 0xE2, + 0x51, 0x30, 0x49, 0xBC, 0x94, 0xC9, 0xD8, 0xD3, 0x50, 0x4F, 0x3F, 0x9B, 0x43, 0x48, 0x5E, 0x2F, + 0xC0, 0xF9, 0xC0, 0xDB, 0x17, 0xF5, 0xC6, 0x6D, 0x11, 0x3B, 0x4C, 0x5C, 0xB1, 0xED, 0x54, 0x25, + 0x82, 0xA6, 0x09, 0x35, 0xB6, 0x84, 0x7C, 0xD4, 0xE8, 0x64, 0x87, 0xB9, 0x72, 0xC5, 0xE0, 0x26, + 0x4F, 0xB0, 0x17, 0x59, 0xD1, 0xB2, 0xFA, 0x36, 0x81, 0x20, 0x4E, 0x00, 0x19, 0x62, 0x53, 0x25, + 0xAC, 0x64, 0x17, 0xA2, 0x81, 0xA0, 0x5D, 0xF6, 0xC1, 0x1C, 0xDA, 0x93, 0xD5, 0x7F, 0xAA, 0x5C, + 0x64, 0x02, 0x88, 0x9C, 0x29, 0x07, 0x05, 0x3E, 0x45, 0x65, 0x1A, 0xEE, 0x8D, 0x11, 0xC8, 0x4E, + 0x63, 0x02, 0x41, 0x21, 0xE1, 0x7E, 0x53, 0xD7, 0x59, 0x03, 0x9D, 0x3B, 0x00, 0x3B, 0x6B, 0xD3, + 0x6D, 0x27, 0x38, 0x8E, 0x41, 0x1B, 0xA0, 0x27, 0x89, 0xDB, 0xEC, 0x43, 0xD1, 0xE2, 0x3E, 0x3B, + 0x63, 0x0D, 0xA2, 0x5E, 0xF0, 0xD3, 0xCC, 0x6D, 0x63, 0x36, 0x23, 0xAE, 0x75, 0x39, 0xB1, 0x1D, + 0xAB, 0xCE, 0x40, 0xA3, 0x07, 0x6D, 0x7C, 0x8D, 0x7E, 0xE6, 0x98, 0x3E, 0xD4, 0xC1, 0xB1, 0x82, + 0x37, 0x5F, 0xB2, 0x6B, 0xF5, 0x5A, 0xCF, 0x12, 0xCF, 0xE4, 0xF0, 0x66, 0x6D, 0xCB, 0x37, 0x16, + 0x6F, 0xF0, 0x99, 0x3F, 0x6A, 0x0E, 0xCD, 0x4E, 0xB3, 0xC3, 0x1B, 0x84, 0x50, 0x6C, 0x09, 0x91, + 0x23, 0x5E, 0x7C, 0x36, 0xEA, 0x97, 0x0F, 0x6F, 0x63, 0xBC, 0xA1, 0xF7, 0x82, 0x5D, 0xAA, 0xD7, + 0xE8, 0x43, 0x83, 0x87, 0x7F, 0xCC, 0x70, 0xA9, 0x59, 0xA4, 0x19, 0x49, 0x8C, 0xF8, 0x3C, 0x20, + 0x8A, 0x8A, 0x35, 0xFF, 0x41, 0x46, 0x0A, 0x97, 0x5D, 0xC8, 0x13, 0x68, 0xEE, 0x75, 0x15, 0xA8, + 0x78, 0x5A, 0x10, 0xC1, 0x91, 0x93, 0x97, 0x30, 0xBC, 0xFD, 0x27, 0x31, 0x7C, 0xD0, 0xC7, 0x81, + 0x56, 0xD7, 0x3B, 0xFA, 0x41, 0x9D, 0x5E, 0x7F, 0x07, 0xEC, 0x4C, 0xEA, 0x8D, 0x83, 0x6E, 0xA3, + 0xD1, 0x0E, 0x40, 0x67, 0xA4, 0xDE, 0xEA, 0x89, 0x26, 0xF0, 0x87, 0xB6, 0x61, 0x9D, 0xE4, 0xDF, + 0x7F, 0xED, 0xCD, 0xFD, 0xA0, 0xA8, 0xC1, 0x3B, 0xDB, 0xC5, 0x4C, 0x5C, 0xD4, 0xE4, 0x1A, 0x06, + 0x2F, 0xAE, 0x95, 0x69, 0xA2, 0xD3, 0x87, 0x1C, 0xC5, 0x48, 0x93, 0x3E, 0xFB, 0x05, 0x25, 0xBF, + 0x54, 0xEC, 0xF3, 0x7A, 0x93, 0xE0, 0x4C, 0x79, 0x5D, 0xAC, 0x5D, 0xDD, 0xCA, 0xC6, 0x11, 0x57, + 0x74, 0x7C, 0xAE, 0x21, 0xA3, 0xFF, 0x54, 0xC0, 0xE2, 0x35, 0x52, 0x66, 0x0E, 0xBD, 0x4A, 0x19, + 0xAA, 0xAC, 0xAF, 0x0A, 0xEB, 0xD1, 0xE4, 0x44, 0x73, 0x7A, 0x8C, 0x9D, 0xAC, 0x3D, 0x2F, 0xE7, + 0xE0, 0xE3, 0x53, 0x11, 0x51, 0xD9, 0x35, 0x1C, 0x70, 0x46, 0xA1, 0x1F, 0x06, 0xA0, 0x45, 0xF9, + 0x08, 0x6E, 0x4B, 0x19, 0x8C, 0x8F, 0x56, 0x4B, 0x00, 0xA4, 0x57, 0x89, 0x4B, 0xB0, 0xD2, 0x28, + 0xB8, 0xB0, 0x5E, 0x48, 0xBF, 0xFC, 0x9A, 0xA2, 0x00, 0xAC, 0x59, 0xCE, 0x15, 0x51, 0x06, 0xDA, + 0x35, 0xA2, 0xA0, 0x87, 0x40, 0x7C, 0xD8, 0x26, 0x85, 0xBC, 0x9C, 0x61, 0x7D, 0x76, 0x48, 0x9F, + 0x8A, 0x85, 0x79, 0x43, 0xF9, 0xEC, 0x30, 0xFE, 0x56, 0x32, 0x10, 0xF1, 0x51, 0x81, 0x58, 0x84, + 0xA4, 0x58, 0xDE, 0x44, 0x96, 0xB7, 0x98, 0xCE, 0x28, 0x81, 0x90, 0xBF, 0x7D, 0xC0, 0xC4, 0x45, + 0x2A, 0x8A, 0x8B, 0x70, 0x71, 0x21, 0x40, 0x3C, 0xC2, 0x2D, 0x9F, 0x5B, 0x89, 0xEC, 0xFF, 0xD7, + 0xE7, 0x31, 0x67, 0x8B, 0x61, 0x21, 0x9D, 0x7C, 0xEE, 0x42, 0x62, 0xAF, 0x18, 0x20, 0xF1, 0x81, + 0x24, 0xC6, 0xD6, 0x62, 0x58, 0x8D, 0x2D, 0x31, 0xF7, 0x81, 0x00, 0x31, 0x5B, 0xEA, 0x19, 0x12, + 0xC1, 0x4A, 0xF4, 0xB2, 0x32, 0xCD, 0x70, 0x2D, 0x2D, 0xFA, 0x4C, 0x76, 0x44, 0x2C, 0x7B, 0xD3, + 0x57, 0x69, 0xB9, 0xC9, 0x9A, 0x49, 0x4C, 0x46, 0x73, 0x2C, 0xA5, 0xA0, 0x51, 0x4B, 0x09, 0x3A, + 0xA2, 0xA3, 0x10, 0x5A, 0x34, 0x62, 0x45, 0x63, 0x74, 0x5A, 0x49, 0x58, 0x51, 0xEB, 0xD8, 0x71, + 0x62, 0x04, 0x62, 0x8E, 0xE6, 0x38, 0x3D, 0xA7, 0xC7, 0x06, 0x2F, 0x8C, 0xD9, 0xD4, 0x10, 0x45, + 0x6E, 0x10, 0xB1, 0x94, 0x68, 0x13, 0x39, 0x08, 0x83, 0xCF, 0x23, 0xB3, 0x94, 0x14, 0xB6, 0xE6, + 0xA9, 0xBF, 0x77, 0x08, 0xCE, 0x87, 0xF0, 0x7D, 0x8C, 0xB8, 0x07, 0xD1, 0xF3, 0x35, 0xC7, 0x5B, + 0x10, 0x5C, 0xBF, 0x14, 0x8F, 0x9B, 0x68, 0x43, 0x02, 0x31, 0x95, 0xB0, 0x59, 0x2D, 0x8C, 0x41, + 0xE1, 0xC4, 0x0E, 0x60, 0x10, 0x8E, 0x9F, 0xB3, 0x24, 0x0F, 0xF5, 0x28, 0x21, 0x96, 0xB2, 0x97, + 0x9D, 0xED, 0x4F, 0x88, 0x93, 0xC1, 0xC4, 0xB2, 0x7C, 0xC8, 0x79, 0xCC, 0x04, 0xA2, 0xA2, 0x79, + 0xB4, 0x35, 0x44, 0x18, 0xDD, 0xFE, 0x6A, 0xA5, 0xA8, 0x66, 0xA0, 0x54, 0x90, 0x11, 0x58, 0x2C, + 0xCB, 0x98, 0xD7, 0x8C, 0x34, 0x55, 0x93, 0x95, 0x05, 0x1A, 0xC5, 0x39, 0x7B, 0x65, 0x94, 0xCF, + 0xD7, 0x0A, 0x93, 0x38, 0x4B, 0xAC, 0xEC, 0x77, 0x7E, 0x28, 0x76, 0x16, 0xB0, 0x33, 0x2C, 0x18, + 0x07, 0x0F, 0xCE, 0x0F, 0x27, 0xE1, 0xD4, 0x19, 0x3C, 0xF8, 0x5F, 0x94, 0x18, 0xA6, 0xBF, 0xBA, + 0xAB, 0x00, 0x00 +}; + + +//File: index_ov3660.html.gz, Size: 8887 +#define index_ov3660_html_gz_len 8887 +const uint8_t index_ov3660_html_gz[] = { + 0x1F, 0x8B, 0x08, 0x08, 0xA3, 0xFA, 0x69, 0x5E, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, + 0x6F, 0x76, 0x33, 0x36, 0x36, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x00, 0xED, 0x3D, 0x69, 0x73, + 0xDB, 0x46, 0xB2, 0xDF, 0xFD, 0x2B, 0x60, 0x24, 0x6B, 0x51, 0x65, 0x91, 0xE2, 0xAD, 0x23, 0x12, + 0xFD, 0x6C, 0x59, 0xB1, 0x53, 0x1B, 0x67, 0xBD, 0x71, 0xE2, 0x24, 0xB5, 0xB5, 0xE5, 0x80, 0xC4, + 0x90, 0x44, 0x0C, 0x02, 0x5C, 0x00, 0xD4, 0x91, 0x94, 0x7E, 0xC7, 0xFB, 0x41, 0xEF, 0x8F, 0xBD, + 0xEE, 0x39, 0x70, 0x71, 0x00, 0x0C, 0x00, 0x11, 0x52, 0xF2, 0x1E, 0x5D, 0x65, 0xE1, 0x98, 0xEE, + 0xE9, 0x7B, 0x7A, 0x7A, 0x06, 0xC0, 0xD9, 0x53, 0xD3, 0x9D, 0x05, 0xB7, 0x6B, 0xA2, 0x2D, 0x83, + 0x95, 0x3D, 0x79, 0x72, 0xC6, 0xFE, 0x68, 0xF0, 0x3B, 0x5B, 0x12, 0xC3, 0x64, 0x87, 0xF4, 0x74, + 0x45, 0x02, 0x43, 0x9B, 0x2D, 0x0D, 0xCF, 0x27, 0xC1, 0xB9, 0xBE, 0x09, 0xE6, 0xED, 0x63, 0x3D, + 0x7D, 0xDB, 0x31, 0x56, 0xE4, 0x5C, 0xBF, 0xB2, 0xC8, 0xF5, 0xDA, 0xF5, 0x02, 0x5D, 0x9B, 0xB9, + 0x4E, 0x40, 0x1C, 0x68, 0x7E, 0x6D, 0x99, 0xC1, 0xF2, 0xDC, 0x24, 0x57, 0xD6, 0x8C, 0xB4, 0xE9, + 0xC9, 0x81, 0xE5, 0x58, 0x81, 0x65, 0xD8, 0x6D, 0x7F, 0x66, 0xD8, 0xE4, 0xBC, 0x17, 0xC7, 0x15, + 0x58, 0x81, 0x4D, 0x26, 0x97, 0x1F, 0xDE, 0x0F, 0xFA, 0xDA, 0x3F, 0x3E, 0x0E, 0xC6, 0xE3, 0xEE, + 0xD9, 0x21, 0xBB, 0x16, 0xB5, 0xF1, 0x83, 0xDB, 0xF8, 0x39, 0xFE, 0xA6, 0xAE, 0x79, 0xAB, 0xFD, + 0x91, 0xB8, 0x84, 0xBF, 0x39, 0x10, 0xD1, 0x9E, 0x1B, 0x2B, 0xCB, 0xBE, 0x3D, 0xD5, 0x5E, 0x7A, + 0xD0, 0xE7, 0xC1, 0x5B, 0x62, 0x5F, 0x91, 0xC0, 0x9A, 0x19, 0x07, 0xBE, 0xE1, 0xF8, 0x6D, 0x9F, + 0x78, 0xD6, 0xFC, 0xAB, 0x2D, 0xC0, 0xA9, 0x31, 0xFB, 0xBC, 0xF0, 0xDC, 0x8D, 0x63, 0x9E, 0x6A, + 0x5F, 0xF4, 0x8E, 0xF1, 0xDF, 0x76, 0xA3, 0x99, 0x6B, 0xBB, 0x1E, 0xDC, 0xBF, 0xFC, 0x1A, 0xFF, + 0x6D, 0xDF, 0xA7, 0xBD, 0xFB, 0xD6, 0xEF, 0xE4, 0x54, 0xEB, 0x8D, 0xD7, 0x37, 0x89, 0xFB, 0x77, + 0x4F, 0x12, 0xA7, 0xCB, 0x7E, 0x16, 0xF5, 0x1C, 0xFE, 0x38, 0x1F, 0xDE, 0x27, 0xB3, 0xC0, 0x72, + 0x9D, 0xCE, 0xCA, 0xB0, 0x1C, 0x09, 0x26, 0xD3, 0xF2, 0xD7, 0xB6, 0x01, 0x32, 0x98, 0xDB, 0x24, + 0x17, 0xCF, 0x17, 0x2B, 0xE2, 0x6C, 0x0E, 0x0A, 0xB0, 0x21, 0x92, 0xB6, 0x69, 0x79, 0xAC, 0xD5, + 0x29, 0xCA, 0x61, 0xB3, 0x72, 0x0A, 0xD1, 0xE6, 0xD1, 0xE5, 0xB8, 0x0E, 0x91, 0x08, 0x10, 0x3B, + 0xBA, 0xF6, 0x8C, 0x35, 0x36, 0xC0, 0xBF, 0xDB, 0x4D, 0x56, 0x96, 0xC3, 0x8C, 0xEA, 0x54, 0x1B, + 0x0C, 0xBB, 0xEB, 0x9B, 0x02, 0x55, 0x0E, 0xC6, 0xF8, 0x6F, 0xBB, 0xD1, 0xDA, 0x30, 0x4D, 0xCB, + 0x59, 0x9C, 0x6A, 0xC7, 0x52, 0x14, 0xAE, 0x67, 0x12, 0xAF, 0xED, 0x19, 0xA6, 0xB5, 0xF1, 0x4F, + 0xB5, 0xA1, 0xAC, 0xCD, 0xCA, 0xF0, 0x16, 0x40, 0x4B, 0xE0, 0x02, 0xB1, 0xED, 0x9E, 0x94, 0x12, + 0xDE, 0xC4, 0xB3, 0x16, 0xCB, 0x00, 0x54, 0xBA, 0xD5, 0x26, 0x2D, 0x34, 0xEE, 0x42, 0x45, 0xFA, + 0xCC, 0x95, 0x9B, 0x5C, 0x6A, 0x86, 0x6D, 0x2D, 0x9C, 0xB6, 0x15, 0x90, 0x15, 0xB0, 0xE3, 0x07, + 0x1E, 0x09, 0x66, 0xCB, 0x3C, 0x52, 0xE6, 0xD6, 0x62, 0xE3, 0x11, 0x09, 0x21, 0xA1, 0xDC, 0x72, + 0x18, 0x86, 0x9B, 0xDB, 0xB7, 0xDA, 0xD7, 0x64, 0xFA, 0xD9, 0x0A, 0xDA, 0x5C, 0x26, 0x53, 0x32, + 0x77, 0x3D, 0x22, 0x6D, 0x29, 0x5A, 0xD8, 0xEE, 0xEC, 0x73, 0xDB, 0x0F, 0x0C, 0x2F, 0x50, 0x41, + 0x68, 0xCC, 0x03, 0xE2, 0x15, 0xE3, 0x23, 0x68, 0x15, 0xC5, 0xD8, 0xB2, 0xBB, 0xE5, 0x0D, 0x2C, + 0xC7, 0xB6, 0x1C, 0xA2, 0x4E, 0x5E, 0x56, 0xBF, 0x49, 0x74, 0xAC, 0x95, 0x82, 0x62, 0xAC, 0xD5, + 0x22, 0xCF, 0x4A, 0x28, 0xAF, 0xDB, 0x9D, 0x71, 0xBF, 0xE9, 0x75, 0xBB, 0x7F, 0xDB, 0xBE, 0xB9, + 0x24, 0xCC, 0x4C, 0x8D, 0x4D, 0xE0, 0xD6, 0xF7, 0x88, 0x2D, 0xB7, 0x4A, 0xF1, 0xF1, 0x5F, 0x2B, + 0x62, 0x5A, 0x86, 0xD6, 0x8A, 0xB9, 0xF3, 0x71, 0x17, 0x6C, 0x6A, 0x5F, 0x33, 0x1C, 0x53, 0x6B, + 0xB9, 0x9E, 0x05, 0x8E, 0x60, 0xD0, 0x70, 0x63, 0xC3, 0x15, 0x18, 0x38, 0xD6, 0x64, 0x5F, 0xC2, + 0x72, 0x8E, 0xCF, 0xC4, 0x25, 0x22, 0x77, 0x1B, 0xFC, 0x29, 0x84, 0x1C, 0xFC, 0x15, 0x3A, 0x90, + 0x84, 0x47, 0x8A, 0x3E, 0x4F, 0x5F, 0x71, 0x0A, 0xB3, 0x74, 0x86, 0xBF, 0x95, 0x71, 0xD3, 0xCE, + 0xD5, 0x9D, 0x68, 0x24, 0x74, 0x08, 0xC3, 0xEC, 0xAC, 0x05, 0x4D, 0xAF, 0x96, 0x5A, 0x5B, 0xC3, + 0x28, 0xB9, 0x2F, 0x87, 0xE1, 0x48, 0xE5, 0x2A, 0xC7, 0x5F, 0xDC, 0x28, 0x4A, 0xB0, 0x2B, 0x67, + 0x35, 0x8A, 0x1D, 0xEC, 0x9F, 0xCC, 0x86, 0x18, 0x27, 0x99, 0x51, 0x04, 0x7F, 0xEA, 0x91, 0x24, + 0x42, 0x56, 0x18, 0x4D, 0x24, 0x88, 0xB3, 0x23, 0xCA, 0x16, 0xDE, 0x2C, 0xEF, 0x96, 0x60, 0xCD, + 0x27, 0x41, 0x35, 0xBA, 0x48, 0x10, 0xE7, 0xD1, 0x50, 0x18, 0x65, 0xF0, 0x77, 0xA7, 0x90, 0x6F, + 0x7C, 0x31, 0xDD, 0x04, 0x81, 0xEB, 0xF8, 0xB5, 0x86, 0xA8, 0x2C, 0x3F, 0xFB, 0x6D, 0xE3, 0x07, + 0xD6, 0xFC, 0xB6, 0xCD, 0x5D, 0x1A, 0xFC, 0x6C, 0x6D, 0x40, 0x0A, 0x39, 0x25, 0xC1, 0x35, 0x21, + 0xF9, 0xE9, 0x86, 0x63, 0x5C, 0x41, 0xDC, 0x59, 0x2C, 0x6C, 0x99, 0xED, 0xCD, 0x36, 0x9E, 0x8F, + 0x79, 0xDB, 0xDA, 0xB5, 0x00, 0xB1, 0xB7, 0xDD, 0x71, 0xD2, 0x07, 0x15, 0x3B, 0x6A, 0xCF, 0xA6, + 0x92, 0xBE, 0xDC, 0x4D, 0x80, 0x32, 0x96, 0x6A, 0xC2, 0x05, 0x76, 0xAC, 0xE0, 0x56, 0x7A, 0x8F, + 0x7B, 0xA2, 0xE4, 0x8E, 0x70, 0xC1, 0xDC, 0x61, 0x21, 0x49, 0xD7, 0xE9, 0x6C, 0x49, 0x66, 0x9F, + 0x89, 0xF9, 0xBC, 0x30, 0x0D, 0x2B, 0x4A, 0x0F, 0x3B, 0x96, 0xB3, 0xDE, 0x04, 0x6D, 0x4C, 0xA7, + 0xD6, 0x3B, 0xD1, 0x39, 0x35, 0x48, 0xC1, 0x62, 0xBF, 0x9F, 0x97, 0x54, 0x8C, 0xD6, 0x37, 0xF9, + 0x42, 0x88, 0x13, 0x3B, 0xB1, 0x8D, 0x29, 0xB1, 0xF3, 0x48, 0xE6, 0xCE, 0x90, 0x11, 0x76, 0x79, + 0xAC, 0xCA, 0xCE, 0xDD, 0x28, 0x65, 0xD1, 0xE0, 0x35, 0x3C, 0xFA, 0x9B, 0xB2, 0x1C, 0xE9, 0xF1, + 0x41, 0xE2, 0x92, 0x4F, 0x6C, 0x70, 0xB0, 0xAC, 0xD4, 0x1B, 0xDA, 0x5C, 0x03, 0x0D, 0xB9, 0x1D, + 0x78, 0x86, 0xB3, 0x20, 0x10, 0x0B, 0x6E, 0x0E, 0xC4, 0x61, 0xFE, 0xC4, 0x40, 0x89, 0x7D, 0x0C, + 0xD5, 0xA3, 0xFC, 0x89, 0x08, 0x0B, 0x08, 0x07, 0x5A, 0x87, 0x1D, 0x54, 0xC8, 0x4A, 0x62, 0xFA, + 0xCD, 0x25, 0xA4, 0x27, 0xB5, 0x0E, 0x96, 0x98, 0x48, 0x3D, 0x27, 0x69, 0x5B, 0xD2, 0x44, 0xBF, + 0x30, 0x34, 0x88, 0x29, 0xDF, 0x7C, 0x5E, 0x34, 0x69, 0x9C, 0xCF, 0x07, 0xDD, 0xC1, 0xB0, 0x30, + 0x73, 0x92, 0x72, 0x99, 0x9A, 0x38, 0x4A, 0x42, 0x47, 0x18, 0x56, 0x72, 0x8D, 0xC0, 0x37, 0xAE, + 0xA4, 0x49, 0xBB, 0xEB, 0x5B, 0x6C, 0xE6, 0x66, 0x4C, 0x7D, 0x98, 0xBB, 0x05, 0x92, 0xA9, 0x17, + 0x37, 0xF4, 0xBE, 0x94, 0x3E, 0x9A, 0xD2, 0x49, 0x5D, 0x40, 0x88, 0x57, 0x4E, 0x76, 0x42, 0x03, + 0xF2, 0x26, 0x31, 0x05, 0x4B, 0x93, 0xCA, 0x80, 0xDC, 0x04, 0x6D, 0x93, 0xCC, 0x5C, 0x8F, 0x65, + 0x83, 0x19, 0x33, 0xC7, 0x94, 0x22, 0x8B, 0x2D, 0xF6, 0x74, 0xE9, 0x5E, 0x11, 0x4F, 0x22, 0xAC, + 0x94, 0x52, 0x87, 0x27, 0x43, 0x53, 0x01, 0x9B, 0x01, 0xC3, 0xA3, 0x54, 0xF6, 0x49, 0x74, 0xFD, + 0xDE, 0xAC, 0x9F, 0xEB, 0xC7, 0x0C, 0x5D, 0x07, 0x7C, 0xC6, 0x98, 0xDA, 0xC4, 0xCC, 0x19, 0xCD, + 0x4C, 0x32, 0x37, 0x36, 0x76, 0x50, 0x60, 0x95, 0x46, 0x17, 0xFF, 0xE5, 0xF5, 0x48, 0xC3, 0xD0, + 0xBF, 0xB0, 0x2E, 0x74, 0x4E, 0x03, 0xC7, 0xBF, 0x25, 0x7D, 0x8A, 0x54, 0xC3, 0x58, 0xAF, 0x89, + 0x01, 0xAD, 0x66, 0x24, 0x4B, 0x0F, 0x4A, 0x53, 0x0C, 0x79, 0x9C, 0x57, 0x9A, 0xB7, 0x17, 0x3A, + 0x6C, 0x98, 0x3C, 0x96, 0xE2, 0xF9, 0x74, 0xEE, 0xCE, 0x36, 0xB2, 0xAC, 0x46, 0xCD, 0xF1, 0xB6, + 0xF1, 0x9D, 0x0A, 0x91, 0xF9, 0xB6, 0x45, 0xDD, 0x7F, 0xE3, 0x38, 0xA8, 0xD1, 0x76, 0xE0, 0x01, + 0x9B, 0x92, 0x8E, 0xD4, 0x04, 0x57, 0x29, 0x86, 0x25, 0x04, 0x9B, 0x55, 0xBB, 0x4A, 0x85, 0x29, + 0x49, 0x38, 0x0D, 0x23, 0xAD, 0x06, 0x31, 0xC4, 0x32, 0x05, 0xAA, 0x7A, 0x72, 0x09, 0x96, 0x9B, + 0x95, 0x2C, 0x8F, 0x12, 0x9D, 0xF5, 0x60, 0xD0, 0x67, 0xDD, 0x79, 0x8B, 0xA9, 0xD1, 0xEA, 0x1E, + 0x74, 0x0F, 0x06, 0xF0, 0x9F, 0x64, 0x3E, 0x93, 0x6F, 0x5C, 0x5C, 0xBC, 0x19, 0x96, 0x97, 0x0A, + 0xD1, 0xC5, 0x65, 0xA5, 0xAC, 0x60, 0x5F, 0xA8, 0x0B, 0x75, 0x4F, 0x4A, 0xD6, 0x97, 0x7A, 0x9D, + 0x82, 0x71, 0x38, 0xC3, 0xA4, 0xCB, 0x1B, 0xA2, 0xC4, 0x5A, 0xCA, 0xAA, 0x78, 0xE5, 0xFE, 0xDE, + 0x66, 0x49, 0xC8, 0xFF, 0x79, 0x6B, 0x8F, 0x89, 0xE2, 0x2F, 0x6D, 0xE9, 0xA5, 0xE5, 0xE2, 0x3F, + 0xB4, 0x6D, 0x74, 0xB3, 0xB5, 0xDE, 0xE6, 0x59, 0x1F, 0x50, 0xE8, 0xC0, 0x1C, 0xD4, 0x83, 0xC9, + 0x68, 0x66, 0x66, 0x18, 0x6B, 0x53, 0x41, 0x06, 0x73, 0xCB, 0xB6, 0xDB, 0xB6, 0x7B, 0x5D, 0x9C, + 0x89, 0xE4, 0x5B, 0xF2, 0x96, 0x9D, 0x16, 0x9B, 0x7C, 0x55, 0x6A, 0x37, 0x10, 0xB9, 0xFE, 0x14, + 0xD4, 0xFE, 0xB5, 0x1D, 0x2E, 0xD7, 0x35, 0xAA, 0x0D, 0x14, 0x15, 0xEC, 0xB1, 0x5E, 0x47, 0x4A, + 0xA6, 0xC4, 0x32, 0xC1, 0xFC, 0x69, 0xCF, 0xB5, 0x15, 0xCC, 0x96, 0x15, 0xA6, 0x9E, 0xD1, 0xC4, + 0xC8, 0x23, 0xB6, 0x81, 0x19, 0x7C, 0xA5, 0x0A, 0x45, 0xE1, 0xF4, 0x2D, 0x0E, 0xAE, 0xC2, 0x09, + 0x15, 0xDD, 0xE3, 0xA9, 0x2E, 0x75, 0x58, 0xEE, 0x90, 0x1D, 0xAB, 0xE5, 0x66, 0x5D, 0x90, 0xEE, + 0x27, 0x3D, 0x43, 0xDE, 0xA8, 0x44, 0x44, 0x17, 0x41, 0x7B, 0xE1, 0x91, 0x5B, 0x05, 0x66, 0x0E, + 0xF8, 0xDF, 0x53, 0x56, 0x3F, 0xAE, 0x5E, 0x2A, 0xA1, 0x03, 0x00, 0xB7, 0xA2, 0xCE, 0xD0, 0x57, + 0xE8, 0x3A, 0xBB, 0x4B, 0x15, 0x7B, 0x0C, 0xAB, 0xA3, 0xBA, 0xAE, 0x10, 0x6E, 0x72, 0x86, 0x50, + 0xB9, 0xA9, 0x8A, 0xD1, 0x57, 0x3E, 0x9F, 0x27, 0xF3, 0x20, 0x63, 0xF1, 0x87, 0xE6, 0xA9, 0x83, + 0xFC, 0xE8, 0xD6, 0x8E, 0x55, 0x53, 0x0A, 0x23, 0x47, 0x58, 0xC4, 0xCC, 0xB6, 0x3E, 0x29, 0x66, + 0x8C, 0x9E, 0xA5, 0x91, 0x67, 0xAB, 0x44, 0xA4, 0xCF, 0x54, 0xCD, 0xD0, 0x66, 0xC5, 0x87, 0x7C, + 0x50, 0x0F, 0xF9, 0xB9, 0xD5, 0x1F, 0x4B, 0xD7, 0x56, 0x72, 0x1A, 0xE7, 0x91, 0x96, 0x59, 0x05, + 0xDC, 0x1E, 0xB2, 0x32, 0x27, 0xC8, 0xF1, 0x58, 0x24, 0x55, 0x54, 0xBE, 0x57, 0xE6, 0x45, 0x98, + 0xED, 0x4A, 0x56, 0xAE, 0xB1, 0x5B, 0x2B, 0x03, 0xD2, 0x5E, 0x34, 0x57, 0x03, 0x30, 0xCA, 0xF4, + 0xA7, 0x62, 0xEE, 0xB1, 0x1A, 0x6B, 0x6F, 0xDC, 0x2D, 0xE8, 0x72, 0x66, 0xBB, 0x7E, 0xCD, 0x02, + 0x58, 0x76, 0xFD, 0x4B, 0x7A, 0x47, 0x69, 0xE8, 0xCE, 0xF5, 0xA9, 0x7C, 0x77, 0x4C, 0xC9, 0xBC, + 0xD7, 0x95, 0x46, 0xDA, 0xDC, 0x2A, 0x25, 0xAD, 0xA0, 0xD1, 0xF5, 0xCB, 0x53, 0x6D, 0x46, 0xE4, + 0x61, 0x34, 0x59, 0xA8, 0x53, 0x29, 0x95, 0xE6, 0xEA, 0x61, 0x69, 0x99, 0x26, 0xC9, 0xAD, 0x05, + 0xE3, 0x9C, 0x57, 0x31, 0x79, 0x40, 0xFA, 0x65, 0x45, 0xA9, 0x9D, 0x38, 0x45, 0xEE, 0xB6, 0x86, + 0xDE, 0xAE, 0x3D, 0x86, 0x0F, 0x34, 0x59, 0x95, 0xF4, 0x64, 0x2A, 0x92, 0x4B, 0xAA, 0xD4, 0xB9, + 0xC3, 0x5A, 0x2B, 0x8A, 0x0C, 0xE4, 0x80, 0xAD, 0xB6, 0xA3, 0x79, 0x8A, 0x2A, 0xBA, 0x90, 0xD2, + 0xE1, 0x6B, 0x4B, 0x7C, 0x19, 0xB0, 0x9D, 0xB5, 0xBA, 0x72, 0x8F, 0x4B, 0x6D, 0xD4, 0x02, 0xD2, + 0xFD, 0x66, 0x8A, 0xE6, 0x81, 0x32, 0xA3, 0x1C, 0x22, 0xC3, 0x21, 0x46, 0x6C, 0xAE, 0x4A, 0xB6, + 0x2A, 0xEB, 0x1C, 0xE1, 0xF9, 0xD9, 0x61, 0x6C, 0x3B, 0xDC, 0xD9, 0x61, 0xB4, 0x73, 0xEF, 0x0C, + 0xF7, 0xC4, 0xC5, 0x77, 0xCD, 0xF1, 0x8E, 0x66, 0xB6, 0xE1, 0xFB, 0xE7, 0x3A, 0xEE, 0xED, 0xD2, + 0x93, 0x9B, 0xE8, 0xCE, 0x4C, 0xEB, 0x4A, 0xB3, 0xCC, 0x73, 0xDD, 0x76, 0x17, 0x6E, 0xEA, 0x1E, + 0xBD, 0xCF, 0xD4, 0x0C, 0x03, 0xD9, 0xB9, 0x9E, 0x58, 0x60, 0xD4, 0x29, 0x54, 0x74, 0x49, 0x9F, + 0x3C, 0xFB, 0xE2, 0xE4, 0xE8, 0x68, 0xFC, 0xD5, 0x33, 0x67, 0xEA, 0xAF, 0xF9, 0xFF, 0x3F, 0xB0, + 0xF5, 0x58, 0xB6, 0xA9, 0x0F, 0xC6, 0xB6, 0x20, 0x00, 0xDB, 0xF3, 0xCF, 0x0E, 0x29, 0xD2, 0x14, + 0x21, 0x87, 0x40, 0x49, 0x06, 0x6D, 0x3C, 0xDF, 0x91, 0x91, 0x27, 0x9A, 0xF8, 0x30, 0x84, 0x4F, + 0x0D, 0x4F, 0xD2, 0x84, 0x36, 0x63, 0xD9, 0x34, 0x8D, 0x25, 0x3A, 0x55, 0xCA, 0xD4, 0xBD, 0x49, + 0x73, 0x40, 0x99, 0xE2, 0x1A, 0xE3, 0xAD, 0x88, 0x99, 0x85, 0x10, 0xC0, 0x28, 0x38, 0xAE, 0xAE, + 0x42, 0x1B, 0x69, 0xA3, 0x84, 0x0A, 0xB0, 0xF1, 0xCD, 0xCC, 0xFE, 0x2C, 0x94, 0xAF, 0x0B, 0xA5, + 0x38, 0x6E, 0xC0, 0x62, 0x65, 0x46, 0x57, 0x09, 0x56, 0x39, 0x4C, 0x6C, 0xDD, 0x90, 0x71, 0x01, + 0xA2, 0x6D, 0x53, 0xEC, 0xEC, 0x5A, 0x3E, 0x26, 0x8A, 0x2D, 0xA6, 0x57, 0x01, 0xAC, 0x4F, 0x7E, + 0xBE, 0xF8, 0xF6, 0xEF, 0xDA, 0xBB, 0xB7, 0xBF, 0x4B, 0x35, 0x54, 0x44, 0x14, 0x06, 0x69, 0x85, + 0x9E, 0x29, 0x18, 0xD3, 0x87, 0x90, 0x89, 0xCE, 0x35, 0x43, 0x31, 0xE0, 0x70, 0x6F, 0x13, 0x67, + 0x11, 0x2C, 0xCF, 0xF5, 0x9E, 0x8E, 0x7B, 0x5A, 0xC4, 0x59, 0x5F, 0xD7, 0x30, 0x80, 0xD3, 0x83, + 0x2B, 0xC3, 0xDE, 0xE0, 0x51, 0x57, 0x85, 0xD7, 0x6D, 0xD3, 0x92, 0x36, 0xE3, 0x91, 0x25, 0x94, + 0x71, 0x2C, 0x12, 0x27, 0xA5, 0xAC, 0x4F, 0x3E, 0x90, 0xE0, 0xEC, 0x90, 0xDD, 0x2A, 0xD0, 0x5A, + 0x7E, 0xDF, 0xE0, 0xC9, 0xCC, 0x1C, 0xF2, 0x4C, 0x28, 0x4F, 0xF1, 0x73, 0xCF, 0x58, 0x11, 0x94, + 0x8A, 0x92, 0xE6, 0xE3, 0x5A, 0x0F, 0x21, 0xF5, 0xC9, 0xF7, 0x84, 0x66, 0x44, 0x40, 0x86, 0x92, + 0xE2, 0xCF, 0x78, 0x92, 0x9A, 0xE8, 0x3F, 0xB4, 0x67, 0xBE, 0x28, 0xD5, 0x36, 0x98, 0x99, 0x2B, + 0xC8, 0xFD, 0x69, 0xBB, 0xAD, 0x0D, 0xDE, 0xBD, 0xD7, 0xDA, 0x6D, 0x85, 0xC6, 0xEE, 0x9A, 0xBA, + 0x13, 0xD7, 0x7F, 0xEF, 0x48, 0x9F, 0xFC, 0xF3, 0xE7, 0x37, 0x2F, 0x5B, 0xFD, 0xEE, 0xF0, 0xF8, + 0xA6, 0x37, 0x1A, 0x0F, 0xF7, 0xCF, 0x0E, 0x59, 0x93, 0xF2, 0xB8, 0xC6, 0xFA, 0xE4, 0x3D, 0x12, + 0xD2, 0x3A, 0x1E, 0x0F, 0xEB, 0xE2, 0x1A, 0x21, 0xAE, 0xB7, 0xAF, 0x5B, 0x47, 0xFD, 0xEE, 0x4D, + 0xAF, 0x7F, 0xDC, 0xAD, 0x81, 0x6A, 0xA8, 0x4F, 0xBE, 0x06, 0x4C, 0xBD, 0x13, 0x44, 0xD5, 0x2D, + 0x87, 0x0A, 0x45, 0xDB, 0xAF, 0x28, 0xDA, 0x81, 0x3E, 0xF9, 0x11, 0x45, 0x0B, 0x39, 0x37, 0xF2, + 0xD0, 0xAD, 0xC3, 0x43, 0x1F, 0x5C, 0x86, 0xE2, 0x02, 0x51, 0x00, 0x13, 0xFD, 0x3A, 0xA2, 0xED, + 0xE9, 0x13, 0x14, 0x07, 0x62, 0x02, 0xE9, 0xD6, 0x40, 0x04, 0xB1, 0x83, 0xD2, 0x04, 0xE4, 0xDC, + 0x1C, 0x8D, 0x8F, 0xAB, 0x63, 0x3A, 0x01, 0xEE, 0x3E, 0x02, 0xA6, 0x63, 0x10, 0xD4, 0xB8, 0x8E, + 0x9C, 0x8E, 0xF5, 0x09, 0xE2, 0x19, 0x0F, 0xBB, 0x37, 0xC3, 0x3A, 0x36, 0x03, 0x5E, 0xF1, 0x16, + 0x11, 0x01, 0x92, 0x9B, 0x41, 0x1D, 0x19, 0x81, 0x4B, 0x5C, 0x7C, 0xF3, 0x75, 0x6B, 0x08, 0x8C, + 0xF5, 0x4F, 0xC6, 0xD5, 0xF1, 0x80, 0x3B, 0xFC, 0x13, 0x09, 0x02, 0x62, 0x6E, 0xFA, 0xC3, 0x1A, + 0x04, 0x81, 0x33, 0x00, 0x3C, 0xE2, 0xA8, 0x8C, 0x02, 0xEC, 0xFA, 0x2D, 0x25, 0x06, 0x11, 0xF5, + 0x8E, 0x6A, 0x70, 0x05, 0x56, 0xFD, 0x4F, 0x14, 0x0F, 0x20, 0xB9, 0xE9, 0x0D, 0xEB, 0xD8, 0x34, + 0x20, 0xA2, 0x24, 0x81, 0xAF, 0xA1, 0xAB, 0x55, 0xC7, 0x04, 0x36, 0x7D, 0x32, 0xBE, 0x39, 0x19, + 0xAB, 0x21, 0xC0, 0xE1, 0x07, 0x43, 0x79, 0xDE, 0x00, 0x95, 0x3F, 0x7E, 0xE5, 0x8D, 0x4D, 0xFF, + 0xD9, 0xC0, 0x94, 0x33, 0xB8, 0x2D, 0x3D, 0x32, 0x71, 0x38, 0x90, 0x09, 0x3B, 0x50, 0x1B, 0x94, + 0x62, 0x94, 0x84, 0xBB, 0x9F, 0xF4, 0xC9, 0x50, 0x61, 0xF0, 0x4F, 0x64, 0x87, 0x14, 0x36, 0x41, + 0x3F, 0xCD, 0x48, 0xD0, 0xF2, 0x30, 0x17, 0x01, 0x97, 0x18, 0xE8, 0xB1, 0x08, 0x52, 0x69, 0xD4, + 0x93, 0xD0, 0x6A, 0xDC, 0xE8, 0x93, 0xF1, 0xA0, 0x30, 0x5B, 0xA8, 0xAE, 0x8C, 0x29, 0x2D, 0x6E, + 0x38, 0xC4, 0xF7, 0x4B, 0xEB, 0x23, 0x02, 0xD5, 0x27, 0xAF, 0xC2, 0xE3, 0x3A, 0x5A, 0x69, 0x17, + 0x71, 0x4A, 0x61, 0x33, 0xD4, 0x12, 0x23, 0x87, 0x69, 0xA6, 0x3D, 0xE0, 0xAA, 0x89, 0x34, 0x73, + 0xBF, 0x8A, 0xD9, 0xA5, 0x5E, 0x70, 0x6E, 0xE3, 0x19, 0x7E, 0x50, 0x5A, 0x2B, 0x02, 0x10, 0x22, + 0x34, 0x3F, 0x7A, 0x30, 0x8D, 0x84, 0xA4, 0xFC, 0x05, 0xF4, 0xE1, 0x1B, 0xC1, 0x86, 0xED, 0x33, + 0x2B, 0xAD, 0x91, 0x08, 0x14, 0xF2, 0x81, 0xF0, 0xB8, 0x96, 0x56, 0xEA, 0x84, 0xAF, 0x18, 0x39, + 0x5C, 0x2F, 0x22, 0x84, 0x0D, 0x77, 0xA4, 0x97, 0x22, 0x6A, 0x6B, 0xE9, 0x65, 0x69, 0x78, 0xEB, + 0x4A, 0xE1, 0x2B, 0x84, 0x04, 0xAD, 0x88, 0xC3, 0x07, 0x73, 0x95, 0x88, 0x98, 0xBF, 0x80, 0xAF, + 0x98, 0xC4, 0x71, 0x2D, 0xBF, 0xFC, 0xD4, 0x93, 0xC3, 0xE9, 0x93, 0xD7, 0xA4, 0xFD, 0x1D, 0x1E, + 0xD5, 0x51, 0xC7, 0xCB, 0x4D, 0xE0, 0xD6, 0x50, 0x88, 0xA0, 0x85, 0xA9, 0xA3, 0xCB, 0xB5, 0x71, + 0xBC, 0x23, 0x6D, 0x1C, 0xEF, 0x50, 0x1B, 0x06, 0xF9, 0x64, 0x93, 0x2B, 0x62, 0x97, 0x56, 0x87, + 0x00, 0xD4, 0x27, 0x97, 0x37, 0x6B, 0xD7, 0xC7, 0xA7, 0x77, 0xBE, 0xC5, 0xF3, 0x5A, 0x4E, 0x32, + 0xAA, 0xA1, 0x93, 0x90, 0x20, 0xEE, 0x23, 0x23, 0xAE, 0x95, 0xD1, 0x8E, 0xB4, 0x52, 0x44, 0x6B, + 0x1D, 0xAD, 0x2C, 0x0C, 0xCB, 0x99, 0x11, 0xCB, 0xC6, 0x27, 0x09, 0xCA, 0x2A, 0x26, 0x06, 0xAB, + 0x4F, 0xDE, 0x44, 0x27, 0x75, 0x14, 0xD3, 0xAD, 0xA1, 0x97, 0x38, 0x3D, 0x49, 0x7F, 0x19, 0xC1, + 0xAC, 0x7C, 0x47, 0xBA, 0xE9, 0xF5, 0x76, 0x39, 0xAA, 0xAC, 0xC9, 0xCC, 0x32, 0xEC, 0x4F, 0x64, + 0x3E, 0x87, 0x69, 0x50, 0xF9, 0xA1, 0x25, 0x01, 0x0E, 0xE3, 0x0B, 0x3B, 0xD7, 0x2E, 0xE9, 0x79, + 0xE9, 0x62, 0x5A, 0x0A, 0x5D, 0xF5, 0x8A, 0x5A, 0x7A, 0x4E, 0xC8, 0x97, 0x95, 0x09, 0xAD, 0x61, + 0xB2, 0x23, 0x7D, 0xF2, 0x9D, 0x1B, 0xD2, 0x59, 0x7D, 0xDA, 0xFA, 0x1D, 0x59, 0xD0, 0x55, 0xDB, + 0x3A, 0x73, 0xE8, 0x37, 0x9E, 0x71, 0x4B, 0x5F, 0x0B, 0x50, 0x67, 0x4A, 0xFF, 0x3D, 0x31, 0xB5, + 0x1F, 0x2C, 0xA7, 0x3A, 0x33, 0x43, 0x24, 0x84, 0x10, 0xA7, 0x1E, 0x96, 0x11, 0x4C, 0x91, 0xE0, + 0xA0, 0x1E, 0x92, 0x31, 0x16, 0x98, 0xD7, 0x96, 0xF1, 0x18, 0x26, 0xF1, 0xC6, 0xF5, 0xB4, 0xFC, + 0x80, 0x72, 0x3D, 0x85, 0x71, 0xF9, 0xA7, 0x57, 0xDA, 0x25, 0xDD, 0x67, 0x5C, 0x3A, 0x5C, 0xB1, + 0x2D, 0x50, 0x2A, 0x86, 0x1E, 0xAD, 0x23, 0x60, 0x9F, 0x5B, 0x0B, 0x3C, 0x72, 0x07, 0x52, 0x5D, + 0xE4, 0x91, 0xB0, 0x27, 0x08, 0xA4, 0x3B, 0x46, 0xF4, 0x18, 0xB7, 0x6A, 0x3C, 0xEE, 0x30, 0x15, + 0x9B, 0x5D, 0x97, 0x4F, 0xC3, 0x66, 0xD7, 0xA0, 0x26, 0xF3, 0x0A, 0xB7, 0xA0, 0x9B, 0x1A, 0xE8, + 0xAB, 0x11, 0x45, 0x61, 0xAF, 0x0F, 0xA3, 0x28, 0xCA, 0xEF, 0x43, 0x2B, 0x0A, 0xAC, 0xE5, 0x13, + 0x8E, 0xA3, 0x55, 0x9C, 0x8A, 0x02, 0xEA, 0x93, 0x77, 0x86, 0xB3, 0x81, 0x41, 0xA6, 0x29, 0x85, + 0x85, 0x1D, 0x3F, 0x98, 0x7B, 0x71, 0xBE, 0x1F, 0x5A, 0x75, 0x40, 0xC8, 0xCA, 0x35, 0xCB, 0x4F, + 0x77, 0x38, 0x1C, 0x0B, 0x89, 0xEF, 0xE0, 0xA8, 0x74, 0x62, 0x20, 0x30, 0xEC, 0x38, 0x23, 0x60, + 0x53, 0xA9, 0xEA, 0xC9, 0xC0, 0x87, 0x8D, 0xE3, 0xDC, 0xD6, 0xC9, 0x04, 0x2E, 0x6C, 0x77, 0x63, + 0x56, 0xC7, 0x00, 0x69, 0xC0, 0x3F, 0xE6, 0x73, 0x6B, 0x56, 0x3D, 0x91, 0x80, 0x24, 0xE0, 0xAD, + 0xBB, 0x52, 0x84, 0xDF, 0xF1, 0xC0, 0x4B, 0x66, 0x15, 0x66, 0x72, 0x33, 0xD0, 0xE2, 0xE5, 0x45, + 0xA3, 0x03, 0x2F, 0xF4, 0xF9, 0x40, 0x91, 0x01, 0xB9, 0x7D, 0xE8, 0xA0, 0x00, 0x44, 0x7C, 0xA2, + 0xC6, 0x53, 0x45, 0x59, 0x0C, 0x32, 0x8C, 0xE8, 0x62, 0xFA, 0xFD, 0x50, 0xF3, 0xBB, 0x88, 0xA2, + 0xE4, 0xEC, 0xAE, 0x37, 0x1A, 0x8C, 0xC3, 0xE9, 0xDD, 0xA0, 0x7F, 0xBF, 0x13, 0x3C, 0x44, 0xBE, + 0x5B, 0xFD, 0xF4, 0xAB, 0xA8, 0x06, 0xA2, 0xD1, 0x77, 0xB8, 0xCE, 0x50, 0x22, 0x60, 0xD7, 0x77, + 0xA4, 0xFE, 0xC3, 0x79, 0x52, 0xFF, 0x11, 0xB8, 0xD2, 0xA2, 0x42, 0xC4, 0x5B, 0x60, 0xC4, 0x7B, + 0x73, 0xD1, 0x8C, 0x86, 0x16, 0x0F, 0x16, 0xEA, 0x16, 0x0F, 0x1A, 0xEA, 0x34, 0xBE, 0x43, 0x4D, + 0x48, 0xA1, 0x62, 0x06, 0xCB, 0x01, 0x59, 0x2D, 0xAB, 0x4E, 0x90, 0xEB, 0xDD, 0xD4, 0x89, 0x72, + 0x82, 0x8C, 0x64, 0x90, 0x1B, 0x47, 0xAB, 0x22, 0xA3, 0xFB, 0x5D, 0xD6, 0x1D, 0x16, 0x51, 0x5B, + 0xC7, 0x69, 0x3C, 0xE3, 0xFA, 0xD3, 0x62, 0x65, 0x94, 0x56, 0x06, 0x87, 0x03, 0x5D, 0xBC, 0x7B, + 0xD9, 0x64, 0xBA, 0x20, 0xFA, 0x7D, 0x18, 0x3F, 0x0A, 0xB9, 0x7E, 0xE8, 0x58, 0x67, 0x13, 0xA7, + 0x7C, 0xB0, 0x43, 0x20, 0x7D, 0xF2, 0x2D, 0x71, 0x7C, 0xED, 0xC2, 0xF5, 0xF8, 0xBB, 0x18, 0x1B, + 0xD1, 0x1A, 0xED, 0xF9, 0x61, 0x54, 0xC6, 0x98, 0x7E, 0x68, 0x7D, 0x2D, 0x57, 0x96, 0xE7, 0xB9, + 0x5E, 0x69, 0x95, 0x71, 0x38, 0x98, 0x56, 0xB4, 0xDF, 0xD1, 0xA3, 0x46, 0xD4, 0x25, 0x7A, 0x7D, + 0x18, 0x8D, 0x85, 0x3C, 0x3F, 0xB4, 0xD2, 0xAE, 0xE6, 0xB6, 0xB5, 0x2E, 0xAD, 0x32, 0x0A, 0xA5, + 0x4F, 0x3E, 0xB6, 0xBF, 0x86, 0xBF, 0x8D, 0xA8, 0x8B, 0xF5, 0xF8, 0x30, 0xCA, 0xE2, 0xDC, 0x3E, + 0xB4, 0xAA, 0xA6, 0xEB, 0xF2, 0xE1, 0x10, 0x60, 0xF4, 0xC9, 0xAB, 0xF7, 0xCD, 0xE4, 0x7E, 0xD8, + 0x99, 0xA2, 0x86, 0x6A, 0xE9, 0x83, 0x32, 0xF5, 0xD0, 0xDA, 0xB8, 0xAE, 0xA0, 0x8D, 0x6B, 0x24, + 0xFC, 0xA7, 0x86, 0xB4, 0x71, 0xAD, 0xAE, 0x8D, 0x7B, 0xF6, 0x97, 0xEB, 0xC7, 0xA0, 0x1F, 0xFA, + 0xB0, 0xDF, 0xD4, 0x28, 0x3F, 0x1C, 0x09, 0x40, 0xDC, 0x34, 0x06, 0x47, 0xDA, 0x2B, 0xA3, 0x99, + 0x01, 0x29, 0xEC, 0xB7, 0x09, 0x17, 0x8A, 0x98, 0x7C, 0x68, 0x3D, 0xD9, 0xC4, 0xAC, 0x90, 0xE4, + 0x99, 0x9F, 0xF0, 0xC9, 0x39, 0x7C, 0xA2, 0xFC, 0x16, 0xB2, 0xBD, 0xCB, 0xD7, 0xDA, 0x37, 0xE2, + 0xF4, 0xA1, 0x0A, 0x43, 0x49, 0x9A, 0x92, 0xF3, 0xA6, 0xFE, 0x68, 0x57, 0xDB, 0x32, 0x00, 0xF3, + 0x0E, 0x75, 0x33, 0x37, 0x66, 0xE4, 0x93, 0x49, 0x82, 0x2A, 0xEB, 0xFE, 0x31, 0x58, 0x7D, 0xF2, + 0x35, 0x9C, 0x68, 0xAF, 0xE9, 0x49, 0x53, 0xE9, 0x78, 0xBC, 0xFF, 0x26, 0x3C, 0x2A, 0xC1, 0xEF, + 0x43, 0x3B, 0x15, 0x25, 0x06, 0x26, 0x3F, 0xEE, 0xC2, 0xA9, 0xF4, 0xDC, 0x53, 0x02, 0x9C, 0xAB, + 0xEF, 0x7B, 0x76, 0xDE, 0xAC, 0x02, 0x23, 0x22, 0x1A, 0xD3, 0x61, 0x8C, 0xEF, 0x26, 0xD4, 0x18, + 0x7F, 0xF8, 0x91, 0xBF, 0x36, 0xB8, 0x48, 0x53, 0xFC, 0x21, 0x3C, 0xBA, 0xDD, 0x88, 0x04, 0x6D, + 0x3F, 0xB0, 0x6C, 0x5B, 0x9F, 0xBC, 0x21, 0x81, 0xF6, 0x01, 0x0F, 0x15, 0x9F, 0xBA, 0x8B, 0x61, + 0x11, 0xCF, 0xDC, 0x06, 0x1E, 0x31, 0x56, 0xFA, 0xE4, 0x03, 0xBE, 0x50, 0x19, 0x70, 0xE1, 0x59, + 0x79, 0x64, 0x54, 0x88, 0xC4, 0xF1, 0x5C, 0x20, 0x2A, 0x54, 0x12, 0x7F, 0x51, 0xA3, 0xAE, 0x89, + 0xA3, 0xD8, 0xB5, 0xC9, 0x25, 0x6D, 0xAC, 0xA1, 0x95, 0x15, 0x77, 0x17, 0x7F, 0x1C, 0x30, 0xDF, + 0x39, 0xE8, 0x03, 0xC0, 0xF8, 0x44, 0x6F, 0xF2, 0x7D, 0xEB, 0xA0, 0x56, 0xF6, 0x7C, 0xFF, 0xE4, + 0xCC, 0x5F, 0x1B, 0x8E, 0x68, 0x46, 0x1F, 0x7E, 0xBF, 0xE6, 0x4F, 0x33, 0x4F, 0x5D, 0xDB, 0xFC, + 0x2A, 0xB6, 0xF0, 0xFF, 0x21, 0x7C, 0x2C, 0x17, 0x41, 0xC0, 0x2E, 0x04, 0x86, 0x02, 0xE5, 0x2E, + 0x3D, 0x81, 0x9E, 0x3D, 0x41, 0x8D, 0x6F, 0xEB, 0xCA, 0xD1, 0x6E, 0xC6, 0x93, 0xC4, 0x1E, 0x59, + 0x84, 0x92, 0x94, 0x3D, 0x61, 0x2E, 0x7D, 0xAE, 0xF8, 0x7B, 0xB2, 0xB0, 0x7C, 0xA0, 0x51, 0x03, + 0xBB, 0x38, 0xA4, 0xCF, 0x62, 0x32, 0x5B, 0x56, 0x7B, 0xCE, 0x37, 0xDE, 0x25, 0x7F, 0x4D, 0x81, + 0xF4, 0xF1, 0xED, 0x52, 0xA9, 0x63, 0xFA, 0x59, 0xEB, 0x24, 0xC6, 0x22, 0xAB, 0x7F, 0xDA, 0x6E, + 0x2F, 0x87, 0xF8, 0x54, 0xA9, 0x26, 0x58, 0x3B, 0x3B, 0x5C, 0x0E, 0x8B, 0x9E, 0xDA, 0x2B, 0x7C, + 0x24, 0x18, 0x38, 0xAD, 0xFC, 0x44, 0x30, 0x4A, 0x69, 0x02, 0xD4, 0x1C, 0x68, 0xEF, 0x0C, 0xFF, + 0xF3, 0x81, 0xF6, 0x11, 0x87, 0xF8, 0x06, 0x1F, 0x0C, 0x46, 0xDA, 0x0D, 0xD3, 0xF4, 0x32, 0x1F, + 0x0E, 0x1E, 0x26, 0x1E, 0x0E, 0x1E, 0x8B, 0x87, 0x83, 0xA3, 0x95, 0xAA, 0xEE, 0xCD, 0xA0, 0xDB, + 0x3D, 0x56, 0x61, 0x5D, 0xF1, 0x01, 0xE1, 0x7B, 0xE1, 0x69, 0x05, 0xD2, 0x54, 0xE4, 0x69, 0x28, + 0x78, 0x8A, 0x6D, 0xD8, 0xBF, 0x99, 0xCF, 0x1F, 0x1B, 0x47, 0x7C, 0xC9, 0xB0, 0x3A, 0x4B, 0xDD, + 0x7E, 0xD3, 0x4F, 0x71, 0x53, 0xE3, 0xBE, 0xAF, 0x87, 0xB8, 0x69, 0x93, 0x74, 0x34, 0x1C, 0xE5, + 0x06, 0x43, 0x0A, 0xC2, 0x9C, 0xFE, 0xCD, 0x7D, 0x3A, 0xFD, 0xA2, 0x86, 0xD3, 0x2F, 0xB6, 0x9C, + 0xBE, 0x41, 0x6F, 0x17, 0x84, 0xFF, 0xD5, 0x3C, 0x5E, 0xF0, 0x55, 0xC2, 0xEB, 0xA5, 0x7C, 0x75, + 0xBB, 0xF7, 0xEA, 0xF7, 0x85, 0x4E, 0x12, 0x1A, 0xC3, 0x9B, 0xFB, 0x74, 0x92, 0x0C, 0xD3, 0xAD, + 0x64, 0xA7, 0x3C, 0xEC, 0x4C, 0x9A, 0x19, 0x97, 0x68, 0x36, 0x15, 0x57, 0x28, 0xEF, 0x1D, 0x1F, + 0xD7, 0x1D, 0x0C, 0x79, 0xEA, 0x74, 0x1F, 0xEA, 0x51, 0x7F, 0x61, 0x44, 0x66, 0x93, 0xFB, 0x49, + 0xCC, 0xD6, 0xB1, 0x14, 0x57, 0x39, 0x31, 0x7B, 0xFF, 0xED, 0xB7, 0xE5, 0x72, 0xB1, 0x78, 0x2F, + 0x8F, 0x24, 0x17, 0xCB, 0x2D, 0x53, 0xDF, 0xAE, 0xE1, 0x06, 0x52, 0x5D, 0xC9, 0x74, 0x23, 0x70, + 0x7D, 0xF2, 0x8A, 0x1E, 0x6B, 0x31, 0x89, 0x95, 0x32, 0x5E, 0xE5, 0x59, 0x27, 0x05, 0x8C, 0xD5, + 0xB1, 0x23, 0x12, 0xD2, 0xBA, 0x51, 0xC4, 0x95, 0x53, 0xBB, 0x8E, 0xB1, 0xA7, 0xCE, 0x54, 0x6D, + 0x9F, 0xA0, 0x4D, 0x8A, 0x52, 0xE1, 0xD5, 0xC6, 0xAE, 0xAC, 0x36, 0x0E, 0xAB, 0x4F, 0xDE, 0xC1, + 0x64, 0xDC, 0x5A, 0xDB, 0x16, 0xCC, 0x3C, 0x5A, 0x5D, 0xAD, 0xAD, 0x0D, 0x7A, 0xFB, 0x0D, 0x8E, + 0x91, 0x82, 0x8C, 0x92, 0x6F, 0xCB, 0xE9, 0x45, 0x0F, 0xB3, 0x0D, 0xEE, 0xE9, 0x75, 0x39, 0x75, + 0x15, 0xE2, 0xB9, 0x6E, 0x50, 0x59, 0x1B, 0x02, 0x18, 0x12, 0x15, 0x38, 0xD2, 0x22, 0x9D, 0xA8, + 0xAB, 0x22, 0xB6, 0xB5, 0x36, 0xC2, 0xA6, 0xA6, 0x0E, 0xA5, 0x8D, 0xB4, 0xB8, 0x3F, 0x45, 0x75, + 0x07, 0xAA, 0x04, 0x6B, 0x4F, 0x9F, 0xF4, 0x4B, 0x60, 0x28, 0xDE, 0x87, 0xCA, 0x5A, 0xD5, 0x77, + 0x22, 0xFF, 0xB6, 0x7A, 0xEC, 0xE3, 0xB0, 0x90, 0x76, 0xDF, 0x42, 0xAA, 0xBB, 0xD2, 0x5E, 0x43, + 0x5F, 0xD4, 0x89, 0x7A, 0xA3, 0x26, 0x9D, 0x48, 0x90, 0x51, 0xDD, 0x89, 0x7A, 0x8F, 0xC3, 0x87, + 0x50, 0x1F, 0x6B, 0x8F, 0x54, 0xD6, 0x07, 0x87, 0xD5, 0x27, 0xEF, 0x3D, 0x82, 0xCA, 0xA8, 0xE4, + 0x3D, 0x21, 0x92, 0x6A, 0xCE, 0x73, 0x0F, 0x8E, 0xD2, 0xEB, 0x8C, 0xEA, 0xE1, 0xE8, 0x97, 0x73, + 0x36, 0x09, 0x86, 0x81, 0x3C, 0x08, 0x0C, 0x1E, 0xA7, 0x0B, 0x13, 0xDB, 0x1C, 0x55, 0x77, 0x62, + 0x01, 0x8D, 0xB3, 0x67, 0x38, 0xAC, 0x6C, 0x38, 0x31, 0x44, 0x8F, 0x2A, 0xEE, 0xD6, 0xC4, 0x70, + 0x1F, 0xC6, 0x34, 0xE9, 0x97, 0x32, 0xE9, 0x66, 0x4C, 0x67, 0x8D, 0x2F, 0x17, 0x24, 0x6A, 0x7B, + 0x3E, 0x29, 0xB2, 0x78, 0xA4, 0x61, 0xB0, 0x10, 0x69, 0xE8, 0xEB, 0x05, 0xE9, 0x5E, 0xF7, 0x46, + 0x73, 0x5E, 0x41, 0xC0, 0xF6, 0x32, 0x4B, 0xF9, 0xAD, 0x01, 0x31, 0xE6, 0x64, 0x29, 0x70, 0xC8, + 0xEB, 0x63, 0xCB, 0x7F, 0x29, 0x61, 0x95, 0xC7, 0x0A, 0x0E, 0xCC, 0x55, 0x18, 0x0E, 0xDD, 0xCD, + 0xE6, 0xBF, 0x21, 0x15, 0x35, 0xC6, 0xEE, 0x06, 0x13, 0xE0, 0xD8, 0xB2, 0x11, 0x55, 0x00, 0x0B, + 0x9A, 0x01, 0x9B, 0xF1, 0x95, 0x58, 0x09, 0xCA, 0x6C, 0x72, 0x3F, 0xF3, 0xFC, 0x6B, 0xCB, 0x29, + 0x3F, 0xCF, 0xFF, 0xC9, 0x72, 0x4C, 0xF7, 0xBA, 0xDC, 0x54, 0x3F, 0xDE, 0xD1, 0x9F, 0x60, 0xAA, + 0x4F, 0x07, 0x4B, 0x5C, 0x2C, 0x6C, 0x7B, 0x44, 0xED, 0xA5, 0x33, 0x69, 0x21, 0x33, 0xE8, 0x1B, + 0x5C, 0x6A, 0x03, 0x14, 0xBE, 0x46, 0x97, 0x1E, 0x77, 0xED, 0x2F, 0x3F, 0x9F, 0xC6, 0x93, 0x5D, + 0x4E, 0x81, 0x9A, 0xC3, 0x0C, 0x25, 0x85, 0xC7, 0x07, 0xAF, 0xA5, 0xFE, 0xB2, 0xCD, 0xCF, 0xED, + 0x83, 0xF3, 0x73, 0x1F, 0x01, 0x99, 0x38, 0x66, 0x65, 0xCB, 0x42, 0xD8, 0xC8, 0xAE, 0x2E, 0x1D, + 0xB3, 0x51, 0xAB, 0x62, 0xBD, 0x57, 0xD6, 0x41, 0xBF, 0x7B, 0x74, 0xF2, 0xB8, 0xCC, 0x0A, 0x19, + 0xAA, 0x61, 0x54, 0xBD, 0xD1, 0xF0, 0xE8, 0xF1, 0xD8, 0x95, 0x3B, 0x9F, 0xB3, 0x15, 0xAE, 0x6A, + 0xA6, 0xC5, 0xC1, 0x6F, 0xE8, 0xA3, 0xB4, 0x3E, 0x69, 0x36, 0x5E, 0x85, 0x9D, 0xAB, 0xE9, 0x62, + 0x20, 0xD1, 0xC5, 0xF8, 0x71, 0x99, 0x16, 0xE7, 0x48, 0xD5, 0xBA, 0x24, 0x1C, 0xDD, 0x13, 0x43, + 0xF7, 0x61, 0x5A, 0x81, 0x1B, 0x18, 0x76, 0x65, 0xCB, 0x62, 0xD0, 0x60, 0x58, 0x3F, 0xE0, 0x81, + 0xF6, 0x01, 0xF8, 0x6C, 0xD4, 0xB8, 0x44, 0xFF, 0xD5, 0x03, 0xD7, 0xA0, 0xFB, 0xC8, 0xC6, 0x43, + 0xC6, 0x52, 0xAD, 0xD0, 0x35, 0x1E, 0x3E, 0x1E, 0xFB, 0x72, 0x37, 0x01, 0x5E, 0xAD, 0x1C, 0xBA, + 0x18, 0x38, 0x86, 0x2E, 0x7A, 0xD4, 0xBC, 0x89, 0x85, 0x14, 0xD4, 0x18, 0x1C, 0x87, 0x0F, 0xBF, + 0x7E, 0xFD, 0x8B, 0x84, 0xA7, 0x5A, 0x46, 0x36, 0x78, 0x2C, 0x41, 0x6C, 0x66, 0x28, 0xBF, 0x88, + 0x8D, 0x22, 0x8B, 0x67, 0xF3, 0x0C, 0x16, 0xE6, 0x70, 0xEC, 0xA0, 0xD1, 0x0A, 0x86, 0xE8, 0xFC, + 0xDE, 0x97, 0xEC, 0x42, 0xAE, 0x1E, 0x53, 0xBD, 0x62, 0x6A, 0x39, 0x4E, 0x55, 0x35, 0x71, 0x58, + 0x7D, 0xF2, 0x8A, 0x1D, 0x34, 0xBB, 0xB8, 0xCA, 0x3B, 0xBF, 0xFF, 0x95, 0x55, 0xC1, 0x55, 0xD3, + 0x6A, 0x4A, 0x15, 0x31, 0xBC, 0xF0, 0x4B, 0x11, 0x3A, 0xDF, 0xAD, 0x18, 0x7D, 0x39, 0xE2, 0xF1, + 0x94, 0x34, 0x16, 0xC6, 0x0A, 0x9F, 0x30, 0x2E, 0x5B, 0xD4, 0x78, 0x83, 0x60, 0xE5, 0x6A, 0x1A, + 0xC9, 0x9E, 0x1E, 0x77, 0x55, 0x63, 0x92, 0x7C, 0xB5, 0x24, 0x10, 0xDE, 0x9E, 0x5A, 0x86, 0x8F, + 0x4F, 0xE3, 0xC3, 0xB1, 0xF6, 0x0A, 0x8E, 0xB5, 0xF7, 0xF6, 0x26, 0x7C, 0x37, 0xAE, 0xCC, 0x21, + 0xE2, 0x3B, 0x9B, 0x22, 0x0C, 0x59, 0xDB, 0xD7, 0xE9, 0x86, 0x2E, 0xFE, 0x14, 0x16, 0x1C, 0xE3, + 0x3E, 0xA6, 0xD1, 0xF0, 0xB8, 0xAB, 0x6B, 0x2C, 0x2B, 0xE6, 0xCF, 0x90, 0xF8, 0x9F, 0xE9, 0x06, + 0xA7, 0x5E, 0x48, 0xA0, 0xCC, 0x01, 0xE2, 0xF4, 0x86, 0x04, 0x52, 0xFB, 0xAD, 0xB3, 0xEF, 0x68, + 0x5B, 0x22, 0x3D, 0x21, 0x8E, 0xAE, 0xD4, 0x10, 0x12, 0x2F, 0xC3, 0x64, 0xED, 0x55, 0x9E, 0x86, + 0x91, 0x0B, 0xA2, 0x27, 0x15, 0x04, 0xEE, 0xF3, 0xBA, 0x5F, 0x9E, 0xFA, 0x82, 0xA7, 0x9E, 0x1A, + 0x4F, 0xFD, 0x1A, 0x3C, 0xF5, 0x1B, 0xE2, 0x69, 0x20, 0x78, 0xEA, 0xAB, 0xF1, 0x34, 0xA8, 0xC1, + 0xD3, 0xA0, 0x21, 0x9E, 0x86, 0x82, 0xA7, 0x81, 0x1A, 0x4F, 0xC3, 0x1A, 0x3C, 0x0D, 0x1B, 0xE2, + 0x69, 0x24, 0x78, 0x1A, 0xAA, 0xF1, 0x34, 0xAA, 0xC1, 0xD3, 0xA8, 0x21, 0x9E, 0xC6, 0x82, 0xA7, + 0x91, 0x1A, 0x4F, 0xE3, 0x1A, 0x3C, 0x8D, 0x1B, 0xE2, 0xE9, 0x48, 0xF0, 0x34, 0x56, 0xE3, 0xE9, + 0xA8, 0x06, 0x4F, 0x47, 0x0D, 0xF1, 0x74, 0x2C, 0x78, 0x3A, 0x52, 0xE3, 0xE9, 0xB8, 0x06, 0x4F, + 0xC7, 0x0D, 0xF1, 0x74, 0x22, 0x78, 0x3A, 0x56, 0xE3, 0xE9, 0xA4, 0x06, 0x4F, 0x27, 0x0D, 0xF1, + 0x84, 0x8B, 0x72, 0x8C, 0xA9, 0x13, 0xC5, 0x41, 0xB7, 0x5B, 0x83, 0x2B, 0xA3, 0x29, 0xAE, 0xC2, + 0x54, 0xA2, 0xA7, 0x9A, 0x4B, 0xD4, 0x49, 0x26, 0xA6, 0x4D, 0xB1, 0x15, 0x65, 0x13, 0x8A, 0xE9, + 0x44, 0xAF, 0x4E, 0x3E, 0x31, 0x6B, 0x8A, 0xAD, 0x30, 0xA1, 0xE8, 0x29, 0x66, 0x14, 0xBD, 0x3A, + 0x29, 0x85, 0xD9, 0x14, 0x5B, 0x61, 0x4E, 0xD1, 0x53, 0x4C, 0x2A, 0x7A, 0x75, 0xB2, 0x0A, 0xD2, + 0x14, 0x5B, 0x61, 0x5A, 0xD1, 0x53, 0xCC, 0x2B, 0x7A, 0x75, 0x12, 0x8B, 0x79, 0x53, 0x6C, 0x85, + 0x99, 0x45, 0x4F, 0x31, 0xB5, 0xE8, 0xD5, 0xC8, 0x2D, 0x4E, 0xE4, 0x13, 0xB1, 0x7B, 0x65, 0x8B, + 0x04, 0x7C, 0x8A, 0x1C, 0x4D, 0xDA, 0x94, 0x1E, 0x3D, 0xE1, 0x40, 0xF8, 0x6C, 0x14, 0x13, 0xC8, + 0x85, 0xEB, 0xCC, 0xAD, 0x45, 0x58, 0x64, 0x78, 0x34, 0x4F, 0x49, 0xF8, 0xB1, 0xB7, 0xF2, 0x2A, + 0x17, 0x1A, 0x3E, 0xBC, 0xBE, 0x2C, 0x57, 0x66, 0x88, 0xF7, 0xF2, 0x27, 0x2A, 0x32, 0x00, 0xD9, + 0xFD, 0xF8, 0x27, 0x02, 0x94, 0xEA, 0x0A, 0x14, 0xA8, 0x4C, 0x45, 0x61, 0x14, 0xAF, 0x28, 0x8C, + 0x95, 0x2B, 0x0A, 0x8C, 0xB8, 0xDD, 0xD4, 0x12, 0x00, 0xF7, 0x80, 0x7D, 0xD7, 0x40, 0x9D, 0xE9, + 0x41, 0x75, 0xA6, 0x47, 0x65, 0x98, 0x1E, 0x54, 0x61, 0xBA, 0xC2, 0xD3, 0x8D, 0x8A, 0x72, 0x02, + 0x7A, 0xBF, 0xB6, 0x6E, 0x88, 0xA9, 0xFD, 0xA2, 0x2E, 0xAA, 0x5E, 0x75, 0x51, 0x1D, 0x95, 0x11, + 0x55, 0x6F, 0x87, 0xF6, 0x31, 0x12, 0x7C, 0xFF, 0xA8, 0xCE, 0xF7, 0xA8, 0x3A, 0xDF, 0x83, 0x32, + 0x7C, 0x8F, 0x76, 0xC8, 0xF7, 0x50, 0xF0, 0xFD, 0x51, 0x9D, 0xEF, 0x61, 0x75, 0xBE, 0x87, 0x65, + 0xF8, 0x1E, 0xEE, 0x90, 0xEF, 0x3E, 0x04, 0x9B, 0x1F, 0x3F, 0x6A, 0x3F, 0x2C, 0x3D, 0xE2, 0x2F, + 0x8B, 0x2B, 0x71, 0x0C, 0xA2, 0xEA, 0xD8, 0x3E, 0x6A, 0x60, 0xEE, 0x86, 0x14, 0x0E, 0xE2, 0x3C, + 0x15, 0xE6, 0xCD, 0x0C, 0x42, 0xE5, 0xC3, 0x41, 0x72, 0x9E, 0xE4, 0x33, 0xB7, 0x9E, 0x2A, 0x53, + 0xBB, 0x8B, 0x61, 0xC7, 0xFA, 0xE4, 0xED, 0xA6, 0xC4, 0xF8, 0x76, 0x5C, 0xDD, 0x9E, 0xD5, 0x2B, + 0xE6, 0x8C, 0xAE, 0x9D, 0xD9, 0xF3, 0x09, 0xE5, 0x19, 0xF2, 0x32, 0x5F, 0x41, 0xED, 0xD5, 0xAB, + 0x10, 0xA3, 0x06, 0xAA, 0xE4, 0x18, 0xE9, 0x8F, 0x18, 0x3B, 0x3F, 0x22, 0x43, 0x1A, 0x64, 0x2C, + 0x25, 0x06, 0xA3, 0xA3, 0x92, 0xDA, 0x3C, 0xAE, 0x18, 0x9D, 0x90, 0xC6, 0x9D, 0xA9, 0x13, 0xA7, + 0x1E, 0x28, 0x80, 0x8F, 0x15, 0x04, 0x30, 0xAE, 0x2E, 0x80, 0x52, 0x99, 0x0B, 0xD2, 0xB8, 0x3B, + 0x01, 0x74, 0x99, 0x00, 0x3E, 0x44, 0x6F, 0xA6, 0xCE, 0x31, 0xE8, 0x1A, 0x15, 0xA8, 0x51, 0x03, + 0x6B, 0x24, 0x18, 0x69, 0x7B, 0xC2, 0xA2, 0x81, 0xA3, 0x72, 0x0A, 0xED, 0x97, 0xCD, 0xAF, 0xE4, + 0xC5, 0x4F, 0x85, 0xFC, 0x7B, 0x97, 0x09, 0x56, 0xBF, 0x2B, 0x2C, 0xBA, 0xBC, 0x00, 0xBA, 0xD5, + 0x05, 0xD0, 0x2B, 0x25, 0x80, 0xEE, 0xE3, 0x4A, 0xC6, 0xC7, 0xDB, 0x1F, 0x13, 0x2E, 0x96, 0x56, + 0x59, 0xF7, 0x8F, 0x8D, 0x66, 0xFD, 0x32, 0xC2, 0xDA, 0xA9, 0xF7, 0x0F, 0x22, 0xCE, 0xB5, 0x5F, + 0xB4, 0xE4, 0xD6, 0xD7, 0xBC, 0x38, 0x50, 0xBD, 0x08, 0x38, 0x6A, 0x60, 0xBD, 0x0A, 0x29, 0x3C, + 0x91, 0x70, 0x56, 0x32, 0xC0, 0x9F, 0x54, 0x77, 0x87, 0x52, 0x1A, 0x46, 0x5A, 0x77, 0xA7, 0xE2, + 0x51, 0x42, 0x10, 0xEC, 0x43, 0xE6, 0x2A, 0x2A, 0xAE, 0x5E, 0x39, 0x1C, 0x35, 0xB0, 0xD4, 0x85, + 0x14, 0x1E, 0x4B, 0x38, 0x2B, 0xA9, 0xE2, 0xB2, 0x29, 0xE9, 0x71, 0xC5, 0xA9, 0x65, 0x6F, 0x97, + 0x39, 0x29, 0x56, 0xBB, 0x63, 0x82, 0x88, 0x7F, 0x65, 0x22, 0x4F, 0xC1, 0xD5, 0x2B, 0xDE, 0xA3, + 0x9A, 0xEB, 0xB3, 0xBB, 0x8B, 0xE4, 0x47, 0xB2, 0x4F, 0x90, 0x17, 0xDB, 0x41, 0xD9, 0x5C, 0xB6, + 0x5B, 0x71, 0xE0, 0xDB, 0x69, 0x2A, 0x0B, 0xBD, 0x43, 0xD6, 0xB3, 0xCD, 0x7D, 0x8E, 0x09, 0x54, + 0x5F, 0x79, 0x1B, 0x35, 0xB0, 0x3D, 0x04, 0x29, 0xEC, 0xEB, 0x93, 0x8F, 0x25, 0x99, 0xAA, 0x53, + 0x3F, 0xA8, 0xBC, 0x3F, 0xA4, 0xB9, 0xD2, 0xFB, 0x6C, 0x75, 0x53, 0xBE, 0xF4, 0x7E, 0xF1, 0xEE, + 0xE7, 0x72, 0xA5, 0xF7, 0x78, 0x2F, 0xCD, 0x95, 0xDE, 0xAB, 0xD9, 0x4C, 0xA9, 0x8D, 0xB2, 0xC0, + 0x18, 0xBE, 0x3F, 0x62, 0x66, 0xF9, 0xB4, 0x4B, 0x10, 0x8C, 0xF6, 0x5E, 0x9C, 0x86, 0x22, 0x8A, + 0x3D, 0xB1, 0x9F, 0x6C, 0x9F, 0x67, 0x3D, 0x83, 0x9C, 0xB0, 0xA0, 0xB6, 0x11, 0x76, 0xFB, 0x75, + 0x28, 0x9D, 0x31, 0xFF, 0x10, 0x57, 0x8D, 0x47, 0xEB, 0xB3, 0x5E, 0x1A, 0xD0, 0x39, 0x2A, 0x89, + 0x7B, 0xE7, 0x8F, 0xDC, 0x4F, 0x52, 0x8A, 0xEA, 0x51, 0xFD, 0xF4, 0xF0, 0x5C, 0xB9, 0x4E, 0x4E, + 0xC1, 0xCA, 0x44, 0xF3, 0x41, 0xBC, 0xD4, 0xA2, 0x1E, 0xCD, 0x19, 0x79, 0xBB, 0x89, 0xE6, 0x88, + 0x3B, 0xC1, 0x7B, 0x89, 0xAC, 0x86, 0xC1, 0x96, 0x13, 0x80, 0x7C, 0x13, 0x85, 0x82, 0x00, 0xB2, + 0x24, 0x70, 0x2F, 0x22, 0xE8, 0x53, 0x09, 0xF4, 0x53, 0xDA, 0xCF, 0x08, 0xFC, 0xB4, 0x7D, 0xD5, + 0xB8, 0x3F, 0x68, 0xA0, 0x36, 0x81, 0xE2, 0x4A, 0x70, 0x54, 0x52, 0xA7, 0xE5, 0x16, 0x07, 0x13, + 0x3A, 0x2D, 0x67, 0xD4, 0x3B, 0x5B, 0x1D, 0x04, 0xE4, 0x03, 0x2A, 0x80, 0x81, 0xB2, 0x4A, 0xAB, + 0x4F, 0x33, 0x07, 0x0D, 0xE4, 0x27, 0x28, 0xAD, 0x04, 0x47, 0x25, 0x55, 0x5A, 0x6E, 0xE9, 0x33, + 0xA1, 0x52, 0xF5, 0xF9, 0x25, 0x27, 0x72, 0x67, 0x2A, 0x1D, 0x52, 0x01, 0x0C, 0x95, 0x55, 0x5A, + 0x7D, 0xD6, 0x31, 0x68, 0x60, 0xF7, 0x2E, 0x4A, 0x2B, 0xC1, 0x51, 0x49, 0x95, 0x96, 0x5B, 0xB2, + 0x4B, 0xA8, 0x54, 0x7D, 0x3E, 0xC9, 0x89, 0xDC, 0x99, 0x4A, 0x47, 0x54, 0x00, 0x23, 0x65, 0x95, + 0x56, 0xAF, 0x14, 0x0C, 0x1A, 0x28, 0x06, 0xA1, 0xB4, 0x12, 0x1C, 0x95, 0x54, 0x69, 0xB9, 0xD5, + 0xE7, 0x84, 0x4A, 0xD5, 0xD7, 0x39, 0x38, 0x91, 0x3B, 0x53, 0xE9, 0x98, 0x0A, 0x60, 0xAC, 0xAC, + 0xD2, 0xEA, 0xFB, 0xAB, 0x06, 0x0D, 0xEC, 0xDD, 0x46, 0x69, 0x25, 0x38, 0x2A, 0xA9, 0xD2, 0x72, + 0xA5, 0xDB, 0x84, 0x4A, 0xD5, 0x57, 0x6E, 0x38, 0x91, 0x3B, 0x53, 0xE9, 0x11, 0x15, 0xC0, 0x91, + 0xB2, 0x4A, 0xAB, 0x6F, 0x5D, 0x1F, 0x34, 0x50, 0xCF, 0x43, 0x69, 0x25, 0x38, 0x2A, 0xA9, 0xD2, + 0x72, 0x15, 0x9C, 0x84, 0x4A, 0xD5, 0xF7, 0x4E, 0x71, 0x22, 0x77, 0xA6, 0xD2, 0x63, 0x2A, 0x80, + 0x63, 0x65, 0x95, 0x56, 0xDF, 0xB9, 0x3F, 0x68, 0x60, 0xE7, 0x3E, 0x4A, 0x2B, 0xC1, 0x51, 0x49, + 0x95, 0x96, 0xAB, 0xCD, 0x26, 0x54, 0xAA, 0xBE, 0xDD, 0x89, 0x13, 0xB9, 0x33, 0x95, 0x9E, 0x50, + 0x01, 0x9C, 0x28, 0xAB, 0xB4, 0xFA, 0x96, 0x81, 0x41, 0x03, 0x9B, 0x5F, 0x50, 0x5A, 0xDD, 0x38, + 0x47, 0x25, 0x55, 0x5A, 0x6E, 0x81, 0x71, 0x90, 0xB1, 0xF5, 0x45, 0x41, 0xA5, 0x59, 0x0B, 0x8C, + 0x8F, 0xA0, 0x7E, 0x67, 0x5C, 0x4F, 0x2B, 0x7C, 0xFA, 0xE5, 0xE5, 0x4F, 0xAF, 0xB2, 0x0B, 0xFB, + 0x99, 0x55, 0xBC, 0x44, 0x5F, 0x8F, 0xBD, 0x8C, 0x17, 0x97, 0x17, 0x12, 0x0E, 0x5A, 0x66, 0x2F, + 0x4D, 0xD4, 0xB6, 0x98, 0xCF, 0xB7, 0x34, 0x06, 0x5C, 0xC2, 0xD2, 0x06, 0xC3, 0xAE, 0x3C, 0x69, + 0x29, 0xB0, 0x34, 0x4E, 0xE5, 0x6E, 0x82, 0x07, 0x22, 0x87, 0xB9, 0x38, 0xF2, 0xFE, 0xBD, 0xD2, + 0x9A, 0x0E, 0x03, 0x48, 0x86, 0x8F, 0x61, 0xF7, 0x44, 0x31, 0x7E, 0x80, 0x0C, 0xB2, 0x36, 0xC6, + 0xDF, 0x63, 0x00, 0x41, 0x1A, 0x07, 0x8C, 0xA9, 0x37, 0xCA, 0x4C, 0xA5, 0xAB, 0x00, 0xA5, 0x98, + 0xCA, 0xAA, 0xEC, 0xDC, 0x33, 0x53, 0x43, 0xC6, 0x54, 0x8E, 0x93, 0xA6, 0x98, 0x4A, 0xCF, 0x83, + 0x4B, 0x31, 0x95, 0x35, 0x11, 0x8E, 0x98, 0x7A, 0x0C, 0x81, 0x8E, 0xCC, 0x8C, 0xC5, 0xAC, 0x42, + 0xA8, 0xBB, 0xBC, 0x38, 0x7C, 0xF9, 0xE6, 0x42, 0xA3, 0x4B, 0x9A, 0xAE, 0x5D, 0x32, 0xE2, 0x25, + 0x3B, 0xFD, 0x53, 0xC5, 0x3C, 0x4A, 0x7A, 0x2C, 0xEA, 0xBD, 0xB9, 0x50, 0x0D, 0x78, 0x1C, 0xB2, + 0x4C, 0xC8, 0x1B, 0x75, 0x07, 0x55, 0x2A, 0x84, 0x21, 0x91, 0x3B, 0x0A, 0x7A, 0x14, 0x7D, 0x3F, + 0x92, 0xC1, 0x65, 0x39, 0x19, 0x94, 0xAA, 0x92, 0x26, 0x65, 0x50, 0x22, 0xEC, 0x0B, 0x22, 0x77, + 0x29, 0x03, 0x8C, 0x92, 0x97, 0x17, 0xDA, 0xFB, 0xBF, 0x6B, 0x97, 0x37, 0x6B, 0xD7, 0xDF, 0x78, + 0xA4, 0x30, 0xAA, 0x70, 0xB8, 0x64, 0x5C, 0x19, 0x8F, 0x46, 0x03, 0xD5, 0xC0, 0x32, 0xCA, 0x1E, + 0x02, 0xE6, 0xDD, 0x7B, 0x8C, 0x97, 0x94, 0xD0, 0x61, 0xC8, 0xE0, 0xF7, 0x04, 0x34, 0xAD, 0x14, + 0x37, 0x39, 0x60, 0x92, 0xC3, 0x5E, 0x17, 0xB7, 0x57, 0x2B, 0x32, 0x28, 0xCF, 0x28, 0x07, 0xF7, + 0x3A, 0x1C, 0x50, 0x2A, 0x47, 0x21, 0x7B, 0x1F, 0x7F, 0xF8, 0xA0, 0xC6, 0x58, 0xBA, 0x8E, 0x56, + 0x4E, 0x75, 0x59, 0x8F, 0x8C, 0xDE, 0xD3, 0xA0, 0x20, 0xBD, 0x71, 0x76, 0x08, 0xA1, 0x77, 0x1B, + 0x26, 0x43, 0x92, 0x67, 0x73, 0x6B, 0x01, 0x76, 0x2C, 0xEF, 0x83, 0x8A, 0x96, 0xBD, 0xEC, 0x14, + 0xBF, 0x51, 0xD9, 0x9E, 0x41, 0xF4, 0x07, 0x93, 0x40, 0xA7, 0x13, 0x02, 0x5F, 0x19, 0x0B, 0x12, + 0x5D, 0xD7, 0x58, 0x6C, 0xCF, 0x8B, 0xD9, 0x06, 0x43, 0x68, 0x5C, 0x11, 0xFE, 0x41, 0x4D, 0x6D, + 0xE9, 0x91, 0xF9, 0xB9, 0xFE, 0x45, 0x88, 0x93, 0x3F, 0x95, 0x87, 0x4D, 0x74, 0xCD, 0x74, 0xAF, + 0x1D, 0xDB, 0x35, 0x70, 0x3C, 0x30, 0xD6, 0x01, 0x50, 0xDA, 0xF9, 0x6D, 0x8D, 0x2F, 0xBE, 0x32, + 0xF0, 0x21, 0x2E, 0x23, 0xA7, 0x9F, 0x98, 0x55, 0xCC, 0x6C, 0xD7, 0x17, 0xB3, 0x39, 0x3C, 0x0C, + 0x3F, 0xC0, 0xF9, 0x3F, 0xFF, 0x5D, 0xB4, 0x83, 0xC0, 0x5A, 0x2D, 0x62, 0x02, 0xD0, 0x35, 0xDF, + 0x9B, 0x9D, 0xEB, 0x40, 0xA9, 0xE7, 0xFA, 0xBE, 0xEB, 0x59, 0x0B, 0x2B, 0x43, 0x3B, 0x59, 0xD2, + 0x3E, 0x94, 0x89, 0x3B, 0xD5, 0x58, 0xA2, 0xF8, 0x33, 0x7F, 0xE6, 0x59, 0xEB, 0x60, 0xF2, 0xC4, + 0x74, 0x67, 0x9B, 0x15, 0x71, 0x82, 0x8E, 0x61, 0x9A, 0x97, 0x57, 0x70, 0xF0, 0x2D, 0x7E, 0xAC, + 0x0D, 0x24, 0xDF, 0xDA, 0x7B, 0xFD, 0x8F, 0x77, 0x38, 0x3A, 0xE3, 0x35, 0x90, 0x17, 0x31, 0xF7, + 0x0E, 0xB4, 0xF9, 0xC6, 0x61, 0x03, 0x64, 0x8B, 0x60, 0xDB, 0x7D, 0xED, 0x0F, 0xC0, 0x78, 0x65, + 0x78, 0xDA, 0xD4, 0xF0, 0xC9, 0x5B, 0xD7, 0x0F, 0xB4, 0x73, 0x2D, 0xC4, 0x68, 0xBB, 0x33, 0xBA, + 0x9D, 0xA3, 0xC3, 0xF8, 0xE2, 0x2D, 0x19, 0xE3, 0x3F, 0x7A, 0x36, 0x34, 0x0D, 0xA1, 0x9E, 0x6B, + 0x7B, 0xA7, 0xC7, 0xBD, 0x3D, 0xB4, 0xDD, 0xB0, 0x8B, 0x39, 0x81, 0xE8, 0x0F, 0xED, 0x5A, 0x1B, + 0xCF, 0x3E, 0xD0, 0x66, 0xD3, 0xFD, 0x3F, 0x28, 0xF5, 0xF4, 0x32, 0x5E, 0xDB, 0xE7, 0xCC, 0x74, + 0x82, 0x25, 0x71, 0x5A, 0x11, 0x65, 0x1E, 0xF1, 0xD7, 0xAE, 0xE3, 0x13, 0x46, 0x1C, 0xFB, 0x59, + 0xF3, 0xE8, 0x7A, 0xC7, 0x0F, 0x8C, 0x60, 0xE3, 0x6B, 0x4F, 0xCF, 0xCF, 0xB5, 0x7E, 0xB7, 0x1B, + 0x6F, 0xA6, 0x41, 0x37, 0xE9, 0x76, 0x07, 0x5A, 0xEA, 0xC2, 0x0F, 0xE4, 0x26, 0xD8, 0xFF, 0x2A, + 0x84, 0xB9, 0xD3, 0x88, 0xED, 0x93, 0x04, 0x92, 0x10, 0x00, 0x5F, 0x27, 0xD7, 0xDA, 0x4F, 0x12, + 0xD8, 0x32, 0x8D, 0xC0, 0xD8, 0xFF, 0x23, 0xA1, 0x2F, 0xE8, 0x15, 0x28, 0x39, 0xD0, 0xE8, 0xAD, + 0xAF, 0x62, 0xB7, 0xEE, 0xF6, 0x3B, 0x20, 0x43, 0xE0, 0x37, 0x84, 0x26, 0x9E, 0x97, 0xA4, 0x98, + 0x42, 0xB7, 0x7B, 0x07, 0x1A, 0xDE, 0x49, 0xC2, 0xC6, 0x88, 0x7C, 0x22, 0xAE, 0x09, 0xA1, 0xE5, + 0xA3, 0x95, 0xA0, 0x64, 0xE8, 0xEE, 0x12, 0x2A, 0x82, 0x38, 0xF4, 0x3D, 0x59, 0x80, 0xC4, 0x16, + 0x07, 0x3C, 0x2C, 0x1D, 0xD0, 0x98, 0x74, 0xC0, 0xC2, 0x59, 0x4C, 0x6B, 0xE0, 0xD0, 0xBE, 0x6B, + 0x13, 0xB0, 0x89, 0x45, 0x6B, 0x8F, 0x7F, 0x0A, 0x14, 0xEC, 0x69, 0xAF, 0x7B, 0xB3, 0xF7, 0x1C, + 0xC0, 0x3B, 0x81, 0xFB, 0x21, 0xF0, 0x2C, 0x67, 0xD1, 0xEA, 0x8D, 0xF7, 0x23, 0x5C, 0xF4, 0x36, + 0x22, 0x4C, 0xDD, 0xA7, 0xD7, 0x69, 0x17, 0xE9, 0x1B, 0x2D, 0x7E, 0xFD, 0xF9, 0xDE, 0xFE, 0x1E, + 0x27, 0x9D, 0x9E, 0x83, 0xB1, 0xB5, 0xD8, 0xC1, 0x33, 0x4A, 0xE1, 0xBE, 0x76, 0x76, 0xC6, 0xBB, + 0x61, 0xAD, 0xF0, 0x22, 0x34, 0xA2, 0x7F, 0x52, 0xB7, 0x42, 0x43, 0xFC, 0xF5, 0xCB, 0x3F, 0x84, + 0xC5, 0xDE, 0x1D, 0x02, 0xD5, 0x2F, 0x30, 0x2E, 0x7F, 0xF9, 0x07, 0xFC, 0x7F, 0xF7, 0x8C, 0x86, + 0xE2, 0x2F, 0xFF, 0xC0, 0x3F, 0x77, 0xCF, 0xA0, 0x27, 0x38, 0xA6, 0xFD, 0xDD, 0xFD, 0x4A, 0xA5, + 0xB0, 0x2D, 0xBB, 0x45, 0xA6, 0xEC, 0x42, 0xA1, 0x95, 0xA6, 0x69, 0x91, 0x43, 0xD4, 0xAF, 0x91, + 0xF7, 0xB6, 0x66, 0xAE, 0x09, 0xCA, 0x09, 0xC0, 0x8E, 0x85, 0xCA, 0x6D, 0x50, 0x89, 0x10, 0x54, + 0x57, 0xA8, 0xDC, 0x9A, 0xD3, 0x96, 0x1A, 0x77, 0x94, 0xC8, 0x3C, 0x44, 0xCB, 0xB5, 0xE1, 0xF9, + 0xE4, 0x1B, 0x27, 0x68, 0x05, 0x09, 0x97, 0xC8, 0x90, 0xF8, 0x64, 0x92, 0x60, 0x01, 0x7F, 0x00, + 0x07, 0xED, 0xF6, 0xB8, 0xD2, 0x42, 0x53, 0x7B, 0x12, 0x5A, 0x61, 0x44, 0x29, 0xBB, 0x99, 0x61, + 0x85, 0x3F, 0xCF, 0xEC, 0xCF, 0xAD, 0x1B, 0xF8, 0x2F, 0x1D, 0x28, 0xB6, 0x44, 0x84, 0x8D, 0x5E, + 0xE0, 0x7F, 0x20, 0x17, 0xFC, 0x93, 0xA9, 0x1F, 0xC0, 0xFA, 0xDE, 0xB6, 0x5B, 0xEC, 0xB3, 0x5F, + 0xA0, 0x9A, 0x0D, 0x04, 0x21, 0xFF, 0x16, 0xC3, 0x81, 0xEB, 0x06, 0x9F, 0x0E, 0xB4, 0xB5, 0x07, + 0x84, 0xD1, 0x2F, 0x7D, 0xC0, 0x31, 0x20, 0x22, 0x0E, 0xFB, 0x5B, 0x48, 0xC1, 0xDA, 0xB6, 0x5F, + 0x30, 0xAC, 0x40, 0x02, 0x3B, 0x00, 0x4D, 0x6D, 0xD0, 0x62, 0xE0, 0xFF, 0xBB, 0x67, 0xD0, 0x09, + 0x1C, 0xC2, 0xFF, 0x77, 0xCF, 0xB0, 0x2B, 0xD4, 0x25, 0xF6, 0x78, 0xF7, 0x0C, 0x7A, 0x84, 0x13, + 0xF8, 0x1F, 0xDA, 0x60, 0xBF, 0xD8, 0x0A, 0xFF, 0xC2, 0x1D, 0xDA, 0x3F, 0xDE, 0xA4, 0x07, 0xEC, + 0x02, 0x3F, 0xCD, 0x63, 0x90, 0xBD, 0xE9, 0xBE, 0x45, 0xDF, 0x3C, 0xFE, 0xE9, 0x06, 0xD8, 0xA1, + 0x07, 0xB7, 0xE0, 0xF8, 0x8E, 0x89, 0xE7, 0xF8, 0xE7, 0x56, 0x98, 0x27, 0x5E, 0xE0, 0x47, 0x70, + 0x8D, 0xBE, 0x9D, 0x15, 0x2F, 0xB1, 0x03, 0x6C, 0x45, 0xDF, 0xA5, 0x49, 0x5B, 0xB1, 0x23, 0xB8, + 0xC6, 0xDF, 0xC0, 0x78, 0xA0, 0xF1, 0x77, 0xFC, 0x15, 0x0A, 0x27, 0x7A, 0x07, 0xDF, 0x0B, 0xFF, + 0x06, 0x19, 0x64, 0xA4, 0xA1, 0x54, 0xC2, 0xB3, 0xDB, 0xBB, 0x67, 0x04, 0xEF, 0x51, 0x22, 0xE1, + 0xF8, 0x96, 0x1F, 0xC3, 0x75, 0xA0, 0x0F, 0xEF, 0x08, 0x82, 0xE9, 0x85, 0xDB, 0xE8, 0x02, 0xB4, + 0x08, 0xF0, 0x3E, 0x27, 0x1E, 0xCE, 0x6E, 0xC3, 0x33, 0x84, 0xA6, 0xB0, 0x9C, 0x0D, 0x38, 0xBD, + 0x8D, 0x4E, 0xE1, 0x2E, 0xF2, 0x82, 0x0A, 0xE0, 0x3C, 0xDD, 0x3D, 0xE3, 0x3C, 0xA1, 0x16, 0xD9, + 0x51, 0x5A, 0xD4, 0x18, 0xF4, 0x02, 0x1E, 0x24, 0x5F, 0xB1, 0x1C, 0x24, 0x36, 0x3C, 0x42, 0x00, + 0xB8, 0xB4, 0x09, 0x1E, 0xBE, 0xBA, 0xFD, 0xC6, 0x6C, 0xED, 0xF1, 0x4F, 0xB7, 0xEE, 0x61, 0x88, + 0x8E, 0xC3, 0x74, 0x5C, 0x67, 0x66, 0x5B, 0x33, 0x8C, 0x04, 0xAD, 0x7D, 0xED, 0x7C, 0xC2, 0xC3, + 0x34, 0x7A, 0x2C, 0x34, 0x8F, 0x7B, 0x61, 0x26, 0x6A, 0x8F, 0x7F, 0x7C, 0x74, 0x6F, 0xBF, 0x43, + 0x1D, 0x8D, 0x3B, 0x13, 0xA2, 0xE0, 0x31, 0x46, 0x0D, 0x07, 0x36, 0x96, 0xE0, 0xD8, 0x0A, 0x07, + 0xB9, 0x48, 0x68, 0xEB, 0x18, 0x16, 0x8A, 0x26, 0x3E, 0x92, 0x74, 0x53, 0x83, 0x48, 0x4E, 0xD8, + 0x12, 0x11, 0xEA, 0x69, 0x3A, 0x42, 0x81, 0xAA, 0xBC, 0xA0, 0xB5, 0x77, 0xE9, 0x79, 0xAE, 0xF7, + 0xAF, 0xBD, 0xE7, 0xD8, 0xE8, 0xF9, 0xDE, 0xBF, 0x4F, 0xB5, 0xBD, 0xE7, 0xF1, 0x50, 0x75, 0x97, + 0x8E, 0x29, 0x4C, 0x63, 0x0B, 0x45, 0x8D, 0x2D, 0x62, 0x1A, 0x5B, 0xDC, 0xAF, 0xC6, 0xE2, 0x9F, + 0x8C, 0xAD, 0xA3, 0xB5, 0xF8, 0x27, 0x5A, 0x73, 0x34, 0x57, 0x08, 0xCF, 0x95, 0xC6, 0xB5, 0xB5, + 0x90, 0x69, 0xAB, 0x8A, 0x9A, 0xD8, 0x18, 0x0E, 0xDE, 0x43, 0xBC, 0xB7, 0x3F, 0xBC, 0xFB, 0x16, + 0xC7, 0x02, 0xB9, 0xCA, 0x42, 0x8D, 0xA5, 0xB3, 0x2D, 0x09, 0x06, 0x4C, 0x0E, 0x12, 0x23, 0x53, + 0x22, 0x49, 0x78, 0xBE, 0xA7, 0xB5, 0x28, 0x4A, 0x4C, 0x11, 0x0A, 0x0C, 0x81, 0x8F, 0x2C, 0x6A, + 0xBE, 0x8B, 0xA3, 0x89, 0x70, 0xDE, 0x08, 0x2A, 0xC7, 0x16, 0x10, 0x40, 0x49, 0x89, 0x0C, 0xF3, + 0x96, 0xC3, 0xC4, 0x06, 0xBD, 0xC6, 0x5D, 0x84, 0xFA, 0xAB, 0xAF, 0x1A, 0xD4, 0x44, 0x4C, 0x8F, + 0x62, 0x9B, 0x5F, 0x28, 0x1D, 0x1E, 0xF9, 0x95, 0x04, 0xC4, 0x3F, 0x05, 0x22, 0x31, 0x70, 0x3E, + 0x62, 0x94, 0xC0, 0x72, 0x2B, 0xC1, 0x42, 0x47, 0x1A, 0x25, 0x1C, 0xF4, 0xF3, 0x11, 0x19, 0x18, + 0xD4, 0xA8, 0xA0, 0xDF, 0x6B, 0x90, 0x60, 0x10, 0x63, 0x9A, 0x12, 0x12, 0xF1, 0xAD, 0x81, 0x6C, + 0x3C, 0x6A, 0xC4, 0x88, 0x37, 0xFC, 0x4B, 0xF0, 0xF0, 0x31, 0x54, 0x09, 0x0D, 0x7F, 0x3B, 0x7D, + 0x26, 0x16, 0x35, 0x62, 0xF8, 0x0B, 0xE1, 0x65, 0x3C, 0xF1, 0x31, 0x5B, 0x8D, 0x27, 0xFE, 0x1E, + 0xF3, 0x6C, 0x3C, 0x8A, 0xB2, 0xE1, 0xEF, 0x0E, 0x97, 0x59, 0x1D, 0x4B, 0x11, 0x72, 0x1D, 0x83, + 0x35, 0x01, 0x60, 0x5E, 0x96, 0x7E, 0xD1, 0x3B, 0xED, 0x46, 0x18, 0x78, 0x46, 0x91, 0x87, 0x81, + 0x37, 0x49, 0x63, 0x10, 0xD1, 0xE1, 0x01, 0x72, 0xBB, 0x87, 0x88, 0x42, 0x90, 0xA3, 0xAB, 0x45, + 0x21, 0x48, 0xBB, 0x45, 0xF8, 0x09, 0x61, 0x32, 0xC2, 0x0F, 0x2D, 0x68, 0xB0, 0x2F, 0x18, 0xE7, + 0xC9, 0x3F, 0xFC, 0x20, 0xB0, 0x4C, 0x89, 0x88, 0x03, 0xD2, 0x79, 0x25, 0x4B, 0xE2, 0xDF, 0xBE, + 0x4D, 0x19, 0x12, 0x2D, 0x96, 0xDC, 0xFA, 0x6A, 0xA1, 0xEB, 0xD6, 0xCF, 0xC0, 0x40, 0xE7, 0x0E, + 0x6A, 0xB9, 0x19, 0xFF, 0x58, 0xAC, 0x04, 0x09, 0xCC, 0x39, 0x94, 0x50, 0xF0, 0x2F, 0x66, 0xCA, + 0x18, 0xA1, 0x1F, 0x54, 0x54, 0x62, 0x45, 0x7C, 0x3C, 0x51, 0x46, 0x07, 0x9D, 0xDE, 0xE4, 0x29, + 0x85, 0x7F, 0xA2, 0x2E, 0x4B, 0x23, 0x6B, 0xD5, 0x21, 0x57, 0x7C, 0x8E, 0x4D, 0x32, 0xEC, 0x56, + 0x9C, 0x15, 0x3E, 0xCC, 0x10, 0xBD, 0xF8, 0x28, 0xE6, 0xE2, 0xC4, 0x96, 0xA6, 0xA2, 0xC4, 0xEE, + 0x18, 0x01, 0x24, 0x47, 0xD3, 0x4D, 0x40, 0xFC, 0x0E, 0xD6, 0x0F, 0x42, 0xE1, 0x6C, 0xDD, 0xEA, + 0x38, 0x40, 0x00, 0x45, 0xB8, 0x1F, 0x8F, 0x55, 0x2C, 0x70, 0x6C, 0xE1, 0x62, 0x97, 0xB3, 0xD0, + 0xB1, 0xBB, 0x19, 0x18, 0x79, 0x7A, 0x9B, 0x84, 0xC0, 0x8B, 0x59, 0xD8, 0x68, 0x8D, 0x28, 0x86, + 0xAB, 0x3F, 0x1A, 0x6D, 0x27, 0xB9, 0xBC, 0x03, 0xB6, 0xAC, 0x84, 0x02, 0xE9, 0x60, 0x89, 0x3E, + 0x2A, 0x7B, 0xCD, 0x60, 0x16, 0xAA, 0xED, 0x89, 0x35, 0xA5, 0xBD, 0xD3, 0xAD, 0x7A, 0x06, 0x40, + 0x70, 0xAB, 0xD2, 0x5E, 0x30, 0x1A, 0x4F, 0xA3, 0x62, 0x89, 0xA6, 0x4D, 0x3D, 0x62, 0x7C, 0xFE, + 0x2A, 0x81, 0x8C, 0x56, 0xFF, 0x43, 0x4C, 0xEC, 0x1A, 0x16, 0x05, 0x53, 0x97, 0xD8, 0x13, 0x37, + 0x6D, 0xD7, 0x21, 0xF2, 0x5E, 0x13, 0xD5, 0x11, 0xDE, 0x11, 0x3F, 0x33, 0xC9, 0xDC, 0xD8, 0xD8, + 0x41, 0x04, 0xE6, 0x91, 0x60, 0xE3, 0x39, 0xBC, 0x5A, 0xB2, 0x3D, 0xB9, 0x92, 0x96, 0xE9, 0x1A, + 0xB4, 0xCD, 0xC3, 0x43, 0xED, 0x65, 0x10, 0x18, 0xA0, 0x00, 0x5C, 0x66, 0x5D, 0xA2, 0x7C, 0x34, + 0x83, 0x17, 0x7C, 0x5D, 0x0F, 0x8D, 0x12, 0xEB, 0xCF, 0x1E, 0x70, 0x4D, 0xBD, 0xD1, 0x07, 0x10, + 0xE1, 0xA4, 0x14, 0x55, 0xE7, 0x3F, 0x1B, 0xE2, 0xDD, 0x7E, 0xA0, 0x02, 0x73, 0xBD, 0x97, 0xE0, + 0x8B, 0x7B, 0x9D, 0x68, 0xA9, 0x64, 0x8F, 0xD5, 0x37, 0x3B, 0x80, 0xEA, 0x12, 0xFA, 0x00, 0x1D, + 0x47, 0x36, 0xCF, 0xB8, 0x09, 0xF5, 0xAE, 0x9D, 0x9F, 0x9F, 0x73, 0x65, 0xA4, 0x0B, 0xAA, 0xD0, + 0xC2, 0x75, 0x3E, 0x93, 0xDB, 0xCD, 0x1A, 0xC4, 0x1F, 0x95, 0x48, 0x53, 0x45, 0x5B, 0x2E, 0x1D, + 0xD2, 0x81, 0x96, 0x17, 0xBC, 0x4C, 0xD6, 0x1B, 0x48, 0x1A, 0x45, 0x2A, 0xA0, 0xD6, 0x89, 0x9E, + 0xF8, 0xD5, 0x56, 0xA3, 0xBB, 0x27, 0xF2, 0x33, 0x49, 0x79, 0x99, 0x13, 0xC8, 0x85, 0x27, 0x86, + 0xAE, 0x54, 0x0F, 0x4F, 0x92, 0xA8, 0xEE, 0xF6, 0x9F, 0x44, 0x91, 0x61, 0xB3, 0x36, 0x8D, 0x80, + 0x24, 0x83, 0x43, 0x68, 0x0B, 0xE2, 0xE6, 0xCA, 0x0D, 0x48, 0x2A, 0x62, 0x58, 0x8E, 0x15, 0x58, + 0x86, 0xFD, 0x31, 0xB2, 0xC6, 0x9D, 0xBA, 0xBF, 0xC4, 0xC7, 0x4B, 0xF8, 0xFF, 0x56, 0x85, 0x57, + 0xAD, 0x2A, 0xB9, 0x65, 0x21, 0x61, 0x3C, 0x88, 0xAC, 0x24, 0x2E, 0x87, 0x44, 0x58, 0xE0, 0xF7, + 0x45, 0x4F, 0x4F, 0x9F, 0xD2, 0xA3, 0x27, 0xA1, 0xD2, 0x44, 0xF4, 0x38, 0xD7, 0xA2, 0x1B, 0x29, + 0x05, 0x6F, 0xE3, 0x4E, 0xE1, 0x10, 0xC8, 0x63, 0x18, 0x98, 0x6F, 0x85, 0xEA, 0x5D, 0xC3, 0x54, + 0x17, 0x6D, 0xE1, 0xFF, 0xA3, 0xFE, 0x23, 0x8A, 0xFA, 0xBB, 0x0B, 0xF1, 0x39, 0xB6, 0x9D, 0xF2, + 0x00, 0x06, 0x27, 0x5F, 0x74, 0x79, 0xBE, 0x77, 0xA0, 0xC9, 0x57, 0x55, 0x52, 0x69, 0xC5, 0xD2, + 0x32, 0x19, 0xC9, 0x91, 0x5D, 0xA1, 0x84, 0x70, 0x61, 0x14, 0x97, 0x0E, 0x71, 0x1D, 0xB1, 0xB5, + 0xC7, 0x56, 0x6D, 0x69, 0x34, 0xBE, 0x8B, 0x12, 0x92, 0xA5, 0x7B, 0x9D, 0x07, 0xE9, 0x41, 0xCC, + 0xB9, 0x22, 0x29, 0xE0, 0x10, 0xDA, 0xB4, 0x7C, 0x63, 0x6A, 0x17, 0x77, 0xCD, 0xDB, 0x99, 0x7C, + 0x28, 0x80, 0x06, 0xE2, 0x0A, 0x80, 0x06, 0x1E, 0xF5, 0x99, 0x18, 0x5A, 0xE2, 0x14, 0x61, 0x15, + 0x64, 0xE5, 0x22, 0x9E, 0x1B, 0xE0, 0xC4, 0x49, 0xCC, 0x2C, 0x90, 0x96, 0x08, 0xB1, 0xF1, 0xCB, + 0x00, 0x91, 0x3C, 0x3D, 0xD7, 0x9C, 0x8D, 0x6D, 0x83, 0x05, 0x22, 0x0B, 0x60, 0x81, 0xF1, 0xBB, + 0xD2, 0x00, 0xFD, 0xE7, 0x8D, 0x66, 0x21, 0xE5, 0x09, 0x09, 0x3C, 0x7B, 0x96, 0xC4, 0x86, 0xCB, + 0xB7, 0x2C, 0x35, 0x0F, 0x7B, 0x63, 0xED, 0xD9, 0xDB, 0x74, 0xA3, 0x51, 0x96, 0x93, 0x04, 0x43, + 0xF5, 0xD3, 0x84, 0xE0, 0x63, 0x19, 0x0E, 0x10, 0x62, 0x99, 0x54, 0x40, 0xB8, 0x49, 0x43, 0xDF, + 0x5A, 0xE9, 0x7A, 0x41, 0xAD, 0xBE, 0x45, 0xF8, 0x1E, 0x9D, 0x7D, 0x90, 0x3F, 0x1A, 0x73, 0x74, + 0x41, 0x64, 0x3B, 0x61, 0x57, 0x71, 0x8C, 0x8B, 0x04, 0x46, 0x64, 0x2C, 0x45, 0x37, 0xFE, 0x68, + 0x07, 0xD0, 0x14, 0x77, 0xC8, 0xC4, 0x06, 0xEF, 0xED, 0xD1, 0x9F, 0x76, 0xBC, 0xDD, 0x30, 0x97, + 0x82, 0xEB, 0xE9, 0xA7, 0x05, 0x34, 0x97, 0x31, 0x46, 0xD1, 0x5D, 0x4F, 0x91, 0x25, 0x4A, 0x02, + 0x1C, 0xE6, 0xA1, 0x9A, 0x1B, 0x33, 0xF2, 0xC9, 0x23, 0x33, 0x77, 0xE1, 0x58, 0xBF, 0x13, 0x19, + 0x42, 0xE6, 0x50, 0x2D, 0xE2, 0x78, 0xAE, 0x98, 0x66, 0x23, 0x72, 0xEE, 0x2B, 0xC9, 0xEB, 0x99, + 0x3D, 0x69, 0x3A, 0xB8, 0xD5, 0x27, 0x0B, 0x37, 0x1F, 0xF8, 0x56, 0x70, 0xBB, 0xDD, 0xCF, 0x44, + 0x6B, 0xF7, 0x04, 0xF5, 0xD0, 0xF4, 0x0D, 0x6E, 0xD0, 0x09, 0x79, 0x08, 0x2F, 0x24, 0x93, 0x50, + 0xE1, 0x9E, 0xE1, 0x0A, 0x58, 0xDC, 0x5E, 0xD8, 0x50, 0x19, 0x8D, 0x93, 0x91, 0x41, 0xDE, 0xD3, + 0xC8, 0xD1, 0xC3, 0x61, 0x43, 0x1A, 0xDF, 0x6B, 0x0E, 0x1A, 0x39, 0x38, 0xD9, 0xC6, 0x97, 0x34, + 0xD2, 0xCD, 0x74, 0x65, 0x05, 0x12, 0x84, 0x7B, 0xBD, 0xBD, 0x32, 0xE3, 0x4F, 0xDC, 0x5B, 0x59, + 0xC4, 0xA3, 0xA9, 0x39, 0x20, 0x4A, 0xAC, 0xE8, 0xCD, 0xD8, 0x06, 0xCF, 0x17, 0x30, 0xFD, 0xC6, + 0x75, 0x3A, 0x54, 0x70, 0x6A, 0x81, 0x9C, 0xA1, 0x60, 0xFB, 0x3A, 0x28, 0x8A, 0xE4, 0xCE, 0x0E, + 0xB1, 0x9B, 0x22, 0x99, 0xC9, 0xC7, 0x37, 0x14, 0xFC, 0xEA, 0x11, 0x80, 0xF3, 0xB1, 0x9A, 0xA8, + 0x7D, 0xF9, 0x07, 0x45, 0x71, 0xA7, 0xCD, 0x21, 0x5A, 0xF8, 0x4B, 0x62, 0xD2, 0xCA, 0x57, 0xB0, + 0xF1, 0x4F, 0x35, 0x5C, 0x14, 0x4F, 0xEC, 0xE4, 0xB8, 0xFB, 0x35, 0xB4, 0x90, 0x70, 0xB0, 0x29, + 0x9C, 0x6C, 0xD0, 0x0D, 0x3F, 0xF9, 0xF3, 0x0C, 0x96, 0x9E, 0x4B, 0x0A, 0x4B, 0xF8, 0x63, 0x91, + 0xC4, 0xEE, 0x40, 0x4E, 0x03, 0xDD, 0x7C, 0x07, 0xD9, 0x4B, 0xCA, 0x4C, 0xF7, 0xF9, 0x34, 0x09, + 0x34, 0x60, 0x8A, 0x90, 0xC7, 0x74, 0x84, 0x93, 0x21, 0x26, 0xA6, 0x84, 0x84, 0x19, 0x33, 0x9C, + 0x97, 0xE2, 0xDD, 0x30, 0x3C, 0x0B, 0x08, 0x65, 0xF1, 0x9B, 0x0F, 0x93, 0x9B, 0xFD, 0x27, 0xA1, + 0x18, 0xB6, 0x71, 0x60, 0x07, 0x31, 0x04, 0x09, 0x11, 0x65, 0x89, 0x89, 0x1B, 0x4D, 0x72, 0x5E, + 0x96, 0x23, 0x33, 0xF6, 0x8B, 0x8D, 0x99, 0x74, 0xC0, 0xA4, 0x3D, 0xFF, 0x8B, 0x1A, 0xCD, 0xBF, + 0x0F, 0xD8, 0x20, 0x1B, 0x8B, 0x79, 0xFB, 0x65, 0x08, 0xDA, 0x9A, 0x24, 0x16, 0x12, 0x73, 0x6F, + 0xE9, 0xB2, 0xF8, 0x41, 0x80, 0xA3, 0xF8, 0x20, 0x29, 0xDD, 0x9A, 0x26, 0xC6, 0x73, 0xBA, 0x90, + 0x41, 0x89, 0x6C, 0x62, 0x73, 0x3C, 0x21, 0x1E, 0x69, 0x3E, 0x97, 0x29, 0x2E, 0x66, 0x5F, 0xCC, + 0x61, 0xAF, 0x2C, 0x72, 0x9D, 0x5B, 0x37, 0xA5, 0x7B, 0xB5, 0xA8, 0xBC, 0x22, 0x80, 0x8B, 0x70, + 0x6F, 0x5E, 0x21, 0x64, 0xB4, 0x8F, 0x2F, 0x86, 0x83, 0x6E, 0xD2, 0x53, 0x5B, 0x5C, 0xA5, 0x4D, + 0x13, 0xA0, 0x88, 0xB5, 0x18, 0x56, 0xEC, 0xDB, 0x4E, 0x93, 0x1F, 0x1F, 0x7C, 0xF2, 0xE0, 0xE9, + 0x28, 0xC7, 0x1A, 0xC7, 0xA0, 0xA9, 0xE7, 0x17, 0x03, 0xC7, 0x77, 0x04, 0xC6, 0x69, 0x37, 0xAE, + 0x14, 0x80, 0xA3, 0x6D, 0x8C, 0x31, 0x50, 0x31, 0x9E, 0xE5, 0x01, 0x42, 0x1B, 0xB6, 0x4D, 0x75, + 0x2F, 0xA6, 0x5F, 0x3F, 0x70, 0xD7, 0x1F, 0x28, 0x21, 0xA9, 0x40, 0x74, 0x4D, 0x17, 0x07, 0x3A, + 0x78, 0xBF, 0xC5, 0xD3, 0xA4, 0xB8, 0x6C, 0x93, 0xEB, 0xA9, 0x1F, 0x70, 0xE5, 0x40, 0x63, 0x78, + 0xF6, 0x92, 0x39, 0x2E, 0x5D, 0x54, 0x90, 0xF6, 0x80, 0x96, 0xD2, 0xF1, 0xBD, 0x19, 0x1B, 0x0E, + 0xC2, 0x4D, 0x7F, 0x18, 0xAD, 0xF0, 0xF0, 0x57, 0xD6, 0x27, 0x0E, 0xDF, 0x09, 0x9B, 0xDA, 0x2F, + 0xA4, 0xC5, 0x5D, 0xA7, 0x49, 0x89, 0x4A, 0x4A, 0xCC, 0xBF, 0x7D, 0x1C, 0x07, 0xD8, 0xD0, 0x87, + 0x11, 0x33, 0x66, 0x6F, 0x19, 0x61, 0x39, 0x12, 0x13, 0x8F, 0x83, 0x49, 0xE2, 0x63, 0x63, 0x19, + 0xDB, 0x31, 0xFA, 0xE2, 0xD3, 0x6C, 0x0A, 0xC3, 0xD7, 0x6B, 0x70, 0x3E, 0xF0, 0xF6, 0xEB, 0xD6, + 0xFE, 0x5D, 0x1E, 0x3B, 0x4C, 0x5C, 0x91, 0xED, 0xA8, 0x12, 0x41, 0x07, 0x0A, 0x39, 0xB6, 0x84, + 0x7C, 0xE4, 0xE8, 0xE2, 0x0E, 0x73, 0xE9, 0x88, 0x69, 0x4A, 0x96, 0x60, 0xCF, 0xB7, 0x45, 0xCB, + 0x32, 0xD5, 0x04, 0x82, 0x68, 0x08, 0xD8, 0x22, 0x36, 0x95, 0xA8, 0xC6, 0xEC, 0x42, 0x34, 0x10, + 0xB4, 0xC7, 0x7D, 0x30, 0x83, 0xF6, 0x64, 0x1E, 0x9F, 0x4A, 0x18, 0x99, 0x00, 0x42, 0x67, 0xCA, + 0x59, 0xC2, 0x99, 0x19, 0xCE, 0x95, 0x91, 0x58, 0xC2, 0x99, 0x01, 0x41, 0x01, 0xE1, 0x7E, 0xD3, + 0xD2, 0x59, 0x03, 0x9D, 0x3B, 0x00, 0x3B, 0xEB, 0xD0, 0x87, 0x61, 0x70, 0x46, 0x82, 0x36, 0x40, + 0x4F, 0x12, 0xB7, 0x97, 0x84, 0xBE, 0x80, 0x90, 0xDF, 0x67, 0x67, 0xAC, 0x41, 0xD8, 0xCB, 0xD4, + 0x35, 0x6F, 0x3B, 0xC6, 0x7A, 0x4D, 0x1C, 0xF3, 0x62, 0x69, 0xD9, 0x66, 0x8B, 0x81, 0xC6, 0xD6, + 0x31, 0x30, 0x2C, 0x12, 0xBA, 0xF5, 0x8D, 0x63, 0x05, 0x6F, 0xBE, 0x60, 0xD7, 0x5A, 0x7B, 0x7D, + 0x53, 0xEC, 0x5C, 0xE4, 0xCD, 0x3A, 0xA6, 0x67, 0x5C, 0x7F, 0x83, 0xFB, 0xA2, 0xA9, 0x39, 0x1C, + 0x74, 0x0F, 0xBA, 0xBC, 0x41, 0x00, 0xE9, 0x96, 0x10, 0x39, 0xE2, 0xC5, 0xFD, 0xA3, 0x3F, 0x7E, + 0xFF, 0x6D, 0x84, 0x37, 0x70, 0x5F, 0xB3, 0x4B, 0xAD, 0x3D, 0xBA, 0xB1, 0xFA, 0xF0, 0xB7, 0x35, + 0xEE, 0x57, 0x11, 0xC3, 0x4C, 0x4C, 0x8C, 0xB8, 0x67, 0x1A, 0x45, 0xC5, 0x9A, 0x7F, 0x15, 0x47, + 0x0A, 0x97, 0x1D, 0x18, 0x27, 0xD0, 0xDC, 0x5B, 0x32, 0x50, 0xB1, 0xA3, 0x1A, 0xC1, 0x91, 0x93, + 0xAF, 0x61, 0xA2, 0xFA, 0x0B, 0x31, 0x3C, 0xD0, 0xC7, 0x73, 0xAD, 0xA5, 0x77, 0xF5, 0xE7, 0x2D, + 0x7A, 0xFD, 0x1D, 0xB0, 0xB3, 0x6C, 0xED, 0x3F, 0xEF, 0xED, 0xEF, 0x77, 0x7C, 0xD0, 0x19, 0x69, + 0xB5, 0xFB, 0xA2, 0x09, 0xFC, 0xA1, 0x6D, 0x58, 0x27, 0xD9, 0xF7, 0xDF, 0xBA, 0x1B, 0xCF, 0xCF, + 0x6B, 0xF0, 0xCE, 0x72, 0x70, 0x24, 0xCE, 0x6B, 0xF2, 0x01, 0xA6, 0x2F, 0x8E, 0xB9, 0xD5, 0x44, + 0xA7, 0x1B, 0xC1, 0xC5, 0x9C, 0x91, 0xEE, 0x8F, 0x85, 0xA4, 0x3F, 0x96, 0xEE, 0xF3, 0x8C, 0x93, + 0x60, 0xC5, 0xBB, 0x25, 0x96, 0xA5, 0xEE, 0xE2, 0xC6, 0x11, 0xE5, 0x74, 0xBC, 0x6A, 0xB0, 0xA5, + 0xFF, 0x54, 0xC0, 0xE2, 0x59, 0xD2, 0x56, 0x2D, 0x5C, 0x25, 0x11, 0x95, 0x66, 0x58, 0xB9, 0x19, + 0x69, 0xB2, 0x60, 0x9C, 0x9E, 0x2D, 0x27, 0xB3, 0xCF, 0x8B, 0x0D, 0xF8, 0xF8, 0x4A, 0x44, 0x54, + 0x76, 0x0D, 0xA7, 0x9C, 0x61, 0xE8, 0x87, 0x29, 0x68, 0xDE, 0x78, 0x04, 0xB7, 0x63, 0x23, 0x18, + 0x9F, 0xAF, 0x16, 0x00, 0xD0, 0x49, 0x6A, 0x38, 0x8A, 0x69, 0x08, 0xB5, 0x4D, 0xB6, 0x24, 0x44, + 0x40, 0xBB, 0xFD, 0x30, 0x62, 0x21, 0x10, 0x9F, 0x75, 0x45, 0xBA, 0xDB, 0x9E, 0x5D, 0xA7, 0x03, + 0xD6, 0xD6, 0xAC, 0xFA, 0x2E, 0xA6, 0x2D, 0xF1, 0x70, 0x4E, 0xC4, 0x0F, 0xC9, 0x67, 0x9E, 0xC4, + 0x99, 0x17, 0x55, 0x82, 0x02, 0x88, 0x4F, 0x34, 0xC7, 0x8F, 0xB3, 0x4F, 0x14, 0xD9, 0x27, 0x9C, + 0x7D, 0x04, 0x88, 0x26, 0x9C, 0xC5, 0x25, 0x8B, 0xD0, 0x18, 0x7F, 0x7A, 0x15, 0x71, 0x76, 0x3D, + 0xCD, 0xA5, 0x93, 0x97, 0x12, 0x62, 0xEC, 0xE5, 0x03, 0x40, 0xFB, 0x15, 0xF8, 0x43, 0x9C, 0xAD, + 0xEB, 0xA9, 0x1A, 0x5B, 0xA2, 0x14, 0x81, 0x00, 0x11, 0x5B, 0xF2, 0x82, 0x85, 0x60, 0xE5, 0x35, + 0x09, 0xF8, 0x23, 0x7C, 0x86, 0x63, 0x6A, 0x73, 0xCF, 0x58, 0x11, 0xFC, 0x62, 0x7B, 0x48, 0xAC, + 0x49, 0xEF, 0x17, 0xE6, 0x7E, 0xAC, 0x59, 0x8C, 0xC9, 0xB0, 0xE4, 0x51, 0x08, 0x1A, 0xB6, 0x8C, + 0x41, 0x87, 0x74, 0xE4, 0x42, 0x8B, 0x46, 0x2C, 0x83, 0x0B, 0x4F, 0x95, 0x84, 0x15, 0xB6, 0x8E, + 0x1C, 0x21, 0x42, 0x20, 0x4A, 0x26, 0xA3, 0x74, 0xA9, 0x8C, 0xCD, 0x24, 0x18, 0xB3, 0xA9, 0xF9, + 0x42, 0xBC, 0x41, 0xC8, 0x52, 0xA2, 0x4D, 0xE8, 0x20, 0x0C, 0x3E, 0x8B, 0xCC, 0x42, 0x52, 0xD8, + 0x42, 0xA2, 0xFE, 0xDE, 0x26, 0x58, 0x9E, 0xE0, 0x2F, 0x65, 0xBC, 0xF8, 0xE6, 0x6B, 0xCD, 0xF5, + 0x34, 0xDB, 0xBD, 0x26, 0xB8, 0x28, 0x28, 0x36, 0x90, 0x69, 0x53, 0x02, 0x01, 0x8E, 0xB0, 0x22, + 0x13, 0xEE, 0x8F, 0x09, 0x96, 0x96, 0x0F, 0x73, 0x62, 0x7C, 0x75, 0x28, 0x79, 0xAA, 0x87, 0xA3, + 0x53, 0x21, 0x7B, 0xDB, 0x25, 0xF4, 0x84, 0x38, 0x19, 0x4C, 0x24, 0xCB, 0xA7, 0x9C, 0xC7, 0xAD, + 0xC0, 0x92, 0x57, 0xD6, 0x2A, 0x21, 0xC2, 0xF0, 0xF6, 0xA3, 0x95, 0xA2, 0x9C, 0x81, 0x42, 0x41, + 0x86, 0x60, 0x91, 0x2C, 0x23, 0x5E, 0xB7, 0xA4, 0x29, 0xAB, 0x1D, 0xE6, 0x68, 0x14, 0x4B, 0xE1, + 0xD2, 0x68, 0x9E, 0xAD, 0x15, 0x26, 0x71, 0x36, 0xCA, 0xB1, 0xDF, 0xD9, 0xA1, 0x78, 0x14, 0x8A, + 0x9D, 0x61, 0xF6, 0x36, 0x79, 0x72, 0x76, 0xB8, 0x0C, 0x56, 0xF6, 0xE4, 0xC9, 0xFF, 0x02, 0x49, + 0x60, 0xC8, 0xA8, 0x55, 0x0C, 0x01, 0x00 +}; + + +//File: index_ov5640.html.gz, Size: 9124 +#define index_ov5640_html_gz_len 9124 +const uint8_t index_ov5640_html_gz[] = { + 0x1F, 0x8B, 0x08, 0x08, 0xD9, 0x6C, 0x6A, 0x5E, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, + 0x6F, 0x76, 0x35, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x00, 0xED, 0x3D, 0x6B, 0x77, + 0xDB, 0xB6, 0x92, 0xDF, 0xF3, 0x2B, 0x18, 0xF5, 0x6E, 0x24, 0x9F, 0x58, 0xB6, 0xA8, 0x97, 0x1F, + 0xB1, 0x95, 0x4D, 0x1C, 0x27, 0xE9, 0xB9, 0x4D, 0x6F, 0x1A, 0xA7, 0x69, 0x7B, 0xBA, 0x3D, 0x29, + 0x25, 0x41, 0x12, 0x1B, 0x8A, 0xD4, 0x25, 0x29, 0xCB, 0x6E, 0x8E, 0x7F, 0xC7, 0xFE, 0xA0, 0xFD, + 0x63, 0x3B, 0x03, 0x80, 0x24, 0x48, 0x81, 0x24, 0x48, 0x4A, 0xB2, 0xDB, 0x5D, 0xE5, 0x9C, 0x98, + 0x0F, 0xCC, 0x60, 0xDE, 0x18, 0x0C, 0x40, 0xF2, 0xEC, 0xF1, 0xD8, 0x19, 0xF9, 0xB7, 0x0B, 0xA2, + 0xCD, 0xFC, 0xB9, 0x35, 0x78, 0x74, 0xC6, 0xFE, 0x68, 0xF0, 0x3B, 0x9B, 0x11, 0x63, 0xCC, 0x0E, + 0xE9, 0xE9, 0x9C, 0xF8, 0x86, 0x36, 0x9A, 0x19, 0xAE, 0x47, 0xFC, 0xF3, 0xDA, 0xD2, 0x9F, 0x34, + 0x8F, 0x6B, 0xC9, 0xDB, 0xB6, 0x31, 0x27, 0xE7, 0xB5, 0x6B, 0x93, 0xAC, 0x16, 0x8E, 0xEB, 0xD7, + 0xB4, 0x91, 0x63, 0xFB, 0xC4, 0x86, 0xE6, 0x2B, 0x73, 0xEC, 0xCF, 0xCE, 0xC7, 0xE4, 0xDA, 0x1C, + 0x91, 0x26, 0x3D, 0xD9, 0x37, 0x6D, 0xD3, 0x37, 0x0D, 0xAB, 0xE9, 0x8D, 0x0C, 0x8B, 0x9C, 0xEB, + 0x22, 0x2E, 0xDF, 0xF4, 0x2D, 0x32, 0xB8, 0xBC, 0x7A, 0xDF, 0x69, 0x6B, 0xFF, 0xFA, 0xD4, 0xEB, + 0x77, 0x5B, 0x67, 0x87, 0xEC, 0x5A, 0xD4, 0xC6, 0xF3, 0x6F, 0xC5, 0x73, 0xFC, 0x0D, 0x9D, 0xF1, + 0xAD, 0xF6, 0x35, 0x76, 0x09, 0x7F, 0x13, 0x20, 0xA2, 0x39, 0x31, 0xE6, 0xA6, 0x75, 0x7B, 0xAA, + 0xBD, 0x70, 0xA1, 0xCF, 0xFD, 0xB7, 0xC4, 0xBA, 0x26, 0xBE, 0x39, 0x32, 0xF6, 0x3D, 0xC3, 0xF6, + 0x9A, 0x1E, 0x71, 0xCD, 0xC9, 0xB3, 0x35, 0xC0, 0xA1, 0x31, 0xFA, 0x32, 0x75, 0x9D, 0xA5, 0x3D, + 0x3E, 0xD5, 0xBE, 0xD1, 0x8F, 0xF1, 0xDF, 0x7A, 0xA3, 0x91, 0x63, 0x39, 0x2E, 0xDC, 0xBF, 0x7C, + 0x8D, 0xFF, 0xD6, 0xEF, 0xD3, 0xDE, 0x3D, 0xF3, 0x4F, 0x72, 0xAA, 0xE9, 0xFD, 0xC5, 0x4D, 0xEC, + 0xFE, 0xDD, 0xA3, 0xD8, 0xE9, 0xAC, 0x9D, 0x46, 0x3D, 0x87, 0x3F, 0xCE, 0x86, 0xF7, 0xC8, 0xC8, + 0x37, 0x1D, 0xFB, 0x60, 0x6E, 0x98, 0xB6, 0x04, 0xD3, 0xD8, 0xF4, 0x16, 0x96, 0x01, 0x32, 0x98, + 0x58, 0x24, 0x13, 0xCF, 0x37, 0x73, 0x62, 0x2F, 0xF7, 0x73, 0xB0, 0x21, 0x92, 0xE6, 0xD8, 0x74, + 0x59, 0xAB, 0x53, 0x94, 0xC3, 0x72, 0x6E, 0xE7, 0xA2, 0xCD, 0xA2, 0xCB, 0x76, 0x6C, 0x22, 0x11, + 0x20, 0x76, 0xB4, 0x72, 0x8D, 0x05, 0x36, 0xC0, 0xBF, 0xEB, 0x4D, 0xE6, 0xA6, 0xCD, 0x8C, 0xEA, + 0x54, 0xEB, 0x74, 0x5B, 0x8B, 0x9B, 0x1C, 0x55, 0x76, 0xFA, 0xF8, 0x6F, 0xBD, 0xD1, 0xC2, 0x18, + 0x8F, 0x4D, 0x7B, 0x7A, 0xAA, 0x1D, 0x4B, 0x51, 0x38, 0xEE, 0x98, 0xB8, 0x4D, 0xD7, 0x18, 0x9B, + 0x4B, 0xEF, 0x54, 0xEB, 0xCA, 0xDA, 0xCC, 0x0D, 0x77, 0x0A, 0xB4, 0xF8, 0x0E, 0x10, 0xDB, 0xD4, + 0xA5, 0x94, 0xF0, 0x26, 0xAE, 0x39, 0x9D, 0xF9, 0xA0, 0xD2, 0xB5, 0x36, 0x49, 0xA1, 0x71, 0x17, + 0xCA, 0xD3, 0x67, 0xA6, 0xDC, 0xE4, 0x52, 0x33, 0x2C, 0x73, 0x6A, 0x37, 0x4D, 0x9F, 0xCC, 0x81, + 0x1D, 0xCF, 0x77, 0x89, 0x3F, 0x9A, 0x65, 0x91, 0x32, 0x31, 0xA7, 0x4B, 0x97, 0x48, 0x08, 0x09, + 0xE5, 0x96, 0xC1, 0x30, 0xDC, 0x5C, 0xBF, 0xD5, 0x5C, 0x91, 0xE1, 0x17, 0xD3, 0x6F, 0x72, 0x99, + 0x0C, 0xC9, 0xC4, 0x71, 0x89, 0xB4, 0x65, 0xD0, 0xC2, 0x72, 0x46, 0x5F, 0x9A, 0x9E, 0x6F, 0xB8, + 0xBE, 0x0A, 0x42, 0x63, 0xE2, 0x13, 0x37, 0x1F, 0x1F, 0x41, 0xAB, 0xC8, 0xC7, 0x96, 0xDE, 0x2D, + 0x6F, 0x60, 0xDA, 0x96, 0x69, 0x13, 0x75, 0xF2, 0xD2, 0xFA, 0x8D, 0xA3, 0x63, 0xAD, 0x14, 0x14, + 0x63, 0xCE, 0xA7, 0x59, 0x56, 0x42, 0x79, 0x5D, 0xEF, 0x8C, 0xFB, 0x8D, 0xDE, 0x6A, 0xFD, 0xC7, + 0xFA, 0xCD, 0x19, 0x61, 0x66, 0x6A, 0x2C, 0x7D, 0xA7, 0xBA, 0x47, 0xAC, 0xB9, 0x55, 0x82, 0x8F, + 0xFF, 0x9C, 0x93, 0xB1, 0x69, 0x68, 0x0D, 0xC1, 0x9D, 0x8F, 0x5B, 0x60, 0x53, 0x7B, 0x9A, 0x61, + 0x8F, 0xB5, 0x86, 0xE3, 0x9A, 0xE0, 0x08, 0x06, 0x0D, 0x37, 0x16, 0x5C, 0x81, 0x81, 0x63, 0x41, + 0xF6, 0x24, 0x2C, 0x67, 0xF8, 0x8C, 0x28, 0x11, 0xB9, 0xDB, 0xE0, 0x4F, 0x21, 0xE4, 0xE0, 0x2F, + 0xD7, 0x81, 0x24, 0x3C, 0x52, 0xF4, 0x59, 0xFA, 0x12, 0x29, 0x4C, 0xD3, 0x19, 0xFE, 0xE6, 0xC6, + 0x4D, 0x33, 0x53, 0x77, 0x41, 0xA3, 0x40, 0x87, 0x30, 0xCC, 0x8E, 0x1A, 0xD0, 0xF4, 0x7A, 0xA6, + 0x35, 0x35, 0x8C, 0x92, 0x7B, 0x72, 0x18, 0x8E, 0x54, 0xAE, 0x72, 0xFC, 0x89, 0x46, 0x51, 0x80, + 0x5D, 0x39, 0xAB, 0x51, 0xEC, 0x60, 0xFF, 0x64, 0x36, 0xC4, 0x38, 0x49, 0x8D, 0x22, 0xF8, 0x53, + 0x8F, 0x24, 0x11, 0xB2, 0xDC, 0x68, 0x22, 0x41, 0x9C, 0x1E, 0x51, 0xD6, 0xF0, 0xA6, 0x79, 0xB7, + 0x04, 0x6B, 0x36, 0x09, 0xAA, 0xD1, 0x45, 0x82, 0x38, 0x8B, 0x86, 0xDC, 0x28, 0x83, 0xBF, 0x3B, + 0x85, 0x7C, 0xE3, 0x9B, 0xE1, 0xD2, 0xF7, 0x1D, 0xDB, 0xAB, 0x34, 0x44, 0xA5, 0xF9, 0xD9, 0x1F, + 0x4B, 0xCF, 0x37, 0x27, 0xB7, 0x4D, 0xEE, 0xD2, 0xE0, 0x67, 0x0B, 0x03, 0x52, 0xC8, 0x21, 0xF1, + 0x57, 0x84, 0x64, 0xA7, 0x1B, 0xB6, 0x71, 0x0D, 0x71, 0x67, 0x3A, 0xB5, 0x64, 0xB6, 0x37, 0x5A, + 0xBA, 0x1E, 0xE6, 0x6D, 0x0B, 0xC7, 0x04, 0xC4, 0xEE, 0x7A, 0xC7, 0x71, 0x1F, 0x54, 0xEC, 0xA8, + 0x39, 0x1A, 0x4A, 0xFA, 0x72, 0x96, 0x3E, 0xCA, 0x58, 0xAA, 0x09, 0x07, 0xD8, 0x31, 0xFD, 0x5B, + 0xE9, 0x3D, 0xEE, 0x89, 0x92, 0x3B, 0x81, 0x0B, 0x66, 0x0E, 0x0B, 0x71, 0xBA, 0x4E, 0x47, 0x33, + 0x32, 0xFA, 0x42, 0xC6, 0x4F, 0x73, 0xD3, 0xB0, 0xBC, 0xF4, 0xF0, 0xC0, 0xB4, 0x17, 0x4B, 0xBF, + 0x89, 0xE9, 0xD4, 0x62, 0x2B, 0x3A, 0xA7, 0x06, 0x19, 0xB0, 0xD8, 0x6E, 0x67, 0x25, 0x15, 0xBD, + 0xC5, 0x4D, 0xB6, 0x10, 0x44, 0x62, 0x07, 0x96, 0x31, 0x24, 0x56, 0x16, 0xC9, 0xDC, 0x19, 0x52, + 0xC2, 0x2E, 0x8F, 0x55, 0xE9, 0xB9, 0x1B, 0xA5, 0x2C, 0x1A, 0xBC, 0xBA, 0x47, 0xFF, 0xA1, 0x2C, + 0x47, 0x7A, 0xBC, 0x1F, 0xBB, 0xE4, 0x11, 0x0B, 0x1C, 0x2C, 0x71, 0x6D, 0x61, 0xA4, 0x26, 0xE3, + 0xD0, 0x62, 0x05, 0x54, 0x65, 0x76, 0xE9, 0x1A, 0xF6, 0x94, 0x40, 0x74, 0xB8, 0xD9, 0x0F, 0x0E, + 0xB3, 0xA7, 0x0A, 0x4A, 0x02, 0xC1, 0xE0, 0xDD, 0xCB, 0x9E, 0x9A, 0xB0, 0x10, 0xB1, 0xAF, 0x1D, + 0xB0, 0x83, 0x12, 0x79, 0x8A, 0xA0, 0xF1, 0x4C, 0x42, 0x74, 0xA9, 0xBD, 0xB0, 0x54, 0x45, 0xEA, + 0x4B, 0x71, 0x6B, 0x93, 0xA6, 0xFE, 0xB9, 0xC1, 0x22, 0x98, 0x04, 0x4E, 0x26, 0x79, 0xD3, 0xC8, + 0xC9, 0xA4, 0xD3, 0xEA, 0x74, 0x73, 0x73, 0x29, 0x29, 0x97, 0x89, 0xA9, 0xA4, 0x24, 0x98, 0x84, + 0x81, 0x26, 0x5F, 0x17, 0xA7, 0x33, 0xE7, 0x9A, 0xB8, 0x12, 0x45, 0x24, 0xC8, 0xED, 0x9E, 0x74, + 0xC7, 0x0A, 0xD8, 0x0C, 0x18, 0x0A, 0xAE, 0x65, 0x81, 0x36, 0x8E, 0xAE, 0xAD, 0x8F, 0xDA, 0x99, + 0x16, 0xCA, 0xD0, 0x1D, 0x80, 0x35, 0x18, 0x43, 0x8B, 0x8C, 0x33, 0x22, 0xF7, 0x98, 0x4C, 0x8C, + 0xA5, 0xE5, 0xE7, 0xC8, 0xDB, 0x68, 0xE1, 0xBF, 0xAC, 0x1E, 0xA9, 0x7B, 0xFD, 0x8A, 0x35, 0x90, + 0x73, 0xEA, 0x12, 0xBF, 0x49, 0xFA, 0x0C, 0x86, 0x55, 0x63, 0xB1, 0x20, 0x06, 0xB4, 0x1A, 0x91, + 0xB4, 0xD9, 0xAA, 0x52, 0x3A, 0x2D, 0x8F, 0x69, 0x4A, 0x73, 0xD4, 0x5C, 0x53, 0x0C, 0x13, 0xA5, + 0x42, 0x3C, 0x9F, 0x4E, 0x9C, 0xD1, 0x52, 0x36, 0x82, 0xAB, 0x99, 0xD4, 0x3A, 0xBE, 0xD3, 0x40, + 0x64, 0x9E, 0x65, 0x52, 0xC3, 0x5E, 0xDA, 0x36, 0x6A, 0xB4, 0xE9, 0xBB, 0xC0, 0xA6, 0xA4, 0x23, + 0x35, 0xC1, 0x95, 0xF2, 0xCE, 0x98, 0x60, 0xD3, 0xEA, 0x34, 0x09, 0x07, 0x94, 0x04, 0x8A, 0x30, + 0x86, 0x68, 0x9E, 0x03, 0x4C, 0x05, 0xA8, 0xAA, 0xC9, 0xC5, 0x9F, 0x2D, 0xE7, 0xB2, 0x9C, 0x21, + 0xE8, 0x4C, 0x87, 0x01, 0x8E, 0x75, 0xE7, 0x4E, 0x87, 0x46, 0xA3, 0xB5, 0xDF, 0xDA, 0xEF, 0xC0, + 0x7F, 0x92, 0xDC, 0x3D, 0xDB, 0xB8, 0xB8, 0x78, 0x53, 0x2C, 0x2F, 0x11, 0x7C, 0xF2, 0x4B, 0x28, + 0x69, 0x61, 0x2C, 0x57, 0x17, 0xEA, 0x9E, 0x14, 0xAF, 0xA5, 0xE8, 0x07, 0x39, 0x23, 0x4C, 0x8A, + 0x49, 0x17, 0x37, 0x44, 0x89, 0xB5, 0x14, 0x55, 0xF1, 0xDC, 0xF9, 0xB3, 0xC9, 0x86, 0xD7, 0xFF, + 0xF3, 0xD6, 0x2E, 0x88, 0xE2, 0x6F, 0x6D, 0xE9, 0x85, 0xE5, 0xE2, 0xDD, 0xB7, 0x6D, 0xB4, 0xD2, + 0xB5, 0xDE, 0xE4, 0xF9, 0x0C, 0x50, 0x68, 0x43, 0xC6, 0xE9, 0xC2, 0xC4, 0x2B, 0x35, 0xE7, 0x11, + 0xDA, 0x94, 0x90, 0xC1, 0xC4, 0xB4, 0xAC, 0xA6, 0xE5, 0xAC, 0xF2, 0x33, 0x91, 0x6C, 0x4B, 0x5E, + 0xB3, 0xD3, 0x7C, 0x93, 0x2F, 0x4B, 0xED, 0x12, 0x22, 0xD7, 0x5F, 0x82, 0xDA, 0xBF, 0xB7, 0xC3, + 0x65, 0xBA, 0x46, 0xB9, 0x81, 0xA2, 0x84, 0x3D, 0x56, 0xEB, 0x48, 0xC9, 0x94, 0x58, 0x26, 0x98, + 0x39, 0xAB, 0xF3, 0x56, 0xA6, 0x3F, 0x9A, 0x95, 0x98, 0x54, 0x2D, 0x1C, 0xCF, 0x64, 0xCB, 0x37, + 0x2E, 0xB1, 0x0C, 0xCC, 0xE0, 0x4B, 0xCD, 0xC6, 0x73, 0x27, 0x26, 0x22, 0xB8, 0x0A, 0x27, 0x54, + 0x74, 0x0F, 0xA7, 0x92, 0x72, 0xC0, 0x72, 0x87, 0xF4, 0x58, 0x2D, 0x37, 0xEB, 0x9C, 0x74, 0x3F, + 0xEE, 0x19, 0xF2, 0x46, 0x05, 0x22, 0x7A, 0x10, 0xB4, 0xA7, 0x2E, 0xB9, 0x55, 0x60, 0x66, 0x9F, + 0xFF, 0x3D, 0x65, 0xB5, 0xD2, 0xF2, 0x45, 0x00, 0x3A, 0x00, 0x70, 0x2B, 0x3A, 0xE8, 0x7A, 0x0A, + 0x5D, 0xA7, 0x77, 0xA9, 0x62, 0x8F, 0x61, 0x25, 0xB0, 0x56, 0x53, 0x08, 0x37, 0x19, 0x43, 0xA8, + 0xDC, 0x54, 0x83, 0xD1, 0x57, 0x7A, 0xD3, 0x22, 0x13, 0x3F, 0x65, 0xA1, 0x83, 0xE6, 0xA9, 0x9D, + 0xEC, 0xE8, 0xD6, 0x14, 0xEA, 0x04, 0xB9, 0x91, 0x23, 0x2C, 0xD8, 0xA5, 0x5B, 0x9F, 0x14, 0x33, + 0x46, 0xCF, 0xC2, 0xC8, 0xD3, 0x55, 0x12, 0xA4, 0xCF, 0x54, 0xCD, 0xD0, 0x66, 0xCE, 0x87, 0x7C, + 0x50, 0x0F, 0xF9, 0xB9, 0xD1, 0xEE, 0x4B, 0xD7, 0x11, 0x32, 0x1A, 0x67, 0x91, 0xC6, 0x2A, 0x5E, + 0x4A, 0x43, 0x56, 0xEA, 0x04, 0x59, 0x8C, 0x45, 0x52, 0x45, 0x65, 0x7B, 0x65, 0x56, 0x84, 0x59, + 0xAF, 0xD1, 0x64, 0x1A, 0xBB, 0x39, 0x37, 0x20, 0xED, 0x45, 0x73, 0x35, 0x00, 0xA3, 0x4C, 0x7F, + 0x2A, 0xE6, 0x2E, 0xD4, 0x13, 0xF5, 0x7E, 0x2B, 0xA7, 0xCB, 0x91, 0xE5, 0x78, 0xD9, 0x7E, 0x65, + 0x0C, 0x41, 0x7E, 0x4B, 0x5F, 0xD2, 0x11, 0xAF, 0x6A, 0x4A, 0x2B, 0x4F, 0xD4, 0xB8, 0xA5, 0x77, + 0x94, 0x86, 0xEE, 0x4C, 0x9F, 0xCA, 0x76, 0xC7, 0x84, 0xCC, 0xF5, 0x96, 0x34, 0xD2, 0x66, 0xD6, + 0xDF, 0x7C, 0x72, 0x03, 0xF3, 0x4D, 0x5C, 0xAB, 0x3B, 0xD5, 0x46, 0x44, 0x1E, 0x46, 0x63, 0x83, + 0x9C, 0xAE, 0x52, 0x04, 0xCC, 0xD4, 0xC3, 0xCC, 0x1C, 0x8F, 0x49, 0x66, 0x95, 0x13, 0xE7, 0xBC, + 0xD9, 0xA1, 0xD2, 0x90, 0x96, 0xD3, 0x0A, 0x68, 0xB2, 0x9D, 0xAE, 0xCA, 0xCC, 0xE1, 0x2A, 0x25, + 0xF4, 0xC5, 0x24, 0x24, 0x6D, 0x22, 0x54, 0x61, 0xE5, 0x21, 0x12, 0x15, 0x31, 0x26, 0x23, 0xC7, + 0x65, 0x8B, 0xB8, 0x29, 0x13, 0xFF, 0x72, 0x33, 0x2B, 0x44, 0x2E, 0x2B, 0xDD, 0x6D, 0x25, 0x74, + 0x64, 0x6E, 0x74, 0xD0, 0xB7, 0x1D, 0x57, 0xF8, 0x70, 0x9C, 0x56, 0x49, 0x8F, 0x27, 0x6C, 0x99, + 0xA4, 0x4A, 0x43, 0x60, 0xA8, 0x46, 0x14, 0x19, 0xC8, 0x01, 0x5B, 0xAD, 0x2B, 0x34, 0x41, 0x15, + 0x5D, 0x5A, 0x39, 0xE0, 0xAB, 0x4D, 0x7C, 0x61, 0xB0, 0x99, 0xB6, 0xDE, 0xB2, 0xC1, 0xC5, 0x37, + 0x6A, 0x01, 0xC9, 0x7E, 0x53, 0x45, 0x73, 0x4F, 0xF9, 0x63, 0x06, 0x91, 0xE1, 0x40, 0x1C, 0x6C, + 0xB7, 0x8A, 0xB7, 0x2A, 0x1B, 0x42, 0xCE, 0x0E, 0x85, 0xFD, 0x71, 0x67, 0x87, 0xD1, 0x56, 0xBE, + 0x33, 0xDC, 0x24, 0x27, 0x6E, 0xA3, 0xE3, 0xFD, 0x8C, 0x2C, 0xC3, 0xF3, 0xCE, 0x6B, 0xB8, 0xD9, + 0xAB, 0x16, 0xDF, 0x55, 0x77, 0x36, 0x36, 0xAF, 0x35, 0x73, 0x7C, 0x5E, 0xB3, 0x9C, 0xA9, 0x93, + 0xB8, 0x47, 0xEF, 0x33, 0x2D, 0xC3, 0x68, 0x7F, 0x5E, 0x8B, 0xAD, 0x38, 0xD6, 0x28, 0x54, 0x74, + 0xA9, 0x36, 0x78, 0xF2, 0xCD, 0xC9, 0xD1, 0x51, 0xFF, 0xD9, 0x13, 0x7B, 0xE8, 0x2D, 0xF8, 0xFF, + 0x1F, 0xD9, 0x02, 0xAD, 0x47, 0x7C, 0x1F, 0x6C, 0xCE, 0x3B, 0x3B, 0xA4, 0xD8, 0x12, 0x14, 0x1C, + 0x02, 0x09, 0x29, 0x44, 0xF1, 0x6C, 0x50, 0x46, 0x57, 0xD0, 0xC4, 0x83, 0x04, 0x67, 0x68, 0xB8, + 0x92, 0x26, 0xB4, 0x19, 0x9B, 0x6B, 0xD0, 0x18, 0x52, 0xA3, 0xCA, 0x18, 0x3A, 0x37, 0x49, 0xD2, + 0x29, 0x37, 0x5C, 0x53, 0xBC, 0x15, 0x19, 0xA7, 0x21, 0x04, 0x30, 0x0A, 0x8E, 0xEB, 0xAC, 0xD0, + 0x46, 0xDA, 0x28, 0x26, 0x7B, 0x6C, 0x7C, 0x33, 0xB2, 0xBE, 0x04, 0x4A, 0xAF, 0x05, 0xDA, 0xB0, + 0x1D, 0x9F, 0x8D, 0x24, 0x29, 0x5D, 0xC5, 0x58, 0xE5, 0x30, 0xC2, 0x6A, 0x21, 0xE3, 0x02, 0x44, + 0xDB, 0xA4, 0xD8, 0xD9, 0xB5, 0x6C, 0x4C, 0x14, 0x9B, 0xA0, 0xD0, 0x00, 0xB8, 0x36, 0xF8, 0xF9, + 0xE2, 0xBB, 0x7F, 0x6A, 0xEF, 0xDE, 0xFE, 0x29, 0xD5, 0x50, 0x1E, 0x51, 0x18, 0x9C, 0x15, 0x7A, + 0xA6, 0x60, 0x4C, 0x1F, 0x81, 0x4C, 0x6A, 0x5C, 0x33, 0x14, 0x03, 0x26, 0x43, 0x16, 0xB1, 0xA7, + 0xFE, 0xEC, 0xBC, 0xA6, 0xD7, 0x70, 0x77, 0x4B, 0x70, 0xD6, 0xAE, 0x69, 0x18, 0xB8, 0xE9, 0xC1, + 0xB5, 0x61, 0x2D, 0xF1, 0xA8, 0xA5, 0xC2, 0xEB, 0xBA, 0x69, 0x49, 0x9B, 0xF1, 0x88, 0x12, 0xCA, + 0x58, 0x88, 0xC0, 0x71, 0x29, 0xD7, 0x06, 0x57, 0xC4, 0x3F, 0x3B, 0x64, 0xB7, 0x72, 0xB4, 0x96, + 0xDD, 0x37, 0xB8, 0x30, 0x33, 0x87, 0x2C, 0x13, 0xCA, 0x52, 0xFC, 0xC4, 0x35, 0xE6, 0x04, 0xA5, + 0xA2, 0xA4, 0x79, 0x51, 0xEB, 0x21, 0x64, 0x6D, 0xF0, 0x81, 0xD0, 0x2C, 0x03, 0xC8, 0x50, 0x52, + 0xFC, 0x19, 0x4F, 0xE1, 0x63, 0xFD, 0x87, 0xF6, 0xCC, 0x97, 0xEC, 0x9A, 0x06, 0x33, 0x73, 0x05, + 0xB9, 0x3F, 0x6E, 0x36, 0xB5, 0xDE, 0xBB, 0xF7, 0x5A, 0xB3, 0xA9, 0xD0, 0xD8, 0x59, 0x50, 0x77, + 0x0A, 0xF4, 0x0F, 0x16, 0xC2, 0xA8, 0x21, 0x54, 0x3F, 0xEC, 0xA8, 0x36, 0xF8, 0xE1, 0xEA, 0xE7, + 0x37, 0x2F, 0x1A, 0xED, 0x5E, 0xBF, 0x75, 0xA3, 0x9F, 0xB4, 0x5B, 0x7B, 0x67, 0x87, 0x0C, 0xAE, + 0x78, 0x07, 0x60, 0x60, 0xEF, 0xB5, 0xD7, 0x6F, 0x5F, 0x35, 0xF4, 0xD6, 0x71, 0x55, 0x64, 0xFA, + 0x49, 0x6D, 0xF0, 0xD3, 0x0F, 0x11, 0x65, 0xFD, 0x56, 0x15, 0x64, 0xC7, 0xC0, 0x26, 0xD0, 0xC5, + 0x50, 0x75, 0xBB, 0x85, 0x50, 0xA1, 0xC8, 0x3B, 0xE5, 0x44, 0xAE, 0x1F, 0x41, 0xBF, 0x94, 0x87, + 0x56, 0xF7, 0xF8, 0x46, 0xEF, 0xF5, 0xBB, 0x15, 0x78, 0xE8, 0xA3, 0x74, 0x81, 0x90, 0xC6, 0x71, + 0xBF, 0x5B, 0x15, 0x57, 0x0F, 0x71, 0x81, 0x40, 0x8E, 0xDA, 0x20, 0x8F, 0xF6, 0x71, 0x15, 0xD1, + 0x76, 0x6B, 0x03, 0xAA, 0xF2, 0x13, 0x44, 0xD5, 0x2A, 0x86, 0x0A, 0x45, 0xDB, 0x2E, 0x29, 0xDA, + 0x4E, 0x6D, 0xF0, 0x23, 0x8A, 0x16, 0x2D, 0x03, 0x78, 0xA8, 0x64, 0x1E, 0x6D, 0x88, 0x52, 0x14, + 0x57, 0x1B, 0xED, 0xB6, 0xD5, 0xAE, 0x22, 0x5A, 0xBD, 0x36, 0x40, 0x71, 0x20, 0xA6, 0xA3, 0x4A, + 0x0E, 0x00, 0xDE, 0x44, 0x69, 0x02, 0x72, 0x6E, 0x8E, 0xFA, 0xC7, 0xE5, 0x31, 0x81, 0x27, 0x5D, + 0x7D, 0x02, 0x4C, 0xC7, 0x20, 0xA8, 0x4A, 0x6E, 0x04, 0x5E, 0x84, 0x78, 0xFA, 0xDD, 0xD6, 0x4D, + 0xB7, 0x8A, 0xCD, 0x80, 0x57, 0xBC, 0x45, 0x44, 0x80, 0xE4, 0xA6, 0x53, 0x45, 0x46, 0xE0, 0x12, + 0x17, 0xDF, 0xBE, 0x6E, 0x74, 0x81, 0xB1, 0xF6, 0x49, 0xBF, 0x3C, 0x1E, 0x70, 0x87, 0x1F, 0x90, + 0x20, 0x20, 0xE6, 0xA6, 0x5D, 0x2C, 0x3A, 0xC4, 0x11, 0x81, 0x33, 0x00, 0x3C, 0xE2, 0x28, 0x8D, + 0x02, 0xEC, 0xFA, 0x2D, 0x25, 0x06, 0x11, 0xE9, 0x47, 0x15, 0xB8, 0x02, 0xAB, 0xFE, 0x01, 0xC5, + 0x03, 0x48, 0x30, 0xE8, 0x55, 0x30, 0x45, 0x40, 0x44, 0x49, 0xD2, 0xFB, 0xD4, 0xD5, 0xCA, 0x63, + 0x02, 0x9B, 0x3E, 0xE9, 0xDF, 0x9C, 0xF4, 0xD5, 0x10, 0xE0, 0x88, 0x8F, 0xA3, 0x54, 0x56, 0x4E, + 0x90, 0x9D, 0x32, 0x64, 0xA5, 0x03, 0xFF, 0x5E, 0x1A, 0x16, 0xCC, 0x6F, 0x0A, 0x27, 0x03, 0x1C, + 0x0E, 0x64, 0xC2, 0x0E, 0xD4, 0xF2, 0x00, 0x81, 0x92, 0x70, 0xA3, 0x59, 0x6D, 0xD0, 0x55, 0xC8, + 0xB7, 0x62, 0x09, 0x39, 0x85, 0x8D, 0xD1, 0x4F, 0x93, 0x40, 0xB4, 0x3C, 0x4C, 0xFF, 0xC0, 0x25, + 0x3A, 0x35, 0x21, 0x82, 0x94, 0x4A, 0x34, 0x24, 0xB4, 0x1A, 0x37, 0xB5, 0x41, 0xBF, 0x93, 0x9B, + 0xA0, 0x95, 0x57, 0xC6, 0x90, 0xD6, 0x68, 0x6C, 0xE2, 0x79, 0x85, 0xF5, 0x11, 0x81, 0xD6, 0x06, + 0x2F, 0xC3, 0xE3, 0x2A, 0x5A, 0x69, 0xE6, 0x71, 0x4A, 0x61, 0x53, 0xD4, 0x22, 0x90, 0xC3, 0x34, + 0xD3, 0xEC, 0x70, 0xD5, 0x44, 0x9A, 0xD9, 0xAC, 0x62, 0xB6, 0xA9, 0x17, 0x9C, 0x4E, 0xBA, 0x86, + 0xE7, 0x17, 0xD6, 0x4A, 0x00, 0x08, 0x11, 0x9A, 0x1F, 0xDD, 0x9B, 0x46, 0x42, 0x52, 0xFE, 0x06, + 0xFA, 0xF0, 0x0C, 0x7F, 0xC9, 0xAA, 0x85, 0x85, 0x35, 0x12, 0x81, 0x42, 0x3E, 0x10, 0x1E, 0x57, + 0xD2, 0x4A, 0x95, 0xF0, 0x25, 0x90, 0xC3, 0xF5, 0x12, 0x84, 0xB0, 0xEE, 0x96, 0xF4, 0x92, 0x47, + 0x6D, 0x25, 0xBD, 0xCC, 0x0C, 0x77, 0x51, 0x2A, 0x7C, 0x85, 0x90, 0xA0, 0x95, 0xE0, 0xF0, 0xDE, + 0x5C, 0x25, 0x22, 0xE6, 0x6F, 0xE0, 0x2B, 0x63, 0x62, 0x3B, 0xA6, 0x57, 0x7C, 0xB6, 0xCF, 0xE1, + 0x6A, 0x83, 0x57, 0xA4, 0xF9, 0x3D, 0x1E, 0x55, 0x51, 0xC7, 0x8B, 0xA5, 0xEF, 0x54, 0x50, 0x48, + 0x40, 0x0B, 0x53, 0x47, 0x8B, 0x6B, 0xE3, 0x78, 0x4B, 0xDA, 0x38, 0xDE, 0xA2, 0x36, 0x0C, 0xF2, + 0xD9, 0x22, 0xD7, 0xC4, 0x2A, 0xAC, 0x8E, 0x00, 0xB0, 0x36, 0xB8, 0xBC, 0x59, 0x38, 0x1E, 0x3E, + 0x3A, 0xF5, 0x1D, 0x9E, 0x57, 0x72, 0x92, 0x5E, 0x05, 0x9D, 0x84, 0x04, 0x71, 0x1F, 0xE9, 0x71, + 0xAD, 0xF4, 0xB6, 0xA4, 0x95, 0x3C, 0x5A, 0xAB, 0x68, 0x65, 0x6A, 0x98, 0xF6, 0x88, 0x98, 0x16, + 0x3E, 0xC6, 0x51, 0x54, 0x31, 0x02, 0x6C, 0x6D, 0xF0, 0x26, 0x3A, 0xA9, 0xA2, 0x98, 0x56, 0x05, + 0xBD, 0x88, 0xF4, 0xC4, 0xFD, 0xA5, 0x07, 0xB3, 0xF2, 0x2D, 0xE9, 0x46, 0xD7, 0xB7, 0x39, 0xAA, + 0x2C, 0xC8, 0xC8, 0x34, 0xAC, 0xCF, 0x64, 0x32, 0x81, 0x69, 0x50, 0xF1, 0xA1, 0x25, 0x06, 0x0E, + 0xE3, 0x0B, 0x3B, 0xD7, 0x2E, 0xE9, 0x79, 0xE1, 0xFA, 0x65, 0x02, 0x5D, 0xF9, 0x22, 0x66, 0x72, + 0x4E, 0x28, 0x2D, 0x4B, 0x7E, 0xEF, 0x84, 0x74, 0x96, 0x9F, 0xB6, 0x7E, 0x4F, 0xA6, 0x74, 0x1B, + 0x41, 0x95, 0x39, 0xF4, 0x1B, 0xD7, 0xB8, 0xA5, 0xEF, 0x64, 0xA8, 0x32, 0xA5, 0xFF, 0x40, 0xC6, + 0xDA, 0x47, 0xD3, 0x2E, 0xCF, 0x4C, 0x17, 0x09, 0x21, 0xC4, 0xAE, 0x86, 0xA5, 0x07, 0x53, 0x24, + 0x38, 0xA8, 0x86, 0xA4, 0x8F, 0x35, 0xFD, 0x85, 0x69, 0x3C, 0x84, 0x49, 0xBC, 0xB1, 0x1A, 0x16, + 0x1F, 0x50, 0x56, 0x43, 0x18, 0x97, 0x7F, 0x7A, 0xA9, 0x5D, 0xD2, 0x8D, 0xEF, 0x85, 0xC3, 0x15, + 0xDB, 0x93, 0xA7, 0x62, 0xE8, 0xD1, 0xD2, 0x0D, 0xF6, 0xB9, 0xB6, 0xA6, 0x26, 0x77, 0x20, 0xD5, + 0x75, 0x35, 0x09, 0x7B, 0x01, 0x81, 0x74, 0x0B, 0x53, 0x4D, 0xE0, 0x56, 0x8D, 0xC7, 0x2D, 0xA6, + 0x62, 0xA3, 0x55, 0xF1, 0x34, 0x6C, 0xB4, 0x02, 0x35, 0x8D, 0xAF, 0xF1, 0x99, 0x88, 0xB1, 0x06, + 0xFA, 0xDA, 0x89, 0xA2, 0xB0, 0xD7, 0xFB, 0x51, 0x14, 0xE5, 0xF7, 0xBE, 0x15, 0x05, 0xD6, 0xF2, + 0x19, 0xC7, 0xD1, 0x32, 0x4E, 0x45, 0x01, 0x6B, 0x83, 0x77, 0x86, 0xBD, 0x84, 0x41, 0x66, 0x57, + 0x0A, 0x0B, 0x3B, 0xBE, 0x37, 0xF7, 0xE2, 0x7C, 0xDF, 0xB7, 0xEA, 0x80, 0x90, 0xB9, 0x33, 0x2E, + 0x3E, 0xDD, 0xE1, 0x70, 0x2C, 0x24, 0xBE, 0x83, 0xA3, 0xC2, 0x89, 0x41, 0x80, 0x61, 0xCB, 0x19, + 0x01, 0x9B, 0x4A, 0x95, 0x4F, 0x06, 0xAE, 0x96, 0xB6, 0x7D, 0x5B, 0x25, 0x13, 0xB8, 0xB0, 0x9C, + 0xE5, 0xB8, 0x3C, 0x06, 0x48, 0x03, 0xFE, 0x35, 0x99, 0x98, 0xA3, 0xF2, 0x89, 0x04, 0x24, 0x01, + 0x6F, 0x9D, 0xB9, 0x22, 0xFC, 0x96, 0x07, 0x5E, 0x32, 0x2A, 0x31, 0x93, 0x1B, 0x81, 0x16, 0x2F, + 0x2F, 0x76, 0x3A, 0xF0, 0x42, 0x9F, 0xF7, 0x14, 0x19, 0x90, 0xDB, 0xFB, 0x0E, 0x0A, 0x40, 0xC4, + 0x67, 0x6A, 0x3C, 0x65, 0x94, 0xC5, 0x20, 0xC3, 0x88, 0x1E, 0x4C, 0xBF, 0xEF, 0x6B, 0x7E, 0x17, + 0x51, 0x14, 0x9F, 0xDD, 0xE1, 0xD2, 0x73, 0x38, 0xBD, 0xEB, 0xB4, 0x37, 0x3B, 0xC1, 0x43, 0xE4, + 0xDB, 0xD5, 0x4F, 0xBB, 0x8C, 0x6A, 0x20, 0x1A, 0x7D, 0x8F, 0xEB, 0x0C, 0x05, 0x02, 0x76, 0x75, + 0x47, 0x6A, 0xDF, 0x9F, 0x27, 0xB5, 0x1F, 0x80, 0x2B, 0x4D, 0x4B, 0x44, 0xBC, 0x29, 0x46, 0xBC, + 0x37, 0x17, 0xBB, 0xD1, 0xD0, 0xF4, 0xDE, 0x42, 0xDD, 0xF4, 0x5E, 0x43, 0x9D, 0xC6, 0x37, 0x05, + 0x06, 0x52, 0x28, 0x99, 0xC1, 0x72, 0x40, 0x56, 0xCB, 0xAA, 0x12, 0xE4, 0xF4, 0x9B, 0x2A, 0x51, + 0x2E, 0x20, 0x23, 0x1E, 0xE4, 0xFA, 0xD1, 0xAA, 0x48, 0x6F, 0xB3, 0xCB, 0xBA, 0xDD, 0x3C, 0x6A, + 0xAB, 0x38, 0x8D, 0x6B, 0xAC, 0x3E, 0x4F, 0xE7, 0x46, 0x61, 0x65, 0x70, 0x38, 0xD0, 0xC5, 0xBB, + 0x17, 0xBB, 0x4C, 0x17, 0x82, 0x7E, 0xEF, 0xC7, 0x8F, 0x42, 0xAE, 0xEF, 0x3B, 0xD6, 0x59, 0xC4, + 0x2E, 0x1E, 0xEC, 0x10, 0xA8, 0x36, 0xF8, 0x8E, 0xD8, 0x9E, 0x76, 0xE1, 0xB8, 0xFC, 0x45, 0x98, + 0x3B, 0xD1, 0x1A, 0xED, 0xF9, 0x7E, 0x54, 0xC6, 0x98, 0xBE, 0x6F, 0x7D, 0xCD, 0xE6, 0xA6, 0xEB, + 0x3A, 0x6E, 0x61, 0x95, 0x71, 0x38, 0x98, 0x56, 0x34, 0xDF, 0xD1, 0xA3, 0x9D, 0xA8, 0x2B, 0xE8, + 0xF5, 0x7E, 0x34, 0x16, 0xF2, 0x7C, 0xDF, 0x4A, 0xBB, 0x9E, 0x58, 0xE6, 0xA2, 0xB0, 0xCA, 0x28, + 0x54, 0x6D, 0xF0, 0xA9, 0xF9, 0x1A, 0xFE, 0xEE, 0x44, 0x5D, 0xAC, 0xC7, 0xFB, 0x51, 0x16, 0xE7, + 0xF6, 0xBE, 0x55, 0x35, 0x5C, 0x14, 0x0F, 0x87, 0x00, 0x53, 0x1B, 0xBC, 0x7C, 0xBF, 0x9B, 0xDC, + 0x0F, 0x3B, 0x53, 0xD4, 0x50, 0x25, 0x7D, 0x50, 0xA6, 0xEE, 0x5B, 0x1B, 0xAB, 0x12, 0xDA, 0x58, + 0x21, 0xE1, 0x3F, 0xED, 0x48, 0x1B, 0x2B, 0x75, 0x6D, 0x6C, 0xD8, 0x5F, 0x56, 0x0F, 0x41, 0x3F, + 0xF4, 0xE9, 0xD3, 0xA1, 0x51, 0x7C, 0x38, 0x0A, 0x00, 0x71, 0xD3, 0x18, 0x1C, 0x69, 0x2F, 0x8D, + 0xDD, 0x0C, 0x48, 0x61, 0xBF, 0xBB, 0x70, 0xA1, 0x88, 0xC9, 0xFB, 0xD6, 0xD3, 0xC4, 0x18, 0x91, + 0xCF, 0x63, 0xE2, 0x97, 0x59, 0x5B, 0x16, 0x60, 0x6B, 0x83, 0xD7, 0x70, 0xA2, 0xBD, 0xA2, 0x27, + 0xBB, 0x4A, 0xF9, 0xC4, 0xFE, 0x77, 0xA1, 0xB5, 0x18, 0xBF, 0x0F, 0x42, 0x71, 0x90, 0x60, 0x3B, + 0x53, 0xBB, 0xD4, 0xE3, 0x4C, 0x31, 0x70, 0xAE, 0xBE, 0x0F, 0xEC, 0x7C, 0xB7, 0x0A, 0x8C, 0x88, + 0xD8, 0x99, 0x0E, 0x05, 0xBE, 0x37, 0xA8, 0x46, 0xC5, 0xA7, 0x1A, 0xF9, 0x9B, 0x81, 0xF3, 0x74, + 0xC5, 0x9F, 0xAE, 0xA3, 0x9B, 0x5A, 0x88, 0xDF, 0xF4, 0x7C, 0xD3, 0xB2, 0x60, 0x2A, 0x4C, 0x7C, + 0xED, 0x0A, 0x0F, 0x15, 0x1F, 0xA7, 0x13, 0xB0, 0x04, 0x0F, 0xD1, 0xFA, 0x2E, 0x31, 0xE6, 0xB5, + 0xC1, 0x15, 0xBE, 0x33, 0x19, 0x70, 0xE1, 0x59, 0x71, 0x64, 0x54, 0x8C, 0xC4, 0x76, 0x1D, 0x20, + 0x2A, 0x54, 0x13, 0x7F, 0x3F, 0x65, 0x4D, 0x0B, 0x8E, 0x84, 0x6B, 0x83, 0x4B, 0xDA, 0x58, 0x43, + 0x3B, 0xCB, 0xEF, 0x4E, 0xF9, 0x39, 0x3F, 0xFA, 0x44, 0x2F, 0x3E, 0xA2, 0x1B, 0x7F, 0xA3, 0x3A, + 0xE8, 0x95, 0xBD, 0xD5, 0x60, 0x70, 0x46, 0xDF, 0x0E, 0xCB, 0x9B, 0xD1, 0x87, 0xD9, 0x57, 0xFC, + 0xE9, 0xE4, 0xA1, 0x63, 0x8D, 0x9F, 0x09, 0xAB, 0xCB, 0x57, 0xE1, 0xE3, 0xB6, 0x08, 0x02, 0x86, + 0x11, 0x60, 0xC8, 0x51, 0xFE, 0xCC, 0x0D, 0xD0, 0xB3, 0x27, 0xA2, 0xF1, 0x1D, 0x65, 0x19, 0xCA, + 0x4D, 0x79, 0x34, 0xD8, 0x25, 0xD3, 0x50, 0x90, 0xB2, 0x27, 0xC6, 0xA5, 0x0F, 0x0A, 0x7F, 0x20, + 0x53, 0xD3, 0x03, 0x1A, 0x35, 0x30, 0x8B, 0x43, 0xFA, 0x8C, 0x25, 0x33, 0x66, 0xB5, 0xE7, 0x77, + 0xC5, 0x2E, 0xF9, 0xCB, 0x19, 0xA4, 0x8F, 0x63, 0x17, 0xCA, 0x4F, 0x92, 0x0F, 0x4F, 0xC7, 0x31, + 0xE6, 0x19, 0xFD, 0xE3, 0x66, 0x73, 0xD6, 0xC5, 0xA7, 0x45, 0xB5, 0x80, 0xB5, 0xB3, 0xC3, 0x59, + 0x37, 0xEF, 0xD1, 0xB0, 0xDC, 0x47, 0x7D, 0x81, 0xD3, 0xD2, 0x4F, 0xFA, 0xA2, 0x94, 0x06, 0x40, + 0xCD, 0xBE, 0xF6, 0xCE, 0xF0, 0xBE, 0xEC, 0x6B, 0x9F, 0xB0, 0x00, 0xB7, 0xC3, 0x07, 0x7E, 0x91, + 0x76, 0x63, 0x3C, 0x76, 0x53, 0x1F, 0xFA, 0xED, 0xC6, 0x1E, 0xFA, 0xED, 0x07, 0x0F, 0xFD, 0xF6, + 0xA3, 0xDD, 0x6E, 0x37, 0x9D, 0x56, 0xEB, 0x58, 0x85, 0x75, 0xC5, 0x07, 0x7F, 0x37, 0xC2, 0xD3, + 0x1C, 0xA4, 0xA9, 0xC8, 0x53, 0x37, 0xE0, 0x49, 0xD8, 0x15, 0x7E, 0x33, 0x99, 0x3C, 0x34, 0x8E, + 0xF8, 0xBA, 0x54, 0x79, 0x96, 0x5A, 0xED, 0x5D, 0x3F, 0x9D, 0x4D, 0x8D, 0x7B, 0x53, 0x0F, 0x67, + 0xD3, 0x26, 0xC9, 0x68, 0xD8, 0xCB, 0x0C, 0x86, 0x14, 0x84, 0x39, 0xFD, 0x9B, 0x4D, 0x3A, 0xFD, + 0xB4, 0x82, 0xD3, 0x4F, 0xD7, 0x9C, 0x7E, 0x87, 0xDE, 0x1E, 0x10, 0xFE, 0x77, 0xF3, 0xF8, 0x80, + 0xAF, 0x02, 0x5E, 0x2F, 0xE5, 0xAB, 0xD5, 0xDA, 0xA8, 0xDF, 0xE7, 0x3A, 0x49, 0x68, 0x0C, 0x6F, + 0x36, 0xE9, 0x24, 0x29, 0xA6, 0x5B, 0xCA, 0x4E, 0x79, 0xD8, 0x19, 0xEC, 0x66, 0x5C, 0xA2, 0xD9, + 0x94, 0xA8, 0x50, 0xDE, 0x3B, 0x3E, 0x13, 0xDA, 0xE9, 0xF2, 0xD4, 0x69, 0x13, 0xEA, 0x51, 0x7F, + 0x11, 0x44, 0x6A, 0x93, 0xCD, 0x24, 0x66, 0x0B, 0x21, 0xC3, 0x55, 0x4E, 0xCC, 0xDE, 0x7F, 0xF7, + 0x5D, 0xB1, 0x5C, 0x4C, 0xEC, 0xE5, 0x81, 0xE4, 0x62, 0x99, 0xB5, 0xD0, 0xDB, 0x05, 0xDC, 0x40, + 0xAA, 0x4B, 0x99, 0x6E, 0x04, 0x5E, 0x1B, 0xBC, 0xA4, 0xC7, 0x9A, 0x20, 0xB1, 0x42, 0xC6, 0xAB, + 0x3C, 0xED, 0xA4, 0x80, 0x42, 0xB1, 0x34, 0x22, 0x21, 0xA9, 0x1B, 0x45, 0x5C, 0x19, 0x05, 0x52, + 0x81, 0x3D, 0x75, 0xA6, 0x2A, 0xFB, 0x04, 0x6D, 0x92, 0x97, 0x0A, 0x2F, 0x5C, 0x52, 0x5A, 0x6D, + 0x1C, 0xB6, 0x36, 0x78, 0xEF, 0x12, 0xED, 0x95, 0x79, 0xAD, 0xCE, 0x9B, 0xB0, 0x51, 0x30, 0x44, + 0xA2, 0x26, 0xE5, 0xE4, 0x0E, 0x3E, 0xE9, 0xAE, 0x40, 0x5C, 0x6C, 0x57, 0xDD, 0x4E, 0x27, 0xC1, + 0x0A, 0x69, 0x57, 0xBB, 0x1A, 0x86, 0x4E, 0x6D, 0xD0, 0xA9, 0x86, 0xA1, 0x5B, 0x1B, 0x74, 0xAB, + 0x61, 0xE8, 0x81, 0x1C, 0x0E, 0x7A, 0xD5, 0x70, 0xF4, 0x6B, 0x83, 0x7E, 0x35, 0x0C, 0x47, 0x20, + 0xCB, 0xAA, 0x54, 0x40, 0xE6, 0x72, 0x5C, 0x00, 0x43, 0xFE, 0x26, 0x47, 0xD6, 0xAA, 0xBA, 0xF3, + 0xCC, 0x97, 0x56, 0x69, 0xE7, 0xE1, 0xB0, 0xB5, 0xC1, 0xBB, 0xA5, 0xE5, 0x9B, 0x0B, 0xCB, 0x84, + 0x69, 0x7B, 0xA3, 0xAB, 0x35, 0xB5, 0x76, 0xAF, 0xBD, 0xB7, 0xC3, 0x0C, 0x33, 0xA0, 0x43, 0xED, + 0x1D, 0x52, 0x9D, 0x20, 0x09, 0xD3, 0x8F, 0xC5, 0x77, 0x0A, 0x3C, 0x88, 0x70, 0xE6, 0x3A, 0x8E, + 0x5F, 0x5A, 0x1D, 0x01, 0x30, 0xA4, 0xF9, 0x70, 0x54, 0x3A, 0x9A, 0x45, 0x68, 0xCA, 0x18, 0x7A, + 0xCA, 0x26, 0xE7, 0x8A, 0xE1, 0x4C, 0x2F, 0x16, 0xCE, 0x76, 0xE7, 0x3E, 0xDE, 0x6D, 0xF9, 0x94, + 0x81, 0xC3, 0xC2, 0x6C, 0xF5, 0x16, 0x66, 0x88, 0x73, 0x54, 0x98, 0xD6, 0x68, 0x81, 0xFB, 0xE8, + 0xBD, 0x5D, 0x7A, 0x4F, 0x40, 0x46, 0xC1, 0x37, 0xB0, 0x89, 0xDE, 0xF3, 0x30, 0x9C, 0x87, 0xEA, + 0x83, 0x58, 0xE3, 0x5E, 0x79, 0x8D, 0x04, 0xD0, 0x90, 0x0F, 0xE0, 0x7B, 0xF0, 0x2A, 0xF9, 0x91, + 0x80, 0xAC, 0x9C, 0x23, 0x55, 0x77, 0x1A, 0xA9, 0x2B, 0x56, 0xCC, 0x0B, 0xDA, 0x95, 0x47, 0xF5, + 0xCE, 0x43, 0x1C, 0x0B, 0x17, 0xF8, 0xEA, 0x44, 0xA2, 0xB6, 0xBD, 0x92, 0x22, 0x13, 0x93, 0x48, + 0x06, 0xCB, 0x8D, 0x86, 0x6D, 0x2B, 0xDF, 0x69, 0xE6, 0x1F, 0x10, 0xB0, 0xBE, 0xDA, 0x54, 0x7C, + 0x15, 0x5E, 0x60, 0x4E, 0x36, 0x11, 0x08, 0x79, 0x7D, 0x70, 0xB3, 0x00, 0x24, 0xAC, 0xF4, 0x34, + 0x80, 0x03, 0x73, 0x15, 0x86, 0x91, 0xB8, 0xA3, 0x17, 0x88, 0xC4, 0xE2, 0x8C, 0x20, 0xC4, 0x57, + 0x72, 0xB4, 0xBB, 0xF7, 0xF4, 0xBF, 0x2B, 0x0F, 0x1E, 0x15, 0x5D, 0xBF, 0x60, 0x1A, 0x2C, 0xC1, + 0x80, 0xEF, 0x0B, 0xD4, 0x8B, 0x24, 0xF4, 0x9B, 0x0B, 0x1F, 0xC2, 0x5A, 0x21, 0x35, 0x38, 0x3A, + 0x74, 0x13, 0x9F, 0xCD, 0xF3, 0x0B, 0x2C, 0xFF, 0xA5, 0x36, 0xD9, 0x4C, 0x75, 0x67, 0x65, 0xDA, + 0xC5, 0xAB, 0x3B, 0x3F, 0x99, 0xF6, 0xD8, 0x59, 0x15, 0x2B, 0xF0, 0x88, 0x1D, 0xFD, 0x05, 0x0A, + 0x3C, 0x34, 0x3D, 0xC0, 0x15, 0xE2, 0xA6, 0x4B, 0xD4, 0xDE, 0x67, 0x93, 0x14, 0x32, 0x83, 0xBE, + 0xC1, 0x05, 0x56, 0x40, 0xE1, 0x69, 0x74, 0xBD, 0x79, 0xDB, 0x99, 0xDA, 0xCF, 0xA7, 0x62, 0xAE, + 0xC6, 0x29, 0x50, 0xCB, 0xD5, 0xBA, 0x92, 0x72, 0xF3, 0xBD, 0x57, 0xD0, 0x7F, 0x59, 0xE7, 0xE7, + 0xF6, 0xDE, 0xF9, 0xD9, 0xC4, 0x00, 0x44, 0xEC, 0x71, 0x69, 0xCB, 0x42, 0xD8, 0xC8, 0xAE, 0x2E, + 0xED, 0xF1, 0x4E, 0xAD, 0x8A, 0xF5, 0x5E, 0x5A, 0x07, 0xED, 0x7E, 0xBB, 0xF3, 0xB0, 0xCC, 0x0A, + 0x19, 0xAA, 0x60, 0x54, 0xFA, 0x49, 0xEF, 0x01, 0x4D, 0x69, 0x9C, 0xC9, 0x84, 0xAD, 0x6B, 0x96, + 0x33, 0x2D, 0x0E, 0x7E, 0x43, 0x9F, 0xD2, 0xF5, 0xC8, 0x6E, 0xE3, 0x55, 0xD8, 0x79, 0xC1, 0xD2, + 0x8C, 0xA0, 0x8B, 0xFE, 0xC3, 0x32, 0x2D, 0xCE, 0x91, 0xAA, 0x75, 0x49, 0x38, 0xEA, 0x3E, 0x1C, + 0xD3, 0xF2, 0x1D, 0xDF, 0xB0, 0x4A, 0x5B, 0x16, 0x83, 0x06, 0xC3, 0xFA, 0x88, 0x07, 0xDA, 0x15, + 0xF0, 0xB9, 0x53, 0xE3, 0x0A, 0xFA, 0x2F, 0x1F, 0xB8, 0x8E, 0xBB, 0x1B, 0x52, 0x46, 0x05, 0x96, + 0x7E, 0x59, 0x67, 0xA9, 0x52, 0xE8, 0xEA, 0x6F, 0x68, 0x91, 0x7C, 0x23, 0xA1, 0x6B, 0xE9, 0xE3, + 0xD5, 0xD2, 0xA1, 0x8B, 0x81, 0x63, 0xE8, 0xA2, 0x47, 0xBB, 0x37, 0xB1, 0x90, 0x82, 0xF2, 0x36, + 0xD6, 0x3B, 0xD9, 0xE4, 0x16, 0x98, 0x4D, 0x44, 0x30, 0xC6, 0x53, 0x25, 0x23, 0xDB, 0x94, 0xDF, + 0x54, 0x36, 0xB2, 0x91, 0xA1, 0xFC, 0x8E, 0x37, 0x8A, 0x4C, 0xCC, 0xE6, 0x19, 0x2C, 0xCC, 0xE1, + 0xD8, 0xC1, 0x4E, 0x2B, 0x36, 0x41, 0xE7, 0x1B, 0x5F, 0xA8, 0x0D, 0xB9, 0x7A, 0x48, 0xF5, 0x99, + 0xA1, 0x69, 0xDB, 0x65, 0xD5, 0xC4, 0x61, 0x6B, 0x83, 0x97, 0xEC, 0x60, 0xB7, 0x4B, 0xEA, 0xBC, + 0xF3, 0xCD, 0xAF, 0xA7, 0x07, 0x5C, 0xED, 0x5A, 0x4D, 0x89, 0x22, 0x86, 0x1B, 0x7E, 0xF7, 0xA3, + 0xC6, 0xF7, 0xA8, 0x46, 0xDF, 0x01, 0x79, 0x38, 0x25, 0x8D, 0xA9, 0x31, 0xC7, 0x87, 0x97, 0x8B, + 0x16, 0x35, 0xDE, 0x20, 0x58, 0xB1, 0x9A, 0x46, 0xBC, 0xA7, 0x87, 0x5D, 0xD5, 0x18, 0xC4, 0xDF, + 0x5A, 0x09, 0x84, 0x37, 0x87, 0xA6, 0xE1, 0xE1, 0x83, 0xFE, 0x70, 0xAC, 0xBD, 0x84, 0x63, 0xED, + 0xBD, 0xB5, 0x0C, 0x5F, 0xBB, 0x2B, 0x73, 0x08, 0x71, 0x3F, 0x5B, 0x84, 0x21, 0xED, 0xA9, 0x05, + 0xBA, 0x8D, 0x8F, 0x3F, 0xE0, 0x05, 0xC7, 0xB8, 0x7B, 0xAD, 0xD7, 0x3D, 0x6E, 0xD5, 0x34, 0x96, + 0x15, 0xF3, 0xC7, 0xFA, 0xBD, 0x2F, 0x74, 0x5B, 0x9B, 0x1E, 0x12, 0x28, 0x73, 0x00, 0x91, 0xDE, + 0x90, 0x40, 0x6A, 0xBF, 0x55, 0x76, 0x9B, 0xAD, 0x4B, 0x44, 0x0F, 0xC4, 0xD1, 0x92, 0x1A, 0x42, + 0xEC, 0x3D, 0x9B, 0xAC, 0x7D, 0xFC, 0x05, 0x05, 0xED, 0x9E, 0xEC, 0xFD, 0xA7, 0x72, 0x41, 0xE8, + 0x52, 0x41, 0xE0, 0xEE, 0xBE, 0xCD, 0xF2, 0xD4, 0x0E, 0x78, 0xD2, 0xD5, 0x78, 0x6A, 0x57, 0xE0, + 0xA9, 0xBD, 0x23, 0x9E, 0x3A, 0x01, 0x4F, 0x6D, 0x35, 0x9E, 0x3A, 0x15, 0x78, 0xEA, 0xEC, 0x88, + 0xA7, 0x6E, 0xC0, 0x53, 0x47, 0x8D, 0xA7, 0x6E, 0x05, 0x9E, 0xBA, 0x3B, 0xE2, 0xA9, 0x17, 0xF0, + 0xD4, 0x55, 0xE3, 0xA9, 0x57, 0x81, 0xA7, 0xDE, 0x8E, 0x78, 0xEA, 0x07, 0x3C, 0xF5, 0xD4, 0x78, + 0xEA, 0x57, 0xE0, 0xA9, 0xBF, 0x23, 0x9E, 0x8E, 0x02, 0x9E, 0xFA, 0x6A, 0x3C, 0x1D, 0x55, 0xE0, + 0xE9, 0x68, 0x47, 0x3C, 0x1D, 0x07, 0x3C, 0x1D, 0xA9, 0xF1, 0x74, 0x5C, 0x81, 0xA7, 0xE3, 0x1D, + 0xF1, 0x74, 0x12, 0xF0, 0x74, 0xAC, 0xC6, 0xD3, 0x49, 0x05, 0x9E, 0x4E, 0x76, 0xC4, 0x13, 0xEE, + 0xA6, 0x62, 0x4C, 0x9D, 0x28, 0x0E, 0xBA, 0xAD, 0x0A, 0x5C, 0x19, 0xBB, 0xE2, 0x2A, 0x4C, 0x25, + 0x74, 0xD5, 0x5C, 0xA2, 0x4A, 0x32, 0x31, 0xDC, 0x15, 0x5B, 0x51, 0x36, 0xA1, 0x98, 0x4E, 0xE8, + 0x55, 0xF2, 0x89, 0xD1, 0xAE, 0xD8, 0x0A, 0x13, 0x0A, 0x5D, 0x31, 0xA3, 0xD0, 0xAB, 0xA4, 0x14, + 0xE3, 0x5D, 0xB1, 0x15, 0xE6, 0x14, 0xBA, 0x62, 0x52, 0xA1, 0x57, 0xC9, 0x2A, 0xC8, 0xAE, 0xD8, + 0x0A, 0xD3, 0x0A, 0x5D, 0x31, 0xAF, 0xD0, 0xAB, 0x24, 0x16, 0x93, 0x5D, 0xB1, 0x15, 0x66, 0x16, + 0xBA, 0x62, 0x6A, 0xA1, 0x57, 0xC8, 0x2D, 0x4E, 0xE4, 0x13, 0xB1, 0x8D, 0xB2, 0x45, 0x7C, 0x3E, + 0x45, 0x8E, 0x26, 0x6D, 0x4A, 0x0F, 0x1C, 0x71, 0x20, 0x7C, 0x22, 0x8E, 0x09, 0xE4, 0xC2, 0xB1, + 0x27, 0xE6, 0x34, 0x2C, 0x32, 0x3C, 0x98, 0x67, 0x63, 0x3C, 0xE1, 0x85, 0xBF, 0xCA, 0x85, 0x86, + 0xAB, 0x57, 0x97, 0xC5, 0xCA, 0x0C, 0x62, 0x2F, 0x7F, 0xA1, 0x22, 0x03, 0x90, 0xDD, 0x16, 0xBF, + 0x3E, 0xA0, 0x54, 0x57, 0xA0, 0x40, 0x45, 0x2A, 0x0A, 0x3D, 0xB1, 0xA2, 0xD0, 0x57, 0xAE, 0x28, + 0x30, 0xE2, 0xB6, 0x53, 0x4B, 0x00, 0xDC, 0x1D, 0xF6, 0xC9, 0x04, 0x75, 0xA6, 0x3B, 0xE5, 0x99, + 0xEE, 0x15, 0x61, 0xBA, 0x53, 0x86, 0xE9, 0x12, 0xCF, 0xB4, 0x2A, 0xCA, 0x09, 0xE8, 0x7D, 0x6D, + 0xDE, 0x90, 0xB1, 0xF6, 0x8B, 0xBA, 0xA8, 0xF4, 0xF2, 0xA2, 0x3A, 0x2A, 0x22, 0x2A, 0x7D, 0x8B, + 0xF6, 0xD1, 0x0B, 0xF8, 0xFE, 0x51, 0x9D, 0xEF, 0x5E, 0x79, 0xBE, 0x3B, 0x45, 0xF8, 0xEE, 0x6D, + 0x91, 0xEF, 0x6E, 0xC0, 0xF7, 0x27, 0x75, 0xBE, 0xBB, 0xE5, 0xF9, 0xEE, 0x16, 0xE1, 0xBB, 0xBB, + 0x45, 0xBE, 0xDB, 0x10, 0x6C, 0x7E, 0xFC, 0xA4, 0x7D, 0x9C, 0xB9, 0xC4, 0x9B, 0xE5, 0x57, 0xE2, + 0x18, 0x44, 0xD9, 0xB1, 0xBD, 0xB7, 0x83, 0xB9, 0x1B, 0x52, 0xD8, 0x11, 0x79, 0xCA, 0xCD, 0x9B, + 0x19, 0x84, 0xCA, 0x37, 0x89, 0xE4, 0x3C, 0xC9, 0x67, 0x6E, 0xBA, 0x2A, 0x53, 0xDB, 0x8B, 0x61, + 0xC7, 0xB5, 0xC1, 0xDB, 0x65, 0x81, 0xF1, 0xED, 0xB8, 0xBC, 0x3D, 0xAB, 0x57, 0xCC, 0x19, 0x5D, + 0x5B, 0xB3, 0xE7, 0x13, 0xCA, 0x33, 0xE4, 0x65, 0x9E, 0x82, 0xDA, 0xCB, 0x57, 0x21, 0x7A, 0x3B, + 0xA8, 0x92, 0x63, 0xA4, 0x3F, 0x62, 0xEC, 0xFC, 0x88, 0x0C, 0x69, 0x90, 0xB1, 0x14, 0x18, 0x8C, + 0x8E, 0x0A, 0x6A, 0xF3, 0xB8, 0x64, 0x74, 0x42, 0x1A, 0xB7, 0xA6, 0x4E, 0x9C, 0x7A, 0xA0, 0x00, + 0x3E, 0x95, 0x10, 0x40, 0xBF, 0xBC, 0x00, 0x0A, 0x65, 0x2E, 0x48, 0xE3, 0xF6, 0x04, 0xD0, 0x62, + 0x02, 0xB8, 0x8A, 0x5E, 0x7A, 0x9D, 0x61, 0xD0, 0x15, 0x2A, 0x50, 0xBD, 0x1D, 0xAC, 0x91, 0x60, + 0xA4, 0xD5, 0x03, 0x8B, 0x06, 0x8E, 0x8A, 0x29, 0xB4, 0x5D, 0x34, 0xBF, 0x92, 0x17, 0x3F, 0x15, + 0xF2, 0xEF, 0x6D, 0x26, 0x58, 0xED, 0x56, 0x60, 0xD1, 0xC5, 0x05, 0xD0, 0x2A, 0x2F, 0x00, 0xBD, + 0x90, 0x00, 0x5A, 0x0F, 0x2B, 0x19, 0xEF, 0xAF, 0x7F, 0xA7, 0x38, 0x5F, 0x5A, 0x45, 0xDD, 0x5F, + 0x18, 0xCD, 0xDA, 0x45, 0x84, 0xB5, 0x55, 0xEF, 0xEF, 0x44, 0x9C, 0x6B, 0xBF, 0x68, 0xF1, 0xAD, + 0xAF, 0x59, 0x71, 0xA0, 0x7C, 0x11, 0xB0, 0xB7, 0x83, 0xF5, 0x2A, 0xA4, 0xF0, 0x44, 0xC2, 0x59, + 0xC1, 0x00, 0x7F, 0x52, 0xDE, 0x1D, 0x0A, 0x69, 0x18, 0x69, 0xDD, 0x9E, 0x8A, 0x7B, 0x31, 0x41, + 0xB0, 0x6F, 0xA4, 0xAB, 0xA8, 0xB8, 0x7C, 0xE5, 0xB0, 0xB7, 0x83, 0xA5, 0x2E, 0xA4, 0xF0, 0x58, + 0xC2, 0x59, 0x41, 0x15, 0x17, 0x4D, 0x49, 0x8F, 0x4B, 0x4E, 0x2D, 0xF5, 0x6D, 0xE6, 0xA4, 0x58, + 0xED, 0x16, 0x04, 0x21, 0x7E, 0xC0, 0x22, 0x4B, 0xC1, 0xE5, 0x2B, 0xDE, 0xBD, 0x8A, 0xEB, 0xB3, + 0xDB, 0x8B, 0xE4, 0x47, 0xB2, 0xAF, 0x9B, 0xE7, 0xDB, 0x41, 0xD1, 0x5C, 0xB6, 0x55, 0x72, 0xE0, + 0xDB, 0x6A, 0x2A, 0x0B, 0xBD, 0x43, 0xD6, 0xB3, 0xCE, 0x7D, 0x86, 0x09, 0x94, 0x5F, 0x79, 0xEB, + 0xED, 0x60, 0x7B, 0x08, 0x52, 0xD8, 0xAE, 0x0D, 0x3E, 0x15, 0x64, 0xAA, 0x4A, 0xFD, 0xA0, 0xF4, + 0xFE, 0x90, 0xDD, 0x95, 0xDE, 0x47, 0xF3, 0x9B, 0xE2, 0xA5, 0xF7, 0x8B, 0x77, 0x3F, 0x17, 0x2B, + 0xBD, 0x8B, 0xBD, 0xEC, 0xAE, 0xF4, 0x5E, 0xCE, 0x66, 0x0A, 0x6D, 0x94, 0x05, 0xC6, 0xF0, 0x55, + 0x48, 0x23, 0xD3, 0xA3, 0x5D, 0x82, 0x60, 0xB4, 0xF7, 0xC1, 0x69, 0x28, 0x22, 0xE1, 0x19, 0xE5, + 0x78, 0xFB, 0x2C, 0xEB, 0xE9, 0x64, 0x84, 0x85, 0x52, 0xCF, 0xF0, 0xE2, 0x0B, 0x75, 0xFA, 0xFC, + 0x1B, 0x5F, 0x15, 0x9E, 0x05, 0x4E, 0x7B, 0xD7, 0xC8, 0xC1, 0x51, 0x41, 0xDC, 0x5B, 0x7F, 0xC5, + 0xC0, 0x20, 0xA1, 0x28, 0x9D, 0xEA, 0x47, 0xC7, 0x73, 0xE5, 0x3A, 0x39, 0x05, 0x2B, 0x12, 0xCD, + 0x3B, 0x62, 0xA9, 0x45, 0x3D, 0x9A, 0x33, 0xF2, 0xB6, 0x13, 0xCD, 0x11, 0x77, 0x8C, 0xF7, 0x02, + 0x59, 0x0D, 0x83, 0x2D, 0x26, 0x00, 0xF9, 0x26, 0x0A, 0x05, 0x01, 0xA4, 0x49, 0x60, 0x23, 0x22, + 0x68, 0x53, 0x09, 0xB4, 0x13, 0xDA, 0x4F, 0x09, 0xFC, 0xB4, 0x7D, 0xD9, 0xB8, 0xDF, 0xD9, 0x41, + 0x6D, 0x02, 0xC5, 0x15, 0xE3, 0xA8, 0xA0, 0x4E, 0x8B, 0x2D, 0x0E, 0xC6, 0x74, 0x5A, 0xCC, 0xA8, + 0xB7, 0xB6, 0x3A, 0x08, 0xC8, 0x3B, 0x54, 0x00, 0x1D, 0x65, 0x95, 0x96, 0x9F, 0x66, 0x76, 0x76, + 0x90, 0x9F, 0xA0, 0xB4, 0x62, 0x1C, 0x15, 0x54, 0x69, 0xB1, 0xA5, 0xCF, 0x98, 0x4A, 0xD5, 0xE7, + 0x97, 0x9C, 0xC8, 0xAD, 0xA9, 0xB4, 0x4B, 0x05, 0xD0, 0x55, 0x56, 0x69, 0xF9, 0x59, 0x47, 0x67, + 0x07, 0xBB, 0x77, 0x51, 0x5A, 0x31, 0x8E, 0x0A, 0xAA, 0xB4, 0xD8, 0x92, 0x5D, 0x4C, 0xA5, 0xEA, + 0xF3, 0x49, 0x4E, 0xE4, 0xD6, 0x54, 0xDA, 0xA3, 0x02, 0xE8, 0x29, 0xAB, 0xB4, 0x7C, 0xA5, 0xA0, + 0xB3, 0x83, 0x62, 0x10, 0x4A, 0x2B, 0xC6, 0x51, 0x41, 0x95, 0x16, 0x5B, 0x7D, 0x8E, 0xA9, 0x54, + 0x7D, 0x9D, 0x83, 0x13, 0xB9, 0x35, 0x95, 0xF6, 0xA9, 0x00, 0xFA, 0xCA, 0x2A, 0x2D, 0xBF, 0xBF, + 0xAA, 0xB3, 0x83, 0xBD, 0xDB, 0x28, 0xAD, 0x18, 0x47, 0x05, 0x55, 0x5A, 0xAC, 0x74, 0x1B, 0x53, + 0xA9, 0xFA, 0xCA, 0x0D, 0x27, 0x72, 0x6B, 0x2A, 0x3D, 0xA2, 0x02, 0x38, 0x52, 0x56, 0x69, 0xF9, + 0xAD, 0xEB, 0x9D, 0x1D, 0xD4, 0xF3, 0x50, 0x5A, 0x31, 0x8E, 0x0A, 0xAA, 0xB4, 0x58, 0x05, 0x27, + 0xA6, 0x52, 0xF5, 0xBD, 0x53, 0x9C, 0xC8, 0xAD, 0xA9, 0xF4, 0x98, 0x0A, 0xE0, 0x58, 0x59, 0xA5, + 0xE5, 0x77, 0xEE, 0x77, 0x76, 0xB0, 0x73, 0x1F, 0xA5, 0x15, 0xE3, 0xA8, 0xA0, 0x4A, 0x8B, 0xD5, + 0x66, 0x63, 0x2A, 0x55, 0xDF, 0xEE, 0xC4, 0x89, 0xDC, 0x9A, 0x4A, 0x4F, 0xA8, 0x00, 0x4E, 0x94, + 0x55, 0x5A, 0x7E, 0xCB, 0x40, 0x67, 0x07, 0x9B, 0x5F, 0x50, 0x5A, 0x2D, 0x91, 0xA3, 0x82, 0x2A, + 0x2D, 0xB6, 0xC0, 0xD8, 0x49, 0xD9, 0xFA, 0xA2, 0xA0, 0xD2, 0xB4, 0x05, 0xC6, 0x07, 0x50, 0xBF, + 0x33, 0x56, 0xC3, 0x12, 0x1F, 0xFC, 0x79, 0xF1, 0xD3, 0xCB, 0xF4, 0xC2, 0x7E, 0x6A, 0x15, 0x2F, + 0xD6, 0xD7, 0x43, 0x2F, 0xE3, 0x89, 0xF2, 0x42, 0xC2, 0x41, 0xCB, 0xEC, 0x25, 0x91, 0xDA, 0x1A, + 0xF3, 0xD9, 0x96, 0xC6, 0x80, 0x0B, 0x58, 0x5A, 0xA7, 0xDB, 0x92, 0x27, 0x2D, 0x39, 0x96, 0xC6, + 0xA9, 0xDC, 0x4E, 0xF0, 0x40, 0xE4, 0x30, 0x17, 0x47, 0xDE, 0x3F, 0x28, 0xAD, 0xE9, 0x30, 0x80, + 0x78, 0xF8, 0xE8, 0xB6, 0x4E, 0x14, 0xE3, 0x07, 0xC8, 0x20, 0x6D, 0x63, 0xFC, 0x06, 0x03, 0x08, + 0xD2, 0xD8, 0x61, 0x4C, 0xBD, 0x51, 0x66, 0x2A, 0x59, 0x05, 0x28, 0xC4, 0x54, 0x5A, 0x65, 0x67, + 0xC3, 0x4C, 0x75, 0x19, 0x53, 0x19, 0x4E, 0x9A, 0x60, 0x2A, 0x39, 0x0F, 0x2E, 0xC4, 0x54, 0xDA, + 0x44, 0x38, 0x62, 0xEA, 0x21, 0x04, 0x3A, 0x32, 0x32, 0xA6, 0xA3, 0x12, 0xA1, 0xEE, 0xF2, 0xE2, + 0xF0, 0xC5, 0x9B, 0x0B, 0x8D, 0x2E, 0x69, 0x3A, 0x56, 0xC1, 0x88, 0x17, 0xEF, 0xF4, 0x2F, 0x15, + 0xF3, 0x28, 0xE9, 0x42, 0xD4, 0x7B, 0x73, 0xA1, 0x1A, 0xF0, 0x38, 0x64, 0x91, 0x90, 0xD7, 0x6B, + 0x75, 0xCA, 0x54, 0x08, 0x43, 0x22, 0xB7, 0x14, 0xF4, 0x28, 0xFA, 0x76, 0x24, 0x83, 0xCB, 0x62, + 0x32, 0x28, 0x54, 0x25, 0x8D, 0xCB, 0xA0, 0x40, 0xD8, 0x0F, 0x88, 0xDC, 0xA6, 0x0C, 0x30, 0x4A, + 0x5E, 0x5E, 0x68, 0xEF, 0xFF, 0xA9, 0x5D, 0xDE, 0x2C, 0x1C, 0x6F, 0xE9, 0x92, 0xDC, 0xA8, 0xC2, + 0xE1, 0xE2, 0x71, 0xA5, 0xDF, 0xEB, 0x75, 0x54, 0x03, 0x4B, 0x2F, 0x7D, 0x08, 0x98, 0xB4, 0x36, + 0x18, 0x2F, 0x29, 0xA1, 0xDD, 0x90, 0xC1, 0x0F, 0x04, 0x34, 0xAD, 0x14, 0x37, 0x39, 0x60, 0x9C, + 0x43, 0xBD, 0x85, 0xDB, 0xAB, 0x15, 0x19, 0x94, 0x67, 0x94, 0x9D, 0x8D, 0x0E, 0x07, 0x94, 0xCA, + 0x5E, 0xC8, 0xDE, 0xA7, 0x8F, 0x57, 0x6A, 0x8C, 0x25, 0xEB, 0x68, 0xC5, 0x54, 0x97, 0xF6, 0xC8, + 0x68, 0xC1, 0x41, 0x41, 0xDE, 0xE8, 0xEC, 0x10, 0x62, 0xEC, 0xBA, 0x6C, 0x52, 0x44, 0x76, 0x36, + 0x31, 0xA7, 0x60, 0xB0, 0x72, 0x59, 0x52, 0x19, 0xB2, 0xB7, 0x9A, 0xE2, 0x17, 0x48, 0x9B, 0x23, + 0x08, 0xF3, 0xA0, 0x7B, 0xF4, 0xAE, 0x40, 0xB2, 0x73, 0x63, 0x4A, 0xA2, 0xEB, 0x1A, 0x0B, 0xE2, + 0x59, 0xC1, 0xD9, 0x60, 0x08, 0x8D, 0x6B, 0xC2, 0x3F, 0x97, 0xAA, 0xCD, 0x5C, 0x32, 0x39, 0xAF, + 0x7D, 0x13, 0xE2, 0xE4, 0x8F, 0xDF, 0x61, 0x93, 0x9A, 0x36, 0x76, 0x56, 0xB6, 0xE5, 0x18, 0x18, + 0xF8, 0x8D, 0x85, 0x0F, 0x94, 0x1E, 0xFC, 0xB1, 0xC0, 0x37, 0x5C, 0x19, 0xF8, 0xB4, 0x96, 0x91, + 0xD1, 0x8F, 0xA0, 0xFE, 0x91, 0xE5, 0x78, 0xC1, 0xB4, 0x0D, 0x0F, 0xC3, 0xCF, 0xAB, 0xFE, 0xCF, + 0x7F, 0xE7, 0x6D, 0x15, 0x30, 0xE7, 0x53, 0x41, 0x00, 0x35, 0xCD, 0x73, 0x47, 0xE7, 0x35, 0xA0, + 0xD4, 0x75, 0x3C, 0xCF, 0x71, 0xCD, 0xA9, 0x99, 0x32, 0x36, 0xA7, 0x49, 0xFB, 0x50, 0x26, 0xEE, + 0x44, 0x63, 0xC9, 0xB0, 0x7F, 0xE6, 0x8D, 0x5C, 0x73, 0xE1, 0x0F, 0x1E, 0x8D, 0x9D, 0xD1, 0x72, + 0x4E, 0x6C, 0xFF, 0xC0, 0x18, 0x8F, 0x2F, 0xAF, 0xE1, 0xE0, 0x3B, 0xFC, 0x16, 0x1F, 0x48, 0xBE, + 0x51, 0x7F, 0xF5, 0xAF, 0x77, 0x38, 0x0C, 0xE3, 0x35, 0x90, 0x17, 0x19, 0xD7, 0xF7, 0xB5, 0xC9, + 0xD2, 0x66, 0x23, 0x61, 0x83, 0x60, 0xDB, 0x3D, 0xED, 0x2B, 0x60, 0xBC, 0x36, 0x5C, 0x6D, 0x68, + 0x78, 0xE4, 0xAD, 0xE3, 0xF9, 0xDA, 0xB9, 0x16, 0x62, 0xB4, 0x9C, 0x11, 0xDD, 0xB7, 0x71, 0xC0, + 0xF8, 0xE2, 0x2D, 0x19, 0xE3, 0x3F, 0xBA, 0x16, 0x34, 0x0D, 0xA1, 0x9E, 0x6A, 0xF5, 0xD3, 0x63, + 0xBD, 0x8E, 0xF6, 0x17, 0x76, 0x31, 0x21, 0x10, 0xE6, 0xA1, 0x5D, 0x63, 0xE9, 0x5A, 0xFB, 0xDA, + 0x68, 0xB8, 0xF7, 0x95, 0x52, 0x4F, 0x2F, 0xE3, 0xB5, 0x3D, 0xCE, 0xCC, 0x81, 0x3F, 0x23, 0x76, + 0x23, 0xA2, 0xCC, 0x25, 0xDE, 0xC2, 0xB1, 0x3D, 0xC2, 0x88, 0x63, 0x3F, 0x73, 0x12, 0x5D, 0x3F, + 0xF0, 0x7C, 0xC3, 0x5F, 0x7A, 0xDA, 0xE3, 0xF3, 0x73, 0xAD, 0xDD, 0x6A, 0x89, 0xCD, 0x34, 0xE8, + 0x26, 0xD9, 0x6E, 0x5F, 0x4B, 0x5C, 0xF8, 0x48, 0x6E, 0xFC, 0xBD, 0x67, 0x21, 0xCC, 0x9D, 0x46, + 0x2C, 0x8F, 0xC4, 0x90, 0x84, 0x00, 0xF8, 0xDE, 0xB8, 0xC6, 0x5E, 0x9C, 0xC0, 0xC6, 0xD8, 0xF0, + 0x8D, 0xBD, 0xAF, 0x31, 0x7D, 0x41, 0xAF, 0x40, 0xC9, 0xBE, 0x46, 0x6F, 0x3D, 0x13, 0x6E, 0xDD, + 0xED, 0x1D, 0x80, 0x0C, 0x81, 0xDF, 0x10, 0x9A, 0xB8, 0x6E, 0x9C, 0x62, 0x0A, 0xDD, 0xD4, 0xF7, + 0x35, 0xBC, 0x13, 0x87, 0x15, 0x88, 0x7C, 0x14, 0x5C, 0x0B, 0x84, 0x96, 0x8D, 0x56, 0x82, 0x92, + 0xA1, 0xBB, 0x8B, 0xA9, 0x08, 0x02, 0xCE, 0x07, 0x32, 0x05, 0x89, 0x4D, 0xF7, 0x79, 0xFC, 0xD9, + 0xA7, 0xC1, 0x67, 0x9F, 0xC5, 0x2D, 0x41, 0x6B, 0x87, 0x87, 0xE0, 0xD2, 0x9E, 0x63, 0x11, 0xB0, + 0x8A, 0x69, 0xA3, 0xCE, 0xBF, 0xF5, 0x0A, 0x16, 0x55, 0x6F, 0xDD, 0xD4, 0x9F, 0x02, 0x82, 0x03, + 0xDF, 0xB9, 0xF2, 0x5D, 0xD3, 0x9E, 0x36, 0xF4, 0xFE, 0x5E, 0x84, 0x8D, 0xDE, 0x46, 0x94, 0x89, + 0xFB, 0xF4, 0x3A, 0xED, 0x24, 0x79, 0xA3, 0xC1, 0xAF, 0x3F, 0xAD, 0xEF, 0xD5, 0x39, 0xF1, 0xF4, + 0x1C, 0xCC, 0xAD, 0xC1, 0x0E, 0x9E, 0x50, 0x1A, 0xF7, 0xB4, 0xB3, 0x33, 0xDE, 0x0D, 0x6B, 0x85, + 0x17, 0xA1, 0x11, 0xFD, 0x93, 0xB8, 0x15, 0x9A, 0xE2, 0xEF, 0xFF, 0xF8, 0x1A, 0xD8, 0xEC, 0xDD, + 0x21, 0x50, 0xFD, 0x1C, 0x43, 0xF0, 0x3F, 0xBE, 0xC2, 0xFF, 0x77, 0x4F, 0x68, 0xD4, 0xFD, 0xC7, + 0x57, 0xFC, 0x73, 0xF7, 0x04, 0x7A, 0x82, 0x63, 0xDA, 0xDF, 0xDD, 0xEF, 0x54, 0x0E, 0xEB, 0xD2, + 0x9B, 0xA6, 0x4A, 0x2F, 0x14, 0x5B, 0x61, 0x9A, 0xA6, 0x19, 0x44, 0xFD, 0x1E, 0xF9, 0x6F, 0x63, + 0xE4, 0x8C, 0x41, 0x3D, 0x3E, 0x58, 0x72, 0xA0, 0x74, 0x0B, 0x54, 0x12, 0x08, 0xAA, 0x15, 0x28, + 0xDD, 0x9C, 0xD0, 0x96, 0x1A, 0x77, 0x95, 0xC8, 0x40, 0x82, 0x96, 0x0B, 0xC3, 0xF5, 0xC8, 0xB7, + 0xB6, 0xDF, 0xF0, 0x63, 0x4E, 0x91, 0x22, 0xF1, 0xC1, 0x20, 0xC6, 0x02, 0xFE, 0x00, 0x0E, 0xDA, + 0xD5, 0xB9, 0xD2, 0x42, 0x63, 0xE3, 0x7F, 0x13, 0x66, 0xF3, 0xA6, 0x90, 0xD9, 0x34, 0xA8, 0xD8, + 0xC2, 0x3E, 0xF7, 0x8A, 0x98, 0x10, 0x90, 0x25, 0x18, 0x10, 0x75, 0x88, 0x48, 0x64, 0xEC, 0x62, + 0x8A, 0x43, 0xFC, 0x3C, 0xB2, 0xBE, 0x34, 0x6E, 0xE0, 0xBF, 0x64, 0xCC, 0x5A, 0xD3, 0x15, 0x36, + 0x7A, 0x8E, 0xFF, 0x81, 0x82, 0xF0, 0x4F, 0xAA, 0xA1, 0x00, 0xD6, 0xF7, 0x96, 0xD5, 0x60, 0x1F, + 0x98, 0x03, 0x1B, 0x59, 0x42, 0x3C, 0xF4, 0x6E, 0x31, 0x32, 0x39, 0x8E, 0xFF, 0x79, 0x5F, 0x5B, + 0xB8, 0x40, 0x18, 0xFD, 0x96, 0x0A, 0x1C, 0x03, 0x22, 0x62, 0xB3, 0xBF, 0xB9, 0x14, 0x2C, 0x2C, + 0xEB, 0x39, 0xC3, 0x0A, 0x24, 0xB0, 0x03, 0x30, 0x99, 0x25, 0x9A, 0x2E, 0xFC, 0x7F, 0xF7, 0x04, + 0x3A, 0x81, 0x43, 0xF8, 0xFF, 0xEE, 0x09, 0x76, 0x85, 0x46, 0x85, 0x3D, 0xDE, 0x3D, 0x81, 0x1E, + 0xE1, 0x04, 0xFE, 0x87, 0x36, 0xD8, 0x2F, 0xB6, 0xC2, 0xBF, 0x70, 0x87, 0xF6, 0x8F, 0x37, 0xE9, + 0x01, 0xBB, 0xC0, 0x4F, 0xB3, 0x18, 0x64, 0x6F, 0xD7, 0x6F, 0xD0, 0xB7, 0x9D, 0x7F, 0xBE, 0x01, + 0x76, 0xE8, 0xC1, 0x2D, 0xC4, 0x20, 0x7B, 0x8C, 0xE7, 0xF8, 0xE7, 0x36, 0x50, 0x30, 0x5E, 0xE0, + 0x47, 0x70, 0x8D, 0xBE, 0x11, 0x16, 0x2F, 0xB1, 0x03, 0x6C, 0x45, 0xDF, 0xDF, 0x49, 0x5B, 0xB1, + 0x23, 0xB8, 0xC6, 0xDF, 0xFA, 0xB8, 0xAF, 0xF1, 0xF7, 0x0A, 0xE6, 0x0A, 0x27, 0x7A, 0xEF, 0xDF, + 0x73, 0xEF, 0x06, 0x19, 0x64, 0xA4, 0xA1, 0x54, 0xC2, 0xB3, 0xDB, 0xBB, 0x27, 0x04, 0xEF, 0x51, + 0x22, 0xE1, 0xF8, 0x96, 0x1F, 0xC3, 0x75, 0xA0, 0x0F, 0xEF, 0x04, 0x04, 0xD3, 0x0B, 0xB7, 0xD1, + 0x05, 0x68, 0xE1, 0xE3, 0x7D, 0x4E, 0x3C, 0x9C, 0xDD, 0x86, 0x67, 0x08, 0x4D, 0x61, 0x39, 0x1B, + 0x70, 0x7A, 0x1B, 0x9D, 0xC2, 0x5D, 0xE4, 0x05, 0x15, 0xC0, 0x79, 0xBA, 0x7B, 0xC2, 0x79, 0x42, + 0x2D, 0xB2, 0xA3, 0xB8, 0xA8, 0xE1, 0x7F, 0xF4, 0x23, 0x9F, 0x07, 0xEC, 0x4F, 0x81, 0x77, 0x12, + 0x6B, 0x4F, 0x3B, 0x1F, 0xF0, 0xB8, 0x8F, 0x01, 0x00, 0x3C, 0x0A, 0xAE, 0x13, 0xEB, 0xC0, 0xF0, + 0xC1, 0x21, 0x20, 0x6F, 0x22, 0xDE, 0x01, 0x46, 0x94, 0xD0, 0xCD, 0xD7, 0x6E, 0x1D, 0xD8, 0xE0, + 0x16, 0x14, 0xE1, 0xDE, 0x29, 0x0F, 0x1B, 0x88, 0x88, 0x71, 0xB9, 0x86, 0x8B, 0x5D, 0x4E, 0x43, + 0xC7, 0xEE, 0xA6, 0x60, 0xE4, 0xA1, 0x30, 0x0E, 0x81, 0x17, 0xD3, 0xB0, 0xD1, 0x51, 0x43, 0xC0, + 0xD5, 0xEE, 0xF5, 0x22, 0x6C, 0x89, 0x48, 0xC7, 0xE6, 0x94, 0x28, 0x90, 0x03, 0xCC, 0xCF, 0xA3, + 0xA1, 0x70, 0x04, 0xE6, 0xA0, 0xD5, 0x83, 0x09, 0x65, 0xFD, 0x74, 0x2D, 0xC2, 0x01, 0x04, 0x2F, + 0x20, 0x68, 0xCF, 0x19, 0x8D, 0xA7, 0x51, 0xF8, 0xD4, 0xB4, 0x21, 0x24, 0x3B, 0x5F, 0x9E, 0xC5, + 0x90, 0xD1, 0xD4, 0x3F, 0xC4, 0xC4, 0xAE, 0x61, 0xA2, 0x90, 0xB8, 0xC4, 0xB6, 0xDB, 0x35, 0x1D, + 0x9B, 0xC8, 0x7B, 0x8D, 0xC5, 0x4B, 0xDE, 0x11, 0x3F, 0x1B, 0x93, 0x89, 0xB1, 0xB4, 0xFC, 0x08, + 0xCC, 0x25, 0x90, 0xE8, 0xDA, 0x3C, 0x6C, 0xB1, 0x24, 0x3F, 0x77, 0xE8, 0xCE, 0x18, 0x2A, 0x82, + 0x51, 0xE1, 0x71, 0x72, 0x54, 0x00, 0xAB, 0x74, 0xFD, 0x46, 0xFD, 0xD2, 0x75, 0x1D, 0xF7, 0xD7, + 0xFA, 0x53, 0x6C, 0xF4, 0xB4, 0xFE, 0xDB, 0xA9, 0x46, 0xE3, 0xE9, 0x5E, 0x3C, 0xB8, 0x0B, 0xE1, + 0xF3, 0xF0, 0x50, 0x7B, 0xE1, 0xFB, 0x06, 0x28, 0x00, 0x6B, 0x2C, 0x33, 0x94, 0x8F, 0x66, 0xF0, + 0x24, 0xD0, 0x71, 0xD1, 0x28, 0xD9, 0xF7, 0xEE, 0x41, 0x22, 0x98, 0x58, 0x7A, 0x00, 0x12, 0x24, + 0x99, 0x14, 0xD5, 0xC1, 0xBF, 0x97, 0xC4, 0xBD, 0xBD, 0xA2, 0x02, 0x73, 0xDC, 0x17, 0x10, 0x2A, + 0xEB, 0x07, 0xD1, 0x3C, 0xA9, 0xCE, 0x72, 0x9E, 0x03, 0x40, 0x75, 0x09, 0x7D, 0x80, 0x8E, 0x23, + 0x9B, 0x67, 0xDC, 0x84, 0x7A, 0x87, 0x71, 0xEE, 0x9C, 0x2B, 0x23, 0x99, 0x64, 0x41, 0x0B, 0xC7, + 0xFE, 0x42, 0x6E, 0x97, 0x0B, 0x10, 0x7F, 0x94, 0x36, 0x25, 0x12, 0x39, 0x2E, 0x1D, 0x72, 0x00, + 0x2D, 0x2F, 0xF8, 0xC0, 0xA9, 0x77, 0x24, 0x8D, 0x22, 0x15, 0x50, 0xEB, 0x44, 0x4F, 0x7C, 0xB6, + 0xD6, 0xE8, 0xEE, 0x91, 0xFC, 0x4C, 0x92, 0x72, 0x72, 0x02, 0xB9, 0xF0, 0xC0, 0xB5, 0xA9, 0x63, + 0x27, 0x7A, 0x48, 0xA4, 0x83, 0x90, 0x0C, 0x46, 0x91, 0x61, 0xB9, 0x80, 0xE4, 0x93, 0xC4, 0x83, + 0x43, 0x68, 0x0B, 0xC1, 0xCD, 0xB9, 0xE3, 0x93, 0x44, 0xC4, 0x30, 0x6D, 0xD3, 0x37, 0x0D, 0xEB, + 0x53, 0x64, 0x8D, 0x5B, 0x75, 0x7F, 0x89, 0x8F, 0x17, 0xF0, 0xFF, 0xB5, 0x9C, 0x4F, 0x2D, 0x4F, + 0x59, 0xB3, 0x90, 0x30, 0x1E, 0x44, 0x56, 0x22, 0xCA, 0x21, 0x16, 0x16, 0xF8, 0xFD, 0xA0, 0xA7, + 0xC7, 0x8F, 0xE9, 0xD1, 0xA3, 0x50, 0x69, 0x41, 0xF4, 0x38, 0xD7, 0xA2, 0x1B, 0x09, 0x05, 0xAF, + 0xE3, 0x4E, 0xE0, 0x08, 0x90, 0x0B, 0x18, 0x12, 0x81, 0x7F, 0x01, 0xE9, 0x0D, 0xDA, 0xC2, 0xFF, + 0x47, 0xFD, 0x07, 0x14, 0xF5, 0xB7, 0x17, 0xE2, 0x33, 0x6C, 0x3B, 0xE1, 0x01, 0x0C, 0x4E, 0x9E, + 0x4F, 0x3F, 0x85, 0x44, 0x5B, 0x9E, 0x24, 0x87, 0xA1, 0x3B, 0x9C, 0xEC, 0xC3, 0x64, 0xE6, 0x92, + 0x85, 0xE7, 0x97, 0xB7, 0xDF, 0x8E, 0x1B, 0xF5, 0xF0, 0x8D, 0x46, 0xF5, 0x3D, 0x8C, 0x4B, 0x96, + 0x39, 0xFA, 0x12, 0x86, 0xA5, 0xC8, 0xF2, 0x20, 0xA5, 0xC1, 0xEC, 0x1F, 0x27, 0xD6, 0xE6, 0x88, + 0x9B, 0xEA, 0xAB, 0x0F, 0x2F, 0xDE, 0x7D, 0x7E, 0xF1, 0xF1, 0xE3, 0x07, 0x6D, 0x09, 0x36, 0xAB, + 0xF7, 0x3F, 0x63, 0xDA, 0x02, 0x93, 0x00, 0xF7, 0x33, 0xD0, 0xE7, 0x7D, 0xA6, 0x48, 0x5B, 0xBF, + 0xFE, 0xF6, 0x6B, 0xFB, 0x37, 0x00, 0xFD, 0xFA, 0x5F, 0x76, 0x9D, 0x31, 0x82, 0xA8, 0x9E, 0x02, + 0x2E, 0x3C, 0xFE, 0x5A, 0x7F, 0x1A, 0x18, 0x7C, 0x23, 0x9D, 0xC2, 0xF0, 0xF5, 0xBA, 0xF5, 0x3D, + 0x60, 0xF5, 0x6E, 0x1F, 0x50, 0xB1, 0x74, 0x10, 0xC6, 0x9C, 0x06, 0x96, 0x2A, 0x4C, 0xE8, 0x40, + 0x7F, 0x06, 0x7F, 0xCE, 0x34, 0xFD, 0x08, 0xFE, 0x3E, 0x7D, 0x1A, 0x99, 0x48, 0xC9, 0xEE, 0xEA, + 0x4F, 0x4D, 0xDA, 0x19, 0xCC, 0x4E, 0x1A, 0xE6, 0x19, 0x48, 0xF2, 0x79, 0x7D, 0xBF, 0x7E, 0x5A, + 0xAF, 0xC3, 0xB5, 0xA0, 0xFB, 0xBB, 0x18, 0x3B, 0x77, 0xCF, 0x42, 0x0E, 0xD9, 0xE8, 0x0A, 0x37, + 0x22, 0xF1, 0x8B, 0x59, 0xDD, 0x4B, 0x56, 0xE5, 0x3A, 0x4F, 0xD7, 0x09, 0x7B, 0x9B, 0xF5, 0x94, + 0x0E, 0x88, 0x22, 0x4C, 0x86, 0x82, 0x58, 0x68, 0x08, 0x7D, 0x2D, 0x15, 0x35, 0x1D, 0x6E, 0xC7, + 0x63, 0x17, 0xB4, 0x4D, 0xAD, 0x65, 0x6F, 0xCD, 0x85, 0xD5, 0x70, 0x60, 0x63, 0x09, 0x8E, 0xB5, + 0xE9, 0x66, 0x26, 0x12, 0xDA, 0x5A, 0xC0, 0xB2, 0x96, 0xF0, 0xB4, 0xEE, 0x2F, 0xD7, 0x61, 0x1A, + 0x9B, 0x2A, 0x6A, 0x6C, 0x2A, 0x68, 0x6C, 0xBA, 0x59, 0x8D, 0x71, 0xD4, 0x95, 0xB5, 0x16, 0xE0, + 0xC9, 0xD1, 0x5C, 0x2E, 0x3C, 0x57, 0x1A, 0xD7, 0xD6, 0x54, 0xA6, 0xAD, 0x32, 0x6A, 0x62, 0xB1, + 0x0B, 0x26, 0x45, 0xC4, 0x7D, 0xFB, 0xF1, 0xDD, 0x77, 0x18, 0x6D, 0xE4, 0x2A, 0x0B, 0x35, 0x96, + 0x4C, 0xAE, 0x24, 0x18, 0x30, 0x28, 0xC6, 0x2A, 0x1F, 0x89, 0xB0, 0xA9, 0x45, 0x15, 0x84, 0x1C, + 0x43, 0xE0, 0x05, 0x03, 0x35, 0xDF, 0xC5, 0x22, 0x41, 0xE0, 0xBC, 0x11, 0x54, 0x86, 0x2D, 0x20, + 0x80, 0x92, 0x12, 0x19, 0xE6, 0x35, 0x87, 0x11, 0x6A, 0x19, 0x3B, 0x77, 0x11, 0xEA, 0xAF, 0x9E, + 0x6A, 0x50, 0x0B, 0xA6, 0xEA, 0x51, 0x6C, 0xF3, 0x72, 0xA5, 0xC3, 0x27, 0xF4, 0x4A, 0x02, 0xE2, + 0x5F, 0x95, 0x93, 0x18, 0x38, 0x2F, 0x04, 0x14, 0xC0, 0x72, 0x2B, 0xC1, 0x42, 0x0B, 0x08, 0x4A, + 0x38, 0xE8, 0x97, 0xC8, 0x52, 0x30, 0xA8, 0x51, 0x41, 0x3F, 0xFD, 0x25, 0xC1, 0x10, 0x94, 0x2A, + 0x94, 0x90, 0x04, 0x9F, 0xAD, 0x4A, 0xC7, 0xA3, 0x46, 0x4C, 0xF0, 0xB1, 0x28, 0x09, 0x1E, 0x5E, + 0x1A, 0x51, 0x42, 0xC3, 0x3F, 0x74, 0x94, 0x8A, 0x45, 0x8D, 0x18, 0xFE, 0x6D, 0x21, 0x19, 0x4F, + 0xBC, 0x14, 0xA3, 0xC6, 0x13, 0xFF, 0x24, 0x4E, 0x3A, 0x1E, 0x45, 0xD9, 0xF0, 0xCF, 0xD0, 0xC8, + 0xAC, 0x8E, 0x55, 0x7E, 0x32, 0x1D, 0x83, 0x35, 0x01, 0x60, 0x9E, 0xAA, 0x3E, 0xD7, 0xC5, 0xCC, + 0x9A, 0x17, 0x8A, 0xB2, 0x30, 0xF0, 0x26, 0x49, 0x0C, 0x41, 0x74, 0xB8, 0x87, 0x92, 0xDD, 0x7D, + 0x44, 0xA1, 0xF7, 0x96, 0xA5, 0x16, 0x85, 0x16, 0x96, 0x15, 0x84, 0x9F, 0x10, 0x26, 0x25, 0xFC, + 0xD0, 0x25, 0x33, 0x5A, 0x6F, 0xCD, 0x94, 0x3F, 0x6D, 0xC1, 0xF0, 0xAE, 0x2B, 0x11, 0x71, 0xCC, + 0x97, 0x96, 0x92, 0x25, 0x41, 0x3B, 0x8E, 0x46, 0x34, 0x24, 0xBA, 0x1C, 0x77, 0xEB, 0xA9, 0x85, + 0xAE, 0x5B, 0x2F, 0x05, 0x03, 0x2D, 0x09, 0xAB, 0xE5, 0x66, 0xD0, 0x32, 0x05, 0xC9, 0xC2, 0x55, + 0x4B, 0xEF, 0xA0, 0x5D, 0x1A, 0x23, 0x58, 0x7F, 0x56, 0x63, 0x25, 0xF8, 0xEA, 0xB8, 0x8C, 0x0E, + 0x5A, 0xB5, 0xCE, 0x52, 0x0A, 0xFF, 0xBA, 0x73, 0x9A, 0x46, 0x16, 0xAA, 0x43, 0x6E, 0xF0, 0xFD, + 0x63, 0xC9, 0xB0, 0x5B, 0xB2, 0xD8, 0xBF, 0x7B, 0xE7, 0x30, 0xAE, 0x89, 0x82, 0x6B, 0x84, 0x2B, + 0xF3, 0x3C, 0xBB, 0x8B, 0xC0, 0x32, 0xBC, 0x63, 0x64, 0xD8, 0xD7, 0x46, 0xCC, 0x3B, 0x46, 0x30, + 0xFD, 0xF5, 0x09, 0x47, 0xDD, 0xA8, 0xB1, 0x06, 0x35, 0x4E, 0x23, 0x3B, 0x3B, 0xA0, 0x5B, 0xD6, + 0xB0, 0x10, 0x62, 0x92, 0x15, 0x3B, 0x89, 0xDD, 0x9E, 0x11, 0xFA, 0x9A, 0x10, 0x7E, 0x9F, 0x9D, + 0xB1, 0x06, 0x61, 0x2F, 0x43, 0x67, 0x7C, 0x7B, 0x60, 0x2C, 0x16, 0x10, 0xBC, 0x2E, 0x66, 0xA6, + 0x35, 0x6E, 0x30, 0x50, 0xC1, 0x44, 0x70, 0x6F, 0x02, 0xA1, 0xAB, 0x56, 0x1C, 0x2B, 0x30, 0x7C, + 0xC1, 0xAE, 0x35, 0xEA, 0xED, 0x71, 0xB0, 0x66, 0xC4, 0x9B, 0x1D, 0x8C, 0x5D, 0x63, 0xF5, 0x2D, + 0x6E, 0x6A, 0x68, 0x60, 0xA7, 0xFB, 0xAD, 0xFD, 0x16, 0x6F, 0xE0, 0xBB, 0xB7, 0x61, 0x96, 0x89, + 0x78, 0x71, 0xF1, 0xF7, 0xC7, 0x0F, 0xDF, 0x45, 0x78, 0x7D, 0xE7, 0x15, 0xBB, 0xD4, 0xA8, 0xD3, + 0x5D, 0x11, 0x87, 0x7F, 0x2C, 0x70, 0x2A, 0x10, 0x28, 0x45, 0x10, 0x23, 0x6E, 0x78, 0x40, 0x51, + 0xB1, 0xE6, 0xCF, 0x44, 0xA4, 0x70, 0xD9, 0x26, 0x2B, 0x0D, 0x30, 0x91, 0x86, 0x0C, 0x34, 0xD8, + 0x0E, 0x81, 0xE0, 0xC8, 0xC9, 0xEB, 0xA5, 0x65, 0xFD, 0x42, 0x0C, 0x17, 0xF4, 0xF1, 0x54, 0x6B, + 0xD4, 0x5A, 0xB5, 0xA7, 0x0D, 0x7A, 0xFD, 0x1D, 0xB0, 0x33, 0x6B, 0xEC, 0x3D, 0xD5, 0xF7, 0xF6, + 0x0E, 0x3C, 0xD0, 0x19, 0x69, 0x34, 0xDB, 0x41, 0x13, 0xF8, 0x43, 0xDB, 0xB0, 0x4E, 0xD2, 0xEF, + 0xBF, 0x75, 0x96, 0xAE, 0x97, 0xD5, 0xE0, 0x9D, 0x69, 0x63, 0x11, 0x27, 0xAB, 0xC9, 0x15, 0x01, + 0xC1, 0x8E, 0xD7, 0x9A, 0xD4, 0xE8, 0x2E, 0x0E, 0x5E, 0xFE, 0xD0, 0xE8, 0xE2, 0xB6, 0xD6, 0x10, + 0x2B, 0x3A, 0x7C, 0x19, 0x91, 0xA0, 0xA1, 0x37, 0x02, 0x8F, 0xBF, 0x13, 0x8D, 0x03, 0x5C, 0x16, + 0x0C, 0xE0, 0x7B, 0xF0, 0x80, 0x03, 0x97, 0xCC, 0x9D, 0x6B, 0xB2, 0xA6, 0x7F, 0x6C, 0x1E, 0x1A, + 0xFF, 0xCC, 0x1C, 0xB3, 0x32, 0x4D, 0x64, 0xB7, 0x58, 0x15, 0xC2, 0x0D, 0x22, 0xB8, 0x85, 0x02, + 0xF7, 0x53, 0x34, 0xEA, 0x6C, 0xF7, 0x0A, 0x1D, 0x15, 0xEE, 0x22, 0xB7, 0x99, 0x39, 0xAB, 0x2C, + 0x48, 0xD6, 0x7B, 0x02, 0x38, 0x84, 0x1E, 0x9B, 0x9E, 0x31, 0xB4, 0xF2, 0xBB, 0xE6, 0xED, 0xC6, + 0xBC, 0xFC, 0x0D, 0x0D, 0x82, 0x2B, 0x00, 0xEA, 0xBB, 0xB4, 0x4E, 0x28, 0xA0, 0x25, 0x76, 0x1E, + 0xD6, 0x80, 0xAC, 0x4C, 0xC4, 0x13, 0x03, 0x26, 0x4F, 0x71, 0xCC, 0xAC, 0x78, 0x5C, 0xA0, 0xAC, + 0x2C, 0x5E, 0x06, 0x88, 0xF8, 0x29, 0x98, 0x33, 0x58, 0xA8, 0xF6, 0x9C, 0xB2, 0xA0, 0x9D, 0xC6, + 0xEE, 0x86, 0xB9, 0x8D, 0x58, 0x30, 0x7D, 0xC4, 0xE2, 0xDF, 0x5F, 0xB0, 0x82, 0x1B, 0x52, 0x1E, + 0x93, 0xC0, 0x93, 0x27, 0x71, 0x6C, 0xB8, 0x8D, 0x85, 0x0D, 0x20, 0x61, 0x6F, 0xAC, 0x3D, 0x7B, + 0x7D, 0x78, 0xB4, 0xB2, 0xC0, 0x49, 0x82, 0xA1, 0xE0, 0x71, 0x4C, 0xF0, 0xC2, 0x18, 0x01, 0x84, + 0x98, 0x63, 0x2A, 0x20, 0xDC, 0x95, 0x56, 0x5B, 0x5B, 0xEF, 0x7F, 0x4E, 0xAD, 0xBE, 0x41, 0xF8, + 0xA6, 0xC4, 0x3D, 0x90, 0x3F, 0x1A, 0x73, 0x74, 0x21, 0x3E, 0x87, 0x4E, 0x60, 0x9C, 0xC6, 0x30, + 0x22, 0x63, 0x09, 0xBA, 0xF1, 0x77, 0x78, 0x48, 0x31, 0x4E, 0x0D, 0xD3, 0xBE, 0x20, 0x26, 0xA6, + 0x7F, 0x7B, 0xC2, 0x5D, 0xDA, 0x3D, 0x20, 0xC2, 0x0D, 0x83, 0xC2, 0x72, 0xC6, 0xFA, 0x7A, 0xC8, + 0xE1, 0x21, 0x6D, 0x9A, 0x82, 0x86, 0x76, 0xB1, 0x8E, 0x26, 0x93, 0xFA, 0xD5, 0xF0, 0x33, 0x62, + 0x93, 0x09, 0x85, 0xA2, 0x5B, 0x0D, 0x51, 0x1C, 0xB4, 0x57, 0x38, 0xCC, 0x42, 0x35, 0x31, 0x46, + 0xE4, 0xB3, 0x0B, 0x71, 0x6C, 0x6A, 0x9B, 0x7F, 0x12, 0x19, 0x42, 0xE6, 0x8C, 0x0D, 0x62, 0xBB, + 0x4E, 0x90, 0x48, 0x22, 0x72, 0xEE, 0x67, 0xF1, 0xEB, 0xF1, 0x21, 0x3A, 0x70, 0xBD, 0x70, 0x69, + 0x5D, 0xB4, 0x05, 0x56, 0xFA, 0x8F, 0x26, 0xC0, 0x91, 0xB1, 0x6D, 0xA8, 0x12, 0xAE, 0x63, 0x19, + 0x3C, 0x6C, 0x22, 0xD6, 0xAB, 0x2B, 0x16, 0xC1, 0x33, 0x70, 0xB2, 0xCD, 0x7D, 0x49, 0xA4, 0xCB, + 0xE1, 0xDC, 0xF4, 0x25, 0x08, 0xEB, 0x7A, 0x5D, 0x8A, 0x2B, 0xA5, 0x9E, 0x2E, 0x7A, 0x22, 0x8B, + 0x66, 0x74, 0xA9, 0x11, 0x10, 0xC5, 0xB6, 0x0A, 0x8C, 0xD8, 0x6E, 0xF5, 0xE7, 0x30, 0xE2, 0xE2, + 0x06, 0x00, 0x54, 0x75, 0x62, 0x0B, 0x10, 0x43, 0xC1, 0xF6, 0xAE, 0x51, 0x14, 0xF1, 0xDD, 0x6B, + 0xC1, 0x8E, 0xB1, 0xF8, 0xCA, 0xA4, 0xB8, 0xF7, 0xE5, 0x77, 0x97, 0x00, 0x9C, 0x87, 0xF3, 0x59, + 0xED, 0x1F, 0x5F, 0x29, 0x8A, 0x3B, 0x6D, 0x02, 0x91, 0xC0, 0x9B, 0x91, 0x31, 0x9D, 0x7B, 0xF9, + 0x4B, 0xEF, 0x54, 0xC3, 0x6D, 0x3F, 0xB1, 0xDD, 0x6A, 0x77, 0xBF, 0x87, 0x16, 0x12, 0x0E, 0x24, + 0xD1, 0x7A, 0x2B, 0x67, 0x7B, 0x6D, 0xDD, 0xF5, 0x91, 0xC2, 0x0A, 0x2B, 0x87, 0x55, 0x5A, 0x65, + 0x95, 0x2D, 0x4E, 0x26, 0xA3, 0x14, 0xCF, 0x31, 0x1F, 0xA9, 0xF4, 0x4D, 0x77, 0x5D, 0xAA, 0x74, + 0x29, 0xC9, 0x2E, 0xF1, 0xC7, 0xC2, 0x98, 0x25, 0x8C, 0xF9, 0x09, 0x3F, 0xDA, 0xE3, 0x72, 0x02, + 0x13, 0x19, 0x07, 0xF1, 0x96, 0x19, 0x11, 0xAE, 0x3E, 0x33, 0x3D, 0xC6, 0x4C, 0x80, 0x49, 0x9B, + 0x0B, 0x3B, 0x7F, 0x4B, 0x22, 0x5F, 0x76, 0x09, 0x95, 0xF5, 0x87, 0x07, 0x79, 0x7B, 0x28, 0x02, + 0x19, 0x0E, 0xEC, 0x40, 0x40, 0x10, 0x13, 0x51, 0x21, 0x15, 0x65, 0xC8, 0x8C, 0xFD, 0x84, 0x01, + 0x9B, 0x8E, 0xD6, 0xB4, 0xE7, 0x5F, 0xA9, 0x55, 0xFF, 0xB6, 0xCF, 0x46, 0x78, 0x21, 0x68, 0xEE, + 0x15, 0x21, 0x68, 0x6D, 0x55, 0x3E, 0x97, 0x98, 0x8D, 0xAD, 0x4F, 0x06, 0x3F, 0x88, 0xC5, 0x14, + 0xDF, 0xB9, 0xD6, 0x5A, 0x5B, 0x97, 0x17, 0x17, 0xD1, 0x42, 0x06, 0x25, 0xB2, 0x11, 0x16, 0xD5, + 0x03, 0xF1, 0x48, 0x17, 0xD0, 0x52, 0xC5, 0xC5, 0xEC, 0x8B, 0x45, 0x14, 0x9C, 0x16, 0x64, 0xCE, + 0x9F, 0xE8, 0x86, 0x59, 0x2A, 0xAF, 0x08, 0xE0, 0x22, 0xDC, 0x20, 0x9D, 0x0B, 0x19, 0x6D, 0xA6, + 0x16, 0x70, 0xD0, 0xF9, 0x98, 0xDA, 0xFA, 0x03, 0x9F, 0xBA, 0x09, 0xA0, 0x88, 0x35, 0x1F, 0x36, + 0x78, 0x4A, 0x26, 0x49, 0xBE, 0x38, 0x7A, 0x65, 0xC1, 0xD3, 0x61, 0x92, 0x35, 0x16, 0xA0, 0xA9, + 0xE7, 0xE7, 0x03, 0x8B, 0xDB, 0xB2, 0xEB, 0x82, 0xB0, 0x3D, 0xDF, 0x59, 0x5C, 0xD1, 0xAB, 0x89, + 0xA8, 0xB0, 0xA2, 0xC5, 0xAC, 0x03, 0xBC, 0x1F, 0xCC, 0x93, 0x44, 0x46, 0xE3, 0xF5, 0xFF, 0x2B, + 0xAC, 0x74, 0x69, 0x0C, 0x4F, 0x3D, 0x9E, 0xED, 0xD2, 0x22, 0x98, 0xB4, 0x07, 0x3A, 0xE7, 0xF4, + 0xDC, 0x11, 0x1B, 0x3C, 0xC2, 0x6D, 0xD0, 0x18, 0x3A, 0xF0, 0xF0, 0x77, 0xD6, 0x27, 0xA6, 0x12, + 0x31, 0x05, 0xEF, 0xE5, 0xD2, 0xE2, 0x2C, 0x92, 0xA4, 0x44, 0x01, 0x9E, 0x39, 0x9B, 0x87, 0xA3, + 0x06, 0x1B, 0x28, 0x31, 0x7C, 0x09, 0xCA, 0x4F, 0x89, 0x91, 0x91, 0x98, 0x78, 0x50, 0x8A, 0x13, + 0x2F, 0x8C, 0x7C, 0x6C, 0x0F, 0xFD, 0xF3, 0xCF, 0xA3, 0x21, 0x0C, 0x76, 0x38, 0x01, 0x04, 0xD7, + 0x5B, 0x35, 0xF6, 0xEE, 0xB2, 0xD8, 0x61, 0xE2, 0x8A, 0x14, 0xA9, 0x4A, 0x04, 0x8D, 0xDA, 0x72, + 0x6C, 0x31, 0xF9, 0xC8, 0xD1, 0x89, 0xD6, 0x7B, 0x69, 0x07, 0x13, 0x96, 0x34, 0xC1, 0x9E, 0xAF, + 0x8B, 0x96, 0xE5, 0xAC, 0x31, 0x04, 0x51, 0x3C, 0x5E, 0x23, 0x36, 0x91, 0x94, 0x0A, 0x76, 0x11, + 0x34, 0x08, 0x68, 0x17, 0x1D, 0x22, 0x85, 0xF6, 0xF8, 0x58, 0x99, 0x48, 0xFF, 0x02, 0x95, 0x5F, + 0x2C, 0x81, 0x88, 0x79, 0xA0, 0x72, 0x76, 0x0D, 0x33, 0xDC, 0xD0, 0x36, 0x21, 0xE3, 0xCD, 0xF2, + 0x19, 0xB8, 0x2D, 0x38, 0x1A, 0x4F, 0x8F, 0x73, 0x00, 0x68, 0x4E, 0xCC, 0x1E, 0x84, 0xA1, 0xB0, + 0x6C, 0xC3, 0xAE, 0xAF, 0x09, 0x89, 0x77, 0x66, 0x7C, 0x81, 0x66, 0x23, 0xD6, 0x4C, 0x40, 0x02, + 0x78, 0xD7, 0xD3, 0x05, 0x89, 0x20, 0xA0, 0xDD, 0x5E, 0xA8, 0x17, 0x04, 0xE2, 0x99, 0x68, 0xA4, + 0x95, 0xF4, 0xD9, 0xC4, 0xFA, 0x4C, 0x22, 0xA1, 0xB0, 0xF4, 0x19, 0xC4, 0xFA, 0xEC, 0xE1, 0x4E, + 0xD0, 0x42, 0xF0, 0xC4, 0x56, 0x24, 0x48, 0x92, 0x2D, 0x75, 0x22, 0x4A, 0x3D, 0x98, 0x49, 0xE5, + 0x40, 0x7C, 0xA6, 0xA9, 0x88, 0x28, 0x32, 0xA2, 0x28, 0x32, 0xC2, 0x45, 0x86, 0x00, 0x51, 0xE2, + 0x9E, 0x3F, 0xAD, 0x0B, 0xE3, 0xCA, 0x4F, 0x2F, 0x23, 0xCE, 0x56, 0xC3, 0x4C, 0x3A, 0xF9, 0x94, + 0x49, 0x60, 0x2F, 0x1B, 0x00, 0xDA, 0xCF, 0x61, 0xDC, 0x16, 0xD9, 0x5A, 0x0D, 0xD5, 0xD8, 0x0A, + 0xA6, 0x5C, 0x08, 0x10, 0xB1, 0x25, 0x9F, 0x98, 0x05, 0xAC, 0xBC, 0x22, 0x3E, 0x7F, 0xAE, 0xD3, + 0xB0, 0xC7, 0xDA, 0xC4, 0x35, 0xE6, 0xC4, 0x83, 0x09, 0x59, 0x48, 0xEC, 0x98, 0xDE, 0xCF, 0x1D, + 0xA2, 0x58, 0x33, 0x81, 0xC9, 0x70, 0x6A, 0x97, 0x0B, 0x1A, 0xB6, 0x14, 0xA0, 0x43, 0x3A, 0x32, + 0xA1, 0x83, 0x46, 0x6C, 0x6C, 0x0B, 0x4F, 0x95, 0x84, 0x15, 0xB6, 0x8E, 0x9C, 0x27, 0x42, 0xC0, + 0x26, 0x4A, 0x03, 0xAD, 0x97, 0x2C, 0x27, 0xB0, 0x84, 0x87, 0x31, 0x9B, 0x48, 0x6B, 0xC4, 0x06, + 0x21, 0x4B, 0xB1, 0x36, 0xA1, 0x83, 0x30, 0xF8, 0x34, 0x32, 0x73, 0x49, 0x61, 0xE5, 0xEA, 0xDA, + 0x7B, 0x8B, 0xE0, 0x34, 0x8F, 0xBF, 0xA9, 0xF3, 0xE2, 0xDB, 0xD7, 0x9A, 0xE3, 0x6A, 0x96, 0xB3, + 0x22, 0xB8, 0x59, 0x34, 0x58, 0x0A, 0xD6, 0x86, 0x04, 0x12, 0x4B, 0xC2, 0x26, 0xD3, 0x18, 0x87, + 0xFC, 0x99, 0xE9, 0x41, 0xEA, 0x8E, 0xEF, 0x93, 0x25, 0x8F, 0x6B, 0x61, 0x31, 0x34, 0x97, 0xBD, + 0xF5, 0xAD, 0x55, 0x31, 0x71, 0x32, 0x98, 0x48, 0x96, 0x8F, 0x39, 0x8F, 0x6B, 0xC1, 0x28, 0x6B, + 0xFA, 0x5E, 0x40, 0x84, 0xE1, 0xED, 0x07, 0x2B, 0x45, 0x39, 0x03, 0xB9, 0x82, 0x0C, 0xC1, 0x22, + 0x59, 0x46, 0xBC, 0xAE, 0x49, 0x53, 0x56, 0x23, 0xC9, 0xD0, 0x28, 0x96, 0x0B, 0xA5, 0x71, 0x3E, + 0x5D, 0x2B, 0x4C, 0xE2, 0x2C, 0x55, 0x67, 0xBF, 0xB3, 0xC3, 0xE0, 0xB1, 0x39, 0x76, 0x86, 0x8B, + 0x05, 0x83, 0x47, 0x67, 0x87, 0x33, 0x7F, 0x6E, 0x0D, 0x1E, 0xFD, 0x2F, 0x5E, 0x72, 0x0B, 0x89, + 0x42, 0x10, 0x01, 0x00 +}; + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/camera_pins.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/camera_pins.h new file mode 100644 index 0000000..caa97be --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/camera_pins.h @@ -0,0 +1,317 @@ + +#if defined(CAMERA_MODEL_WROVER_KIT) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 21 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 19 +#define Y4_GPIO_NUM 18 +#define Y3_GPIO_NUM 5 +#define Y2_GPIO_NUM 4 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_ESP_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 37 +#define Y7_GPIO_NUM 38 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 35 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 13 +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#define LED_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_M5STACK_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_WIDE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#define LED_GPIO_NUM 2 + +#elif defined(CAMERA_MODEL_M5STACK_ESP32CAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 17 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_UNITCAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_AI_THINKER) +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 0 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 21 +#define Y4_GPIO_NUM 19 +#define Y3_GPIO_NUM 18 +#define Y2_GPIO_NUM 5 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +// 4 for flash led or 33 for normal led +#define LED_GPIO_NUM 4 + +#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) +#define PWDN_GPIO_NUM 0 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 17 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_XIAO_ESP32S3) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 10 +#define SIOD_GPIO_NUM 40 +#define SIOC_GPIO_NUM 39 + +#define Y9_GPIO_NUM 48 +#define Y8_GPIO_NUM 11 +#define Y7_GPIO_NUM 12 +#define Y6_GPIO_NUM 14 +#define Y5_GPIO_NUM 16 +#define Y4_GPIO_NUM 18 +#define Y3_GPIO_NUM 17 +#define Y2_GPIO_NUM 15 +#define VSYNC_GPIO_NUM 38 +#define HREF_GPIO_NUM 47 +#define PCLK_GPIO_NUM 13 + +#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD) +// The 18 pin header on the board has Y5 and Y3 swapped +#define USE_BOARD_HEADER 0 +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM 33 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 19 +#define Y7_GPIO_NUM 21 +#define Y6_GPIO_NUM 39 +#if USE_BOARD_HEADER +#define Y5_GPIO_NUM 13 +#else +#define Y5_GPIO_NUM 35 +#endif +#define Y4_GPIO_NUM 14 +#if USE_BOARD_HEADER +#define Y3_GPIO_NUM 35 +#else +#define Y3_GPIO_NUM 13 +#endif +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 40 +#define SIOD_GPIO_NUM 17 +#define SIOC_GPIO_NUM 18 + +#define Y9_GPIO_NUM 39 +#define Y8_GPIO_NUM 41 +#define Y7_GPIO_NUM 42 +#define Y6_GPIO_NUM 12 +#define Y5_GPIO_NUM 3 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 47 +#define Y2_GPIO_NUM 13 +#define VSYNC_GPIO_NUM 21 +#define HREF_GPIO_NUM 38 +#define PCLK_GPIO_NUM 11 + +#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD) +// The 18 pin header on the board has Y5 and Y3 swapped +#define USE_BOARD_HEADER 0 +#define PWDN_GPIO_NUM 1 +#define RESET_GPIO_NUM 2 +#define XCLK_GPIO_NUM 42 +#define SIOD_GPIO_NUM 41 +#define SIOC_GPIO_NUM 18 + +#define Y9_GPIO_NUM 16 +#define Y8_GPIO_NUM 39 +#define Y7_GPIO_NUM 40 +#define Y6_GPIO_NUM 15 +#if USE_BOARD_HEADER +#define Y5_GPIO_NUM 12 +#else +#define Y5_GPIO_NUM 13 +#endif +#define Y4_GPIO_NUM 5 +#if USE_BOARD_HEADER +#define Y3_GPIO_NUM 13 +#else +#define Y3_GPIO_NUM 12 +#endif +#define Y2_GPIO_NUM 14 +#define VSYNC_GPIO_NUM 38 +#define HREF_GPIO_NUM 4 +#define PCLK_GPIO_NUM 3 + +#elif defined(CAMERA_MODEL_ESP32S3_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 15 +#define SIOD_GPIO_NUM 4 +#define SIOC_GPIO_NUM 5 + +#define Y2_GPIO_NUM 11 +#define Y3_GPIO_NUM 9 +#define Y4_GPIO_NUM 8 +#define Y5_GPIO_NUM 10 +#define Y6_GPIO_NUM 12 +#define Y7_GPIO_NUM 18 +#define Y8_GPIO_NUM 17 +#define Y9_GPIO_NUM 16 + +#define VSYNC_GPIO_NUM 6 +#define HREF_GPIO_NUM 7 +#define PCLK_GPIO_NUM 13 + +#elif defined(CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3) || defined(CAMERA_MODEL_DFRobot_Romeo_ESP32S3) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 45 +#define SIOD_GPIO_NUM 1 +#define SIOC_GPIO_NUM 2 + +#define Y9_GPIO_NUM 48 +#define Y8_GPIO_NUM 46 +#define Y7_GPIO_NUM 8 +#define Y6_GPIO_NUM 7 +#define Y5_GPIO_NUM 4 +#define Y4_GPIO_NUM 41 +#define Y3_GPIO_NUM 40 +#define Y2_GPIO_NUM 39 +#define VSYNC_GPIO_NUM 6 +#define HREF_GPIO_NUM 42 +#define PCLK_GPIO_NUM 5 + +#else +#error "Camera model not selected" +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv new file mode 100644 index 0000000..4f76ca6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Camera/CameraWebServer/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x3d0000, +fr, data, , 0x3e0000, 0x20000, diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ChipID/GetChipID/GetChipID.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ChipID/GetChipID/GetChipID.ino new file mode 100644 index 0000000..d6288c8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ChipID/GetChipID/GetChipID.ino @@ -0,0 +1,30 @@ +/* The true ESP32 chip ID is essentially its MAC address. +This sketch provides an alternate chip ID that matches +the output of the ESP.getChipId() function on ESP8266 +(i.e. a 32-bit integer matching the last 3 bytes of +the MAC address. This is less unique than the +MAC address chip ID, but is helpful when you need +an identifier that can be no more than a 32-bit integer +(like for switch...case). + +created 2020-06-07 by cweinhofer +with help from Cicicok */ + +uint32_t chipId = 0; + +void setup() { + Serial.begin(115200); +} + +void loop() { + for(int i=0; i<17; i=i+8) { + chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; + } + + Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision()); + Serial.printf("This chip has %d cores\n", ESP.getChipCores()); + Serial.print("Chip ID: "); Serial.println(chipId); + + delay(3000); + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ExternalWakeUp.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ExternalWakeUp.ino new file mode 100644 index 0000000..8a13b77 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/ExternalWakeUp/ExternalWakeUp.ino @@ -0,0 +1,82 @@ +/* +Deep Sleep with External Wake Up +===================================== +This code displays how to use deep sleep with +an external trigger as a wake up source and how +to store data in RTC memory to use it over reboots + +This code is under Public Domain License. + +Hardware Connections +====================== +Push Button to GPIO 33 pulled down with a 10K Ohm +resistor + +NOTE: +====== +Only RTC IO can be used as a source for external wake +source. They are pins: 0,2,4,12-15,25-27,32-39. + +Author: +Pranav Cherukupalli +*/ + +#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex + +RTC_DATA_ATTR int bootCount = 0; + +/* +Method to print the reason by which ESP32 +has been awaken from sleep +*/ +void print_wakeup_reason(){ + esp_sleep_wakeup_cause_t wakeup_reason; + + wakeup_reason = esp_sleep_get_wakeup_cause(); + + switch(wakeup_reason) + { + case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; + case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; + case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; + case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; + case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; + default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; + } +} + +void setup(){ + Serial.begin(115200); + delay(1000); //Take some time to open up the Serial Monitor + + //Increment boot number and print it every reboot + ++bootCount; + Serial.println("Boot number: " + String(bootCount)); + + //Print the wakeup reason for ESP32 + print_wakeup_reason(); + + /* + First we configure the wake up source + We set our ESP32 to wake up for an external trigger. + There are two types for ESP32, ext0 and ext1 . + ext0 uses RTC_IO to wakeup thus requires RTC peripherals + to be on while ext1 uses RTC Controller so doesnt need + peripherals to be powered on. + Note that using internal pullups/pulldowns also requires + RTC peripherals to be turned on. + */ + esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low + + //If you were to use ext1, you would use it like + //esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ANY_HIGH); + + //Go to sleep now + Serial.println("Going to sleep now"); + esp_deep_sleep_start(); + Serial.println("This will never be printed"); +} + +void loop(){ + //This is not going to be called +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino new file mode 100644 index 0000000..28f9ffb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino @@ -0,0 +1,166 @@ +/* + This example smothly blinks GPIO_2 using different frequencies changed after Deep Sleep Time + The PWM and control of blink frequency is done by ULP exclusively + This is an example about how to program the ULP using Arduino + It also demonstrates use of RTM MEMORY to persist data and states +*/ + +#include +#include "esp32/ulp.h" +#include "driver/rtc_io.h" +#include "soc/rtc_io_reg.h" + +// RTC Memory used for ULP internal variable and Sketch interfacing +#define RTC_dutyMeter 0 +#define RTC_dir 4 +#define RTC_fadeDelay 12 +// *fadeCycleDelay is used to pass values to ULP and change its behaviour +uint32_t *fadeCycleDelay = &RTC_SLOW_MEM[RTC_fadeDelay]; +#define ULP_START_OFFSET 32 + +// For ESP32 Arduino, it is usually at offeset 512, defined in sdkconfig +RTC_DATA_ATTR uint32_t ULP_Started = 0; // 0 or 1 + +//Time-to-Sleep +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in microseconds); multiplied by above conversion to achieve seconds*/ + + +void ulp_setup() { + if (ULP_Started) { + return; + } + *fadeCycleDelay = 5; // 5..200 works fine for a full Fade In + Out cycle + ULP_Started = 1; + + // GPIO2 initialization (set to output and initial value is 0) + const gpio_num_t MeterPWMPin = GPIO_NUM_2; + rtc_gpio_init(MeterPWMPin); + rtc_gpio_set_direction(MeterPWMPin, RTC_GPIO_MODE_OUTPUT_ONLY); + rtc_gpio_set_level(MeterPWMPin, 0); + + // if LED is connected to GPIO2 (specify by +RTC_GPIO_OUT_DATA_S : ESP32 is 14, S2/S3 is 10) + const uint32_t MeterPWMBit = rtc_io_number_get(MeterPWMPin) + RTC_GPIO_OUT_DATA_S; + + enum labels { + INIFINITE_LOOP, + RUN_PWM, + NEXT_PWM_CYCLE, + PWM_ON, + PWM_OFF, + END_PWM_CYCLE, + POSITIVE_DIR, + DEC_DUTY, + INC_DUTY, + }; + + // Define ULP program + const ulp_insn_t ulp_prog[] = { + // Initial Value setup + I_MOVI(R0, 0), // R0 = 0 + I_ST(R0, R0, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] = 0 + I_MOVI(R1, 1), // R1 = 1 + I_ST(R1, R0, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 1 + + M_LABEL(INIFINITE_LOOP), // while(1) { + + // run certain PWM Duty for about (RTC_fadeDelay x 100) microseconds + I_MOVI(R3, 0), // R3 = 0 + I_LD(R3, R3, RTC_fadeDelay), // R3 = RTC_SLOW_MEM[RTC_fadeDelay] + M_LABEL(RUN_PWM), // do { // repeat RTC_fadeDelay times: + + // execute about 10KHz PWM on GPIO2 using as duty cycle = RTC_SLOW_MEM[RTC_dutyMeter] + I_MOVI(R0, 0), // R0 = 0 + I_LD(R0, R0, RTC_dutyMeter), // R0 = RTC_SLOW_MEM[RTC_dutyMeter] + M_BL(NEXT_PWM_CYCLE, 1), // if (R0 > 0) turn on LED + I_WR_REG(RTC_GPIO_OUT_W1TS_REG, MeterPWMBit, MeterPWMBit, 1), // W1TS set bit to clear GPIO - GPIO2 on + M_LABEL(PWM_ON), // while (R0 > 0) // repeat RTC_dutyMeter times: + M_BL(NEXT_PWM_CYCLE, 1), // { + //I_DELAY(8), // // 8 is about 1 microsecond based on 8MHz + I_SUBI(R0, R0, 1), // R0 = R0 - 1 + M_BX(PWM_ON), // } + M_LABEL(NEXT_PWM_CYCLE), // // toggle GPIO_2 + I_MOVI(R0, 0), // R0 = 0 + I_LD(R0, R0, RTC_dutyMeter), // R0 = RTC_SLOW_MEM[RTC_dutyMeter] + I_MOVI(R1, 100), // R1 = 100 + I_SUBR(R0, R1, R0), // R0 = 100 - dutyMeter + M_BL(END_PWM_CYCLE, 1), // if (R0 > 0) turn off LED + I_WR_REG(RTC_GPIO_OUT_W1TC_REG, MeterPWMBit, MeterPWMBit, 1), // W1TC set bit to clear GPIO - GPIO2 off + M_LABEL(PWM_OFF), // while (R0 > 0) // repeat (100 - RTC_dutyMeter) times: + M_BL(END_PWM_CYCLE, 1), // { + //I_DELAY(8), // // 8 is about 1us: ULP fetch+execution time + I_SUBI(R0, R0, 1), // R0 = R0 - 1 + M_BX(PWM_OFF), // } + M_LABEL(END_PWM_CYCLE), // + + I_SUBI(R3, R3, 1), // R3 = R3 - 1 // RTC_fadeDelay + I_MOVR(R0, R3), // R0 = R3 // only R0 can be used to compare and branch + M_BGE(RUN_PWM, 1), // } while (R3 > 0) // ESP32 repeatinf RTC_fadeDelay times + + // increase/decrease DutyMeter to apply Fade In/Out loop + I_MOVI(R1, 0), // R1 = 0 + I_LD(R1, R1, RTC_dutyMeter), // R1 = RTC_SLOW_MEM[RTC_dutyMeter] + I_MOVI(R0, 0), // R0 = 0 + I_LD(R0, R0, RTC_dir), // R0 = RTC_SLOW_MEM[RTC_dir] + + M_BGE(POSITIVE_DIR, 1), // if(dir == 0) { // decrease duty by 2 + // Dir is 0, means decrease Duty by 2 + I_MOVR(R0, R1), // R0 = Duty + M_BGE(DEC_DUTY, 1), // if (duty == 0) { // change direction and increase duty + I_MOVI(R3, 0), // R3 = 0 + I_MOVI(R2, 1), // R2 = 1 + I_ST(R2, R3, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 1 // increasing direction + M_BX(INC_DUTY), // goto "increase Duty" + M_LABEL(DEC_DUTY), // } "decrease Duty": + I_SUBI(R0, R0, 2), // Duty -= 2 + I_MOVI(R2, 0), // R2 = 0 + I_ST(R0, R2, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] += 2 + M_BX(INIFINITE_LOOP), // } + + M_LABEL(POSITIVE_DIR), // else { // dir == 1 // increase duty by 2 + // Dir is 1, means increase Duty by 2 + I_MOVR(R0, R1), // R0 = Duty + M_BL(INC_DUTY, 100), // if (duty == 100) { // change direction and decrease duty + I_MOVI(R2, 0), // R2 = 0 + I_ST(R2, R2, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 0 // decreasing direction + M_BX(DEC_DUTY), // goto "decrease Duty" + M_LABEL(INC_DUTY), // } "increase Duty": + I_ADDI(R0, R0, 2), // Duty += 2 + I_MOVI(R2, 0), // R2 = 0 + I_ST(R0, R2, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] -= 2 + // } // if (dir == 0) + M_BX(INIFINITE_LOOP), // } // while(1) + }; + // Run ULP program + size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); + ulp_process_macros_and_load(ULP_START_OFFSET, ulp_prog, &size); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + ulp_run(ULP_START_OFFSET); +} + + +void setup() { + Serial.begin(115200); + while (!Serial) {} // wait for Serial to start + + ulp_setup(); // it really only runs on the first ESP32 boot + Serial.printf("\nStarted smooth blink with delay %ld\n", *fadeCycleDelay); + + // *fadeCycleDelay resides in RTC_SLOW_MEM and persists along deep sleep waking up + // it is used as a delay time parameter for smooth blinking, in the ULP processing code + if (*fadeCycleDelay < 195) { + *fadeCycleDelay += 10; + } else { + *fadeCycleDelay = 5; // 5..200 works fine for a full Fade In + Out cycle + } + Serial.println("Entering in Deep Sleep"); + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR /*/ 4*/); // time set with variable above + esp_deep_sleep_start(); + // From this point on, no code is executed in DEEP SLEEP mode +} + + +void loop() { + // It never reaches this code because it enters in Deep Sleep mode at the end of setup() +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TimerWakeUp/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TimerWakeUp/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TimerWakeUp/TimerWakeUp.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TimerWakeUp/TimerWakeUp.ino new file mode 100644 index 0000000..ec43cf7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TimerWakeUp/TimerWakeUp.ino @@ -0,0 +1,94 @@ +/* +Simple Deep Sleep with Timer Wake Up +===================================== +ESP32 offers a deep sleep mode for effective power +saving as power is an important factor for IoT +applications. In this mode CPUs, most of the RAM, +and all the digital peripherals which are clocked +from APB_CLK are powered off. The only parts of +the chip which can still be powered on are: +RTC controller, RTC peripherals ,and RTC memories + +This code displays the most basic deep sleep with +a timer to wake it up and how to store data in +RTC memory to use it over reboots + +This code is under Public Domain License. + +Author: +Pranav Cherukupalli +*/ + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */ + +RTC_DATA_ATTR int bootCount = 0; + +/* +Method to print the reason by which ESP32 +has been awaken from sleep +*/ +void print_wakeup_reason(){ + esp_sleep_wakeup_cause_t wakeup_reason; + + wakeup_reason = esp_sleep_get_wakeup_cause(); + + switch(wakeup_reason) + { + case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; + case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; + case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; + case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; + case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; + default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; + } +} + +void setup(){ + Serial.begin(115200); + delay(1000); //Take some time to open up the Serial Monitor + + //Increment boot number and print it every reboot + ++bootCount; + Serial.println("Boot number: " + String(bootCount)); + + //Print the wakeup reason for ESP32 + print_wakeup_reason(); + + /* + First we configure the wake up source + We set our ESP32 to wake up every 5 seconds + */ + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); + Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + + " Seconds"); + + /* + Next we decide what all peripherals to shut down/keep on + By default, ESP32 will automatically power down the peripherals + not needed by the wakeup source, but if you want to be a poweruser + this is for you. Read in detail at the API docs + http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html + Left the line commented as an example of how to configure peripherals. + The line below turns off all RTC peripherals in deep sleep. + */ + //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); + //Serial.println("Configured all RTC Peripherals to be powered down in sleep"); + + /* + Now that we have setup a wake cause and if needed setup the + peripherals state in deep sleep, we can now start going to + deep sleep. + In the case that no wake up sources were provided but deep + sleep was started, it will sleep forever unless hardware + reset occurs. + */ + Serial.println("Going to sleep now"); + Serial.flush(); + esp_deep_sleep_start(); + Serial.println("This will never be printed"); +} + +void loop(){ + //This is not going to be called +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino new file mode 100644 index 0000000..94f2dc7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/DeepSleep/TouchWakeUp/TouchWakeUp.ino @@ -0,0 +1,110 @@ +/* +Deep Sleep with Touch Wake Up +===================================== +This code displays how to use deep sleep with +a touch as a wake up source and how to store data in +RTC memory to use it over reboots + +ESP32 can have multiple touch pads enabled as wakeup source +ESP32-S2 and ESP32-S3 supports only 1 touch pad as wakeup source enabled + +This code is under Public Domain License. + +Author: +Pranav Cherukupalli +*/ + +#if CONFIG_IDF_TARGET_ESP32 + #define THRESHOLD 40 /* Greater the value, more the sensitivity */ +#else //ESP32-S2 and ESP32-S3 + default for other chips (to be adjusted) */ + #define THRESHOLD 5000 /* Lower the value, more the sensitivity */ +#endif + +RTC_DATA_ATTR int bootCount = 0; +touch_pad_t touchPin; +/* +Method to print the reason by which ESP32 +has been awaken from sleep +*/ +void print_wakeup_reason(){ + esp_sleep_wakeup_cause_t wakeup_reason; + + wakeup_reason = esp_sleep_get_wakeup_cause(); + + switch(wakeup_reason) + { + case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; + case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; + case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; + case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; + case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; + default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; + } +} + +/* +Method to print the touchpad by which ESP32 +has been awaken from sleep +*/ +void print_wakeup_touchpad(){ + touchPin = esp_sleep_get_touchpad_wakeup_status(); + + #if CONFIG_IDF_TARGET_ESP32 + switch(touchPin) + { + case 0 : Serial.println("Touch detected on GPIO 4"); break; + case 1 : Serial.println("Touch detected on GPIO 0"); break; + case 2 : Serial.println("Touch detected on GPIO 2"); break; + case 3 : Serial.println("Touch detected on GPIO 15"); break; + case 4 : Serial.println("Touch detected on GPIO 13"); break; + case 5 : Serial.println("Touch detected on GPIO 12"); break; + case 6 : Serial.println("Touch detected on GPIO 14"); break; + case 7 : Serial.println("Touch detected on GPIO 27"); break; + case 8 : Serial.println("Touch detected on GPIO 33"); break; + case 9 : Serial.println("Touch detected on GPIO 32"); break; + default : Serial.println("Wakeup not by touchpad"); break; + } + #else + if(touchPin < TOUCH_PAD_MAX) + { + Serial.printf("Touch detected on GPIO %d\n", touchPin); + } + else + { + Serial.println("Wakeup not by touchpad"); + } + #endif +} + +void setup(){ + Serial.begin(115200); + delay(1000); //Take some time to open up the Serial Monitor + + //Increment boot number and print it every reboot + ++bootCount; + Serial.println("Boot number: " + String(bootCount)); + + //Print the wakeup reason for ESP32 and touchpad too + print_wakeup_reason(); + print_wakeup_touchpad(); + + #if CONFIG_IDF_TARGET_ESP32 + //Setup sleep wakeup on Touch Pad 3 + 7 (GPIO15 + GPIO 27) + touchSleepWakeUpEnable(T3,THRESHOLD); + touchSleepWakeUpEnable(T7,THRESHOLD); + + #else //ESP32-S2 + ESP32-S3 + //Setup sleep wakeup on Touch Pad 3 (GPIO3) + touchSleepWakeUpEnable(T3,THRESHOLD); + + #endif + + //Go to sleep now + Serial.println("Going to sleep now"); + esp_deep_sleep_start(); + Serial.println("This will never be printed"); +} + +void loop(){ + //This will never be reached +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino new file mode 100644 index 0000000..b2e6b35 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Master/ESPNow_Basic_Master.ino @@ -0,0 +1,262 @@ +/** + ESPNOW - Basic communication - Master + Date: 26th September 2017 + Author: Arvind Ravulavaru + Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32 + Description: This sketch consists of the code for the Master module. + Resources: (A bit outdated) + a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf + b. http://www.esploradores.com/practica-6-conexion-esp-now/ + + << This Device Master >> + + Flow: Master + Step 1 : ESPNow Init on Master and set it in STA mode + Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) + Step 3 : Once found, add Slave as peer + Step 4 : Register for send callback + Step 5 : Start Transmitting data from Master to Slave + + Flow: Slave + Step 1 : ESPNow Init on Slave + Step 2 : Update the SSID of Slave with a prefix of `slave` + Step 3 : Set Slave in AP mode + Step 4 : Register for receive callback and wait for data + Step 5 : Once data arrives, print it in the serial monitor + + Note: Master and Slave have been defined to easily understand the setup. + Based on the ESPNOW API, there is no concept of Master and Slave. + Any devices can act as master or salve. +*/ + +#include +#include +#include // only for esp_wifi_set_channel() + +// Global copy of slave +esp_now_peer_info_t slave; +#define CHANNEL 1 +#define PRINTSCANRESULTS 0 +#define DELETEBEFOREPAIR 0 + +// Init ESP Now with fallback +void InitESPNow() { + WiFi.disconnect(); + if (esp_now_init() == ESP_OK) { + Serial.println("ESPNow Init Success"); + } + else { + Serial.println("ESPNow Init Failed"); + // Retry InitESPNow, add a counte and then restart? + // InitESPNow(); + // or Simply Restart + ESP.restart(); + } +} + +// Scan for slaves in AP mode +void ScanForSlave() { + int16_t scanResults = WiFi.scanNetworks(false, false, false, 300, CHANNEL); // Scan only on one channel + // reset on each scan + bool slaveFound = 0; + memset(&slave, 0, sizeof(slave)); + + Serial.println(""); + if (scanResults == 0) { + Serial.println("No WiFi devices in AP Mode found"); + } else { + Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices "); + for (int i = 0; i < scanResults; ++i) { + // Print SSID and RSSI for each device found + String SSID = WiFi.SSID(i); + int32_t RSSI = WiFi.RSSI(i); + String BSSIDstr = WiFi.BSSIDstr(i); + + if (PRINTSCANRESULTS) { + Serial.print(i + 1); + Serial.print(": "); + Serial.print(SSID); + Serial.print(" ("); + Serial.print(RSSI); + Serial.print(")"); + Serial.println(""); + } + delay(10); + // Check if the current device starts with `Slave` + if (SSID.indexOf("Slave") == 0) { + // SSID of interest + Serial.println("Found a Slave."); + Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println(""); + // Get BSSID => Mac Address of the Slave + int mac[6]; + if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) { + for (int ii = 0; ii < 6; ++ii ) { + slave.peer_addr[ii] = (uint8_t) mac[ii]; + } + } + + slave.channel = CHANNEL; // pick a channel + slave.encrypt = 0; // no encryption + + slaveFound = 1; + // we are planning to have only one slave in this example; + // Hence, break after we find one, to be a bit efficient + break; + } + } + } + + if (slaveFound) { + Serial.println("Slave Found, processing.."); + } else { + Serial.println("Slave Not Found, trying again."); + } + + // clean up ram + WiFi.scanDelete(); +} + +// Check if the slave is already paired with the master. +// If not, pair the slave with master +bool manageSlave() { + if (slave.channel == CHANNEL) { + if (DELETEBEFOREPAIR) { + deletePeer(); + } + + Serial.print("Slave Status: "); + // check if the peer exists + bool exists = esp_now_is_peer_exist(slave.peer_addr); + if ( exists) { + // Slave already paired. + Serial.println("Already Paired"); + return true; + } else { + // Slave not paired, attempt pair + esp_err_t addStatus = esp_now_add_peer(&slave); + if (addStatus == ESP_OK) { + // Pair success + Serial.println("Pair success"); + return true; + } else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) { + // How did we get so far!! + Serial.println("ESPNOW Not Init"); + return false; + } else if (addStatus == ESP_ERR_ESPNOW_ARG) { + Serial.println("Invalid Argument"); + return false; + } else if (addStatus == ESP_ERR_ESPNOW_FULL) { + Serial.println("Peer list full"); + return false; + } else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) { + Serial.println("Out of memory"); + return false; + } else if (addStatus == ESP_ERR_ESPNOW_EXIST) { + Serial.println("Peer Exists"); + return true; + } else { + Serial.println("Not sure what happened"); + return false; + } + } + } else { + // No slave found to process + Serial.println("No Slave found to process"); + return false; + } +} + +void deletePeer() { + esp_err_t delStatus = esp_now_del_peer(slave.peer_addr); + Serial.print("Slave Delete Status: "); + if (delStatus == ESP_OK) { + // Delete success + Serial.println("Success"); + } else if (delStatus == ESP_ERR_ESPNOW_NOT_INIT) { + // How did we get so far!! + Serial.println("ESPNOW Not Init"); + } else if (delStatus == ESP_ERR_ESPNOW_ARG) { + Serial.println("Invalid Argument"); + } else if (delStatus == ESP_ERR_ESPNOW_NOT_FOUND) { + Serial.println("Peer not found."); + } else { + Serial.println("Not sure what happened"); + } +} + +uint8_t data = 0; +// send data +void sendData() { + data++; + const uint8_t *peer_addr = slave.peer_addr; + Serial.print("Sending: "); Serial.println(data); + esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data)); + Serial.print("Send Status: "); + if (result == ESP_OK) { + Serial.println("Success"); + } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { + // How did we get so far!! + Serial.println("ESPNOW not Init."); + } else if (result == ESP_ERR_ESPNOW_ARG) { + Serial.println("Invalid Argument"); + } else if (result == ESP_ERR_ESPNOW_INTERNAL) { + Serial.println("Internal Error"); + } else if (result == ESP_ERR_ESPNOW_NO_MEM) { + Serial.println("ESP_ERR_ESPNOW_NO_MEM"); + } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { + Serial.println("Peer not found."); + } else { + Serial.println("Not sure what happened"); + } +} + +// callback when data is sent from Master to Slave +void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { + char macStr[18]; + snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + Serial.print("Last Packet Sent to: "); Serial.println(macStr); + Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); +} + +void setup() { + Serial.begin(115200); + //Set device in STA mode to begin with + WiFi.mode(WIFI_STA); + esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE); + Serial.println("ESPNow/Basic/Master Example"); + // This is the mac address of the Master in Station Mode + Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); + Serial.print("STA CHANNEL "); Serial.println(WiFi.channel()); + // Init ESPNow with a fallback logic + InitESPNow(); + // Once ESPNow is successfully Init, we will register for Send CB to + // get the status of Trasnmitted packet + esp_now_register_send_cb(OnDataSent); +} + +void loop() { + // In the loop we scan for slave + ScanForSlave(); + // If Slave is found, it would be populate in `slave` variable + // We will check if `slave` is defined and then we proceed further + if (slave.channel == CHANNEL) { // check if slave channel is defined + // `slave` is defined + // Add slave as peer if it has not been added already + bool isPaired = manageSlave(); + if (isPaired) { + // pair success or already paired + // Send data to device + sendData(); + } else { + // slave pair failed + Serial.println("Slave pair failed!"); + } + } + else { + // No slave found to process + } + + // wait for 3seconds to run the logic again + delay(3000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino new file mode 100644 index 0000000..50711b1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_Basic_Slave/ESPNow_Basic_Slave.ino @@ -0,0 +1,92 @@ +/** + ESPNOW - Basic communication - Slave + Date: 26th September 2017 + Author: Arvind Ravulavaru + Purpose: ESPNow Communication between a Master ESP32 and a Slave ESP32 + Description: This sketch consists of the code for the Slave module. + Resources: (A bit outdated) + a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf + b. http://www.esploradores.com/practica-6-conexion-esp-now/ + + << This Device Slave >> + + Flow: Master + Step 1 : ESPNow Init on Master and set it in STA mode + Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) + Step 3 : Once found, add Slave as peer + Step 4 : Register for send callback + Step 5 : Start Transmitting data from Master to Slave + + Flow: Slave + Step 1 : ESPNow Init on Slave + Step 2 : Update the SSID of Slave with a prefix of `slave` + Step 3 : Set Slave in AP mode + Step 4 : Register for receive callback and wait for data + Step 5 : Once data arrives, print it in the serial monitor + + Note: Master and Slave have been defined to easily understand the setup. + Based on the ESPNOW API, there is no concept of Master and Slave. + Any devices can act as master or salve. +*/ + +#include +#include + +#define CHANNEL 1 + +// Init ESP Now with fallback +void InitESPNow() { + WiFi.disconnect(); + if (esp_now_init() == ESP_OK) { + Serial.println("ESPNow Init Success"); + } + else { + Serial.println("ESPNow Init Failed"); + // Retry InitESPNow, add a counte and then restart? + // InitESPNow(); + // or Simply Restart + ESP.restart(); + } +} + +// config AP SSID +void configDeviceAP() { + const char *SSID = "Slave_1"; + bool result = WiFi.softAP(SSID, "Slave_1_Password", CHANNEL, 0); + if (!result) { + Serial.println("AP Config failed."); + } else { + Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID)); + Serial.print("AP CHANNEL "); Serial.println(WiFi.channel()); + } +} + +void setup() { + Serial.begin(115200); + Serial.println("ESPNow/Basic/Slave Example"); + //Set device in AP mode to begin with + WiFi.mode(WIFI_AP); + // configure device AP mode + configDeviceAP(); + // This is the mac address of the Slave in AP Mode + Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); + // Init ESPNow with a fallback logic + InitESPNow(); + // Once ESPNow is successfully Init, we will register for recv CB to + // get recv packer info. + esp_now_register_recv_cb(OnDataRecv); +} + +// callback when data is recv from Master +void OnDataRecv(const esp_now_recv_info_t * info, const uint8_t *data, int data_len) { + char macStr[18]; + snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", + info->src_addr[0], info->src_addr[1], info->src_addr[2], info->src_addr[3], info->src_addr[4], info->src_addr[5]); + Serial.print("Last Packet Recv from: "); Serial.println(macStr); + Serial.print("Last Packet Recv Data: "); Serial.println(*data); + Serial.println(""); +} + +void loop() { + // Chill +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino new file mode 100644 index 0000000..6e212dd --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Master/ESPNow_MultiSlave_Master.ino @@ -0,0 +1,244 @@ +/** + ESPNOW - Basic communication - Master + Date: 26th September 2017 + Author: Arvind Ravulavaru + Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves + Description: This sketch consists of the code for the Master module. + Resources: (A bit outdated) + a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf + b. http://www.esploradores.com/practica-6-conexion-esp-now/ + + << This Device Master >> + + Flow: Master + Step 1 : ESPNow Init on Master and set it in STA mode + Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) + Step 3 : Once found, add Slave as peer + Step 4 : Register for send callback + Step 5 : Start Transmitting data from Master to Slave(s) + + Flow: Slave + Step 1 : ESPNow Init on Slave + Step 2 : Update the SSID of Slave with a prefix of `slave` + Step 3 : Set Slave in AP mode + Step 4 : Register for receive callback and wait for data + Step 5 : Once data arrives, print it in the serial monitor + + Note: Master and Slave have been defined to easily understand the setup. + Based on the ESPNOW API, there is no concept of Master and Slave. + Any devices can act as master or salve. + + + // Sample Serial log with 1 master & 2 slaves + Found 12 devices + 1: Slave:24:0A:C4:81:CF:A4 [24:0A:C4:81:CF:A5] (-44) + 3: Slave:30:AE:A4:02:6D:CC [30:AE:A4:02:6D:CD] (-55) + 2 Slave(s) found, processing.. + Processing: 24:A:C4:81:CF:A5 Status: Already Paired + Processing: 30:AE:A4:2:6D:CD Status: Already Paired + Sending: 9 + Send Status: Success + Last Packet Sent to: 24:0a:c4:81:cf:a5 + Last Packet Send Status: Delivery Success + Send Status: Success + Last Packet Sent to: 30:ae:a4:02:6d:cd + Last Packet Send Status: Delivery Success + +*/ + +#include +#include + +// Global copy of slave +#define NUMSLAVES 20 +esp_now_peer_info_t slaves[NUMSLAVES] = {}; +int SlaveCnt = 0; + +#define CHANNEL 3 +#define PRINTSCANRESULTS 0 + +// Init ESP Now with fallback +void InitESPNow() { + WiFi.disconnect(); + if (esp_now_init() == ESP_OK) { + Serial.println("ESPNow Init Success"); + } + else { + Serial.println("ESPNow Init Failed"); + // Retry InitESPNow, add a counte and then restart? + // InitESPNow(); + // or Simply Restart + ESP.restart(); + } +} + +// Scan for slaves in AP mode +void ScanForSlave() { + int8_t scanResults = WiFi.scanNetworks(); + //reset slaves + memset(slaves, 0, sizeof(slaves)); + SlaveCnt = 0; + Serial.println(""); + if (scanResults == 0) { + Serial.println("No WiFi devices in AP Mode found"); + } else { + Serial.print("Found "); Serial.print(scanResults); Serial.println(" devices "); + for (int i = 0; i < scanResults; ++i) { + // Print SSID and RSSI for each device found + String SSID = WiFi.SSID(i); + int32_t RSSI = WiFi.RSSI(i); + String BSSIDstr = WiFi.BSSIDstr(i); + + if (PRINTSCANRESULTS) { + Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println(""); + } + delay(10); + // Check if the current device starts with `Slave` + if (SSID.indexOf("Slave") == 0) { + // SSID of interest + Serial.print(i + 1); Serial.print(": "); Serial.print(SSID); Serial.print(" ["); Serial.print(BSSIDstr); Serial.print("]"); Serial.print(" ("); Serial.print(RSSI); Serial.print(")"); Serial.println(""); + // Get BSSID => Mac Address of the Slave + int mac[6]; + + if ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5] ) ) { + for (int ii = 0; ii < 6; ++ii ) { + slaves[SlaveCnt].peer_addr[ii] = (uint8_t) mac[ii]; + } + } + slaves[SlaveCnt].channel = CHANNEL; // pick a channel + slaves[SlaveCnt].encrypt = 0; // no encryption + SlaveCnt++; + } + } + } + + if (SlaveCnt > 0) { + Serial.print(SlaveCnt); Serial.println(" Slave(s) found, processing.."); + } else { + Serial.println("No Slave Found, trying again."); + } + + // clean up ram + WiFi.scanDelete(); +} + +// Check if the slave is already paired with the master. +// If not, pair the slave with master +void manageSlave() { + if (SlaveCnt > 0) { + for (int i = 0; i < SlaveCnt; i++) { + Serial.print("Processing: "); + for (int ii = 0; ii < 6; ++ii ) { + Serial.print((uint8_t) slaves[i].peer_addr[ii], HEX); + if (ii != 5) Serial.print(":"); + } + Serial.print(" Status: "); + // check if the peer exists + bool exists = esp_now_is_peer_exist(slaves[i].peer_addr); + if (exists) { + // Slave already paired. + Serial.println("Already Paired"); + } else { + // Slave not paired, attempt pair + esp_err_t addStatus = esp_now_add_peer(&slaves[i]); + if (addStatus == ESP_OK) { + // Pair success + Serial.println("Pair success"); + } else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) { + // How did we get so far!! + Serial.println("ESPNOW Not Init"); + } else if (addStatus == ESP_ERR_ESPNOW_ARG) { + Serial.println("Add Peer - Invalid Argument"); + } else if (addStatus == ESP_ERR_ESPNOW_FULL) { + Serial.println("Peer list full"); + } else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) { + Serial.println("Out of memory"); + } else if (addStatus == ESP_ERR_ESPNOW_EXIST) { + Serial.println("Peer Exists"); + } else { + Serial.println("Not sure what happened"); + } + delay(100); + } + } + } else { + // No slave found to process + Serial.println("No Slave found to process"); + } +} + + +uint8_t data = 0; +// send data +void sendData() { + data++; + for (int i = 0; i < SlaveCnt; i++) { + const uint8_t *peer_addr = slaves[i].peer_addr; + if (i == 0) { // print only for first slave + Serial.print("Sending: "); + Serial.println(data); + } + esp_err_t result = esp_now_send(peer_addr, &data, sizeof(data)); + Serial.print("Send Status: "); + if (result == ESP_OK) { + Serial.println("Success"); + } else if (result == ESP_ERR_ESPNOW_NOT_INIT) { + // How did we get so far!! + Serial.println("ESPNOW not Init."); + } else if (result == ESP_ERR_ESPNOW_ARG) { + Serial.println("Invalid Argument"); + } else if (result == ESP_ERR_ESPNOW_INTERNAL) { + Serial.println("Internal Error"); + } else if (result == ESP_ERR_ESPNOW_NO_MEM) { + Serial.println("ESP_ERR_ESPNOW_NO_MEM"); + } else if (result == ESP_ERR_ESPNOW_NOT_FOUND) { + Serial.println("Peer not found."); + } else { + Serial.println("Not sure what happened"); + } + delay(100); + } +} + +// callback when data is sent from Master to Slave +void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { + char macStr[18]; + snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + Serial.print("Last Packet Sent to: "); Serial.println(macStr); + Serial.print("Last Packet Send Status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); +} + +void setup() { + Serial.begin(115200); + //Set device in STA mode to begin with + WiFi.mode(WIFI_STA); + Serial.println("ESPNow/Multi-Slave/Master Example"); + // This is the mac address of the Master in Station Mode + Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); + // Init ESPNow with a fallback logic + InitESPNow(); + // Once ESPNow is successfully Init, we will register for Send CB to + // get the status of Trasnmitted packet + esp_now_register_send_cb(OnDataSent); +} + +void loop() { + // In the loop we scan for slave + ScanForSlave(); + // If Slave is found, it would be populate in `slave` variable + // We will check if `slave` is defined and then we proceed further + if (SlaveCnt > 0) { // check if slave channel is defined + // `slave` is defined + // Add slave as peer if it has not been added already + manageSlave(); + // pair success or already paired + // Send data to device + sendData(); + } else { + // No slave found to process + } + + // wait for 3seconds to run the logic again + delay(1000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino new file mode 100644 index 0000000..ad3b940 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ESPNow/ESPNow_MultiSlave_Slave/ESPNow_MultiSlave_Slave.ino @@ -0,0 +1,94 @@ +/** + ESPNOW - Basic communication - Slave + Date: 26th September 2017 + Author: Arvind Ravulavaru + Purpose: ESPNow Communication between a Master ESP32 and multiple ESP32 Slaves + Description: This sketch consists of the code for the Slave module. + Resources: (A bit outdated) + a. https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf + b. http://www.esploradores.com/practica-6-conexion-esp-now/ + + << This Device Slave >> + + Flow: Master + Step 1 : ESPNow Init on Master and set it in STA mode + Step 2 : Start scanning for Slave ESP32 (we have added a prefix of `slave` to the SSID of slave for an easy setup) + Step 3 : Once found, add Slave as peer + Step 4 : Register for send callback + Step 5 : Start Transmitting data from Master to Slave(s) + + Flow: Slave + Step 1 : ESPNow Init on Slave + Step 2 : Update the SSID of Slave with a prefix of `slave` + Step 3 : Set Slave in AP mode + Step 4 : Register for receive callback and wait for data + Step 5 : Once data arrives, print it in the serial monitor + + Note: Master and Slave have been defined to easily understand the setup. + Based on the ESPNOW API, there is no concept of Master and Slave. + Any devices can act as master or salve. +*/ + +#include +#include + +#define CHANNEL 1 + +// Init ESP Now with fallback +void InitESPNow() { + WiFi.disconnect(); + if (esp_now_init() == ESP_OK) { + Serial.println("ESPNow Init Success"); + } + else { + Serial.println("ESPNow Init Failed"); + // Retry InitESPNow, add a counte and then restart? + // InitESPNow(); + // or Simply Restart + ESP.restart(); + } +} + +// config AP SSID +void configDeviceAP() { + String Prefix = "Slave:"; + String Mac = WiFi.macAddress(); + String SSID = Prefix + Mac; + String Password = "123456789"; + bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0); + if (!result) { + Serial.println("AP Config failed."); + } else { + Serial.println("AP Config Success. Broadcasting with AP: " + String(SSID)); + } +} + +void setup() { + Serial.begin(115200); + Serial.println("ESPNow/Basic/Slave Example"); + //Set device in AP mode to begin with + WiFi.mode(WIFI_AP); + // configure device AP mode + configDeviceAP(); + // This is the mac address of the Slave in AP Mode + Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); + // Init ESPNow with a fallback logic + InitESPNow(); + // Once ESPNow is successfully Init, we will register for recv CB to + // get recv packer info. + esp_now_register_recv_cb(OnDataRecv); +} + +// callback when data is recv from Master +void OnDataRecv(const esp_now_recv_info_t * info, const uint8_t *data, int data_len) { + char macStr[18]; + snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", + info->src_addr[0], info->src_addr[1], info->src_addr[2], info->src_addr[3], info->src_addr[4], info->src_addr[5]); + Serial.print("Last Packet Recv from: "); Serial.println(macStr); + Serial.print("Last Packet Recv Data: "); Serial.println(*data); + Serial.println(""); +} + +void loop() { + // Chill +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/BasicMultiThreading.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/BasicMultiThreading.ino new file mode 100644 index 0000000..2cfe185 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/BasicMultiThreading.ino @@ -0,0 +1,117 @@ +/* Basic Multi Threading Arduino Example + This example code is in the Public Domain (or CC0 licensed, at your option.) + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +// Please read file README.md in the folder containing this example. + +#if CONFIG_FREERTOS_UNICORE +#define ARDUINO_RUNNING_CORE 0 +#else +#define ARDUINO_RUNNING_CORE 1 +#endif + +#define ANALOG_INPUT_PIN A0 + +#ifndef LED_BUILTIN + #define LED_BUILTIN 13 // Specify the on which is your LED +#endif + +// Define two tasks for Blink & AnalogRead. +void TaskBlink( void *pvParameters ); +void TaskAnalogRead( void *pvParameters ); +TaskHandle_t analog_read_task_handle; // You can (don't have to) use this to be able to manipulate a task from somewhere else. + +// The setup function runs once when you press reset or power on the board. +void setup() { + // Initialize serial communication at 115200 bits per second: + Serial.begin(115200); + // Set up two tasks to run independently. + uint32_t blink_delay = 1000; // Delay between changing state on LED pin + xTaskCreate( + TaskBlink + , "Task Blink" // A name just for humans + , 2048 // The stack size can be checked by calling `uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);` + , (void*) &blink_delay // Task parameter which can modify the task behavior. This must be passed as pointer to void. + , 2 // Priority + , NULL // Task handle is not used here - simply pass NULL + ); + + // This variant of task creation can also specify on which core it will be run (only relevant for multi-core ESPs) + xTaskCreatePinnedToCore( + TaskAnalogRead + , "Analog Read" + , 2048 // Stack size + , NULL // When no parameter is used, simply pass NULL + , 1 // Priority + , &analog_read_task_handle // With task handle we will be able to manipulate with this task. + , ARDUINO_RUNNING_CORE // Core on which the task will run + ); + + Serial.printf("Basic Multi Threading Arduino Example\n"); + // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started. +} + +void loop(){ + if(analog_read_task_handle != NULL){ // Make sure that the task actually exists + delay(10000); + vTaskDelete(analog_read_task_handle); // Delete task + analog_read_task_handle = NULL; // prevent calling vTaskDelete on non-existing task + } +} + +/*--------------------------------------------------*/ +/*---------------------- Tasks ---------------------*/ +/*--------------------------------------------------*/ + +void TaskBlink(void *pvParameters){ // This is a task. + uint32_t blink_delay = *((uint32_t*)pvParameters); + +/* + Blink + Turns on an LED on for one second, then off for one second, repeatedly. + + If you want to know what pin the on-board LED is connected to on your ESP32 model, check + the Technical Specs of your board. +*/ + + // initialize digital LED_BUILTIN on pin 13 as an output. + pinMode(LED_BUILTIN, OUTPUT); + + for (;;){ // A Task shall never return or exit. + digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) + // arduino-esp32 has FreeRTOS configured to have a tick-rate of 1000Hz and portTICK_PERIOD_MS + // refers to how many milliseconds the period between each ticks is, ie. 1ms. + delay(blink_delay); + digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW + delay(blink_delay); + } +} + +void TaskAnalogRead(void *pvParameters){ // This is a task. + (void) pvParameters; + // Check if the given analog pin is usable - if not - delete this task + if(digitalPinToAnalogChannel(ANALOG_INPUT_PIN) == -1){ + Serial.printf("TaskAnalogRead cannot work because the given pin %d cannot be used for ADC - the task will delete itself.\n", ANALOG_INPUT_PIN); + analog_read_task_handle = NULL; // Prevent calling vTaskDelete on non-existing task + vTaskDelete(NULL); // Delete this task + } + +/* + AnalogReadSerial + Reads an analog input on pin A3, prints the result to the serial monitor. + Graphical representation is available using serial plotter (Tools > Serial Plotter menu) + Attach the center pin of a potentiometer to pin A3, and the outside pins to +5V and ground. + + This example code is in the public domain. +*/ + + for (;;){ + // read the input on analog pin: + int sensorValue = analogRead(ANALOG_INPUT_PIN); + // print out the value you read: + Serial.println(sensorValue); + delay(100); // 100ms delay + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md new file mode 100644 index 0000000..c7112e8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/BasicMultiThreading/README.md @@ -0,0 +1,89 @@ +# Basic Multi Threading Example + +This example demonstrates the basic usage of FreeRTOS Tasks for multi threading. + +Please refer to other examples in this folder to better utilize their full potential and safeguard potential problems. +It is also advised to read the documentation on FreeRTOS web pages: +[https://www.freertos.org/a00106.html](https://www.freertos.org/a00106.html) + +This example will blink the built-in LED and read analog data. +Additionally, this example demonstrates the usage of the task handle, simply by deleting the analog +read task after 10 seconds from the main loop by calling the function `vTaskDelete`. + +### Theory: +A task is simply a function that runs when the operating system (FreeeRTOS) sees fit. +This task can have an infinite loop inside if you want to do some work periodically for the entirety of the program run. +This, however, can create a problem - no other task will ever run and also the Watch Dog will trigger and your program will restart. +A nice behaving tasks know when it is useless to keep the processor for itself and give it away for other tasks to be used. +This can be achieved in many ways, but the simplest is called `delay(`milliseconds)`. +During that delay, any other task may run and do its job. +When the delay runs out the Operating System gives the processor the task which can continue. +For other ways to yield the CPU in a task please see other examples in this folder. +It is also worth mentioning that two or more tasks running the same function will run them with separate stacks, so if you want to run the same code (which could be differentiated by the argument) there is no need to have multiple copies of the same function. + +**Task creation has a few parameters you should understand:** +``` + xTaskCreate(TaskFunction_t pxTaskCode, + const char * const pcName, + const uint16_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) +``` + - **pxTaskCode** is the name of your function which will run as a task + - **pcName** is a string of human-readable descriptions for your task + - **usStackDepth** is the number of words (word = 4B) available to the task. If you see an error similar to this "Debug exception reason: Stack canary watchpoint triggered (Task Blink)" you should increase it + - **pvParameters** is a parameter that will be passed to the task function - it must be explicitly converted to (void*) and in your function explicitly converted back to the intended data type. + - **uxPriority** is a number from 0 to configMAX_PRIORITIES which determines how the FreeRTOS will allow the tasks to run. 0 is the lowest priority. + - **pxCreatedTask** task handle is a pointer to the task which allows you to manipulate the task - delete it, suspend and resume. + If you don't need to do anything special with your task, simply pass NULL for this parameter. + You can read more about task control here: https://www.freertos.org/a00112.html + +# Supported Targets + +This example supports all SoCs. + +### Hardware Connection + +If your board does not have a built-in LED, please connect one to the pin specified by the `LED_BUILTIN` in the code (you can also change the number and connect it to the pin you desire). + +Optionally you can connect the analog element to the pin. such as a variable resistor, analog input such as an audio signal, or any signal generator. However, if the pin is left unconnected it will receive background noise and you will also see a change in the signal when the pin is touched by a finger. +Please refer to the ESP-IDF ADC documentation for specific SoC for info on which pins are available: +[ESP32](https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32/api-reference/peripherals/adc.html), + [ESP32-S2](https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32s2/api-reference/peripherals/adc.html), + [ESP32-S3](https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32s3/api-reference/peripherals/adc.html), + [ESP32-C3](https://docs.espressif.com/projects/esp-idf/en/v4.4/esp32c3/api-reference/peripherals/adc.html) + + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. + +#### Using Platform IO + +* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file. + +## Troubleshooting + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) +* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) +* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) +* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Mutex/Mutex.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Mutex/Mutex.ino new file mode 100644 index 0000000..157c574 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Mutex/Mutex.ino @@ -0,0 +1,97 @@ +/* Basic Multi Threading Arduino Example + This example code is in the Public Domain (or CC0 licensed, at your option.) + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +// Please read file README.md in the folder containing this example. + +#define USE_MUTEX +int shared_variable = 0; +SemaphoreHandle_t shared_var_mutex = NULL; + +// Define a task function +void Task( void *pvParameters ); + +// The setup function runs once when you press reset or power on the board. +void setup() { + // Initialize serial communication at 115200 bits per second: + Serial.begin(115200); + while(!Serial) delay(100); + Serial.printf(" Task 0 | Task 1\n"); + +#ifdef USE_MUTEX + shared_var_mutex = xSemaphoreCreateMutex(); // Create the mutex +#endif + + // Set up two tasks to run the same function independently. + static int task_number0 = 0; + xTaskCreate( + Task + , "Task 0" // A name just for humans + , 2048 // The stack size + , (void*)&task_number0 // Pass reference to a variable describing the task number + //, 5 // High priority + , 1 // priority + , NULL // Task handle is not used here - simply pass NULL + ); + + static int task_number1 = 1; + xTaskCreate( + Task + , "Task 1" + , 2048 // Stack size + , (void*)&task_number1 // Pass reference to a variable describing the task number + , 1 // Low priority + , NULL // Task handle is not used here - simply pass NULL + ); + + // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started. +} + +void loop(){ +} + +/*--------------------------------------------------*/ +/*---------------------- Tasks ---------------------*/ +/*--------------------------------------------------*/ + +void Task(void *pvParameters){ // This is a task. + int task_num = *((int*)pvParameters); + Serial.printf("%s\n", task_num ? " Starting |" : " | Starting"); + for (;;){ // A Task shall never return or exit. +#ifdef USE_MUTEX + if(shared_var_mutex != NULL){ // Sanity check if the mutex exists + // Try to take the mutex and wait indefintly if needed + if(xSemaphoreTake(shared_var_mutex, portMAX_DELAY) == pdTRUE){ + // Mutex successfully taken +#endif + int new_value = random(1000); + + char str0[32]; sprintf(str0, " %d <- %d |", shared_variable, new_value); + char str1[32]; sprintf(str1, " | %d <- %d", shared_variable, new_value); + Serial.printf("%s\n", task_num ? str0 : str1); + + shared_variable = new_value; + delay(random(100)); // wait random time of max 100 ms - simulating some computation + + sprintf(str0, " R: %d |", shared_variable); + sprintf(str1, " | R: %d", shared_variable); + Serial.printf("%s\n", task_num ? str0 : str1); + //Serial.printf("Task %d after write: reading %d\n", task_num, shared_variable); + + if(shared_variable != new_value){ + Serial.printf("%s\n", task_num ? " Mismatch! |" : " | Mismatch!"); + //Serial.printf("Task %d: detected race condition - the value changed!\n", task_num); + } + +#ifdef USE_MUTEX + xSemaphoreGive(shared_var_mutex); // After accessing the shared resource give the mutex and allow other processes to access it + }else{ + // We could not obtain the semaphore and can therefore not access the shared resource safely. + } // mutex take + } // sanity check +#endif + delay(10); // Allow other task to be scheduled + } // Infinite loop +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Mutex/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Mutex/README.md new file mode 100644 index 0000000..d1c8c19 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Mutex/README.md @@ -0,0 +1,121 @@ +# Mutex Example + +This example demonstrates the basic usage of FreeRTOS Mutually Exclusive Locks (Mutex) for securing access to shared resources in multi-threading. +Please refer to other examples in this folder to better understand the usage of tasks. +It is also advised to read the documentation on FreeRTOS web pages: +https://www.freertos.org/a00106.html + +This example creates 2 tasks with the same implementation - they write into a shared variable and then read it and check if it is the same as what they have written. +In single-thread programming like on Arduino this is of no concern and will be always ok, however when multi-threading is used the execution of the task is switched by the FreeRTOS and the value can be rewritten from another task before reading again. +The tasks print write and read operation - each in their column for better reading. Task 0 is on the left and Task 1 is on the right. +Watch the writes and read in secure mode when using the mutex (default) as the results are as you would expect them. +Then try to comment the USE_MUTEX and watch again - there will be a lot of mismatches! + +### Theory: +Mutex is a specialized version of Semaphore (please see the Semaphore example for more info). +In essence, the mutex is a variable whose value determines if the mute is taken (locked) or given (unlocked). +When two or more processes access the same resource (variable, peripheral, etc) it might happen, for example, that when one task starts to read a variable and the operating system (FreeRTOS) will schedule the execution of another task +which will write to this variable and when the previous task runs again it will read something different. + +Mutexes and binary semaphores are very similar but have some subtle differences: +Mutexes include a priority inheritance mechanism, whereas binary semaphores do not. +This makes binary semaphores the better choice for implementing synchronization (between tasks or between tasks and an interrupt), and mutexes the better +choice for implementing simple mutual exclusion. +What is priority inheritance? +If a low-priority task holds the Mutex but gets interrupted by a Higher priority task, which +then tries to take the Mutex, the low-priority task will temporarily ‘inherit’ the high priority so a middle-priority task can't block the low-priority task, and thus also block the high priority task. +Semaphores don't have the logic to handle this, in part because Semaphores aren't 'owned' by the task that takes them. + +A mutex can also be recursive - if a task that holds the mutex takes it again, it will succeed, and the mutex will be released +for other tasks only when it is given the same number of times that it was taken. + +You can check the danger by commenting on the definition of USE_MUTEX which will disable the mutex and present the danger of concurrent access. + + +# Supported Targets + +This example supports all ESP32 SoCs. + +## How to Use Example + +Flash and observe the serial output. + +Comment the `USE_MUTEX` definition, save and flash again and observe the behavior of unprotected access to the shared variable. + +* How to install the Arduino IDE: [Install Arduino IDE](https://github.com/espressif/arduino-esp32/tree/master/docs/arduino-ide). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. + +#### Using Platform IO + +* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file. + +## Example Log Output + +The expected output of shared variables protected by mutex demonstrates mutually exclusive access from tasks - they do not interrupt each other and do not rewrite the value before the other task has read it back. + +``` + Task 0 | Task 1 + | Starting + | 0 <- 227 + Starting | + | R: 227 + 227 <- 737 | + R: 737 | + | 737 <- 282 + | R: 282 + 282 <- 267 | +``` + +The output of unprotected access to shared variable - it happens often that a task is interrupted after writing and before reading the other task write a different value - a corruption occurred! + +``` + Task 0 | Task 1 + | Starting + | 0 <- 333 + Starting | + 333 <- 620 | + R: 620 | + 620 <- 244 | + | R: 244 + | Mismatch! + | 244 <- 131 + R: 131 | + Mismatch! | + 131 <- 584 | + | R: 584 + | Mismatch! + | 584 <- 134 + | R: 134 + | 134 <- 554 + R: 554 | + Mismatch! | + 554 <- 313 | +``` + +## Troubleshooting + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) +* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) +* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) +* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Queue/Queue.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Queue/Queue.ino new file mode 100644 index 0000000..a26ee33 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Queue/Queue.ino @@ -0,0 +1,120 @@ +/* Basic Multi Threading Arduino Example + This example code is in the Public Domain (or CC0 licensed, at your option.) + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +// Please read file README.md in the folder containing this example./* + +#define MAX_LINE_LENGTH (64) + +// Define two tasks for reading and writing from and to the serial port. +void TaskWriteToSerial(void *pvParameters); +void TaskReadFromSerial(void *pvParameters); + +// Define Queue handle +QueueHandle_t QueueHandle; +const int QueueElementSize = 10; +typedef struct{ + char line[MAX_LINE_LENGTH]; + uint8_t line_length; +} message_t; + +// The setup function runs once when you press reset or power on the board. +void setup() { + // Initialize serial communication at 115200 bits per second: + Serial.begin(115200); + while(!Serial){delay(10);} + + // Create the queue which will have number of elements, each of size `message_t` and pass the address to . + QueueHandle = xQueueCreate(QueueElementSize, sizeof(message_t)); + + // Check if the queue was successfully created + if(QueueHandle == NULL){ + Serial.println("Queue could not be created. Halt."); + while(1) delay(1000); // Halt at this point as is not possible to continue + } + + // Set up two tasks to run independently. + xTaskCreate( + TaskWriteToSerial + , "Task Write To Serial" // A name just for humans + , 2048 // The stack size can be checked by calling `uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);` + , NULL // No parameter is used + , 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. + , NULL // Task handle is not used here + ); + + xTaskCreate( + TaskReadFromSerial + , "Task Read From Serial" + , 2048 // Stack size + , NULL // No parameter is used + , 1 // Priority + , NULL // Task handle is not used here + ); + + // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started. + Serial.printf("\nAnything you write will return as echo.\nMaximum line length is %d characters (+ terminating '0').\nAnything longer will be sent as a separate line.\n\n", MAX_LINE_LENGTH-1); +} + +void loop(){ + // Loop is free to do any other work + + delay(1000); // While not being used yield the CPU to other tasks +} + +/*--------------------------------------------------*/ +/*---------------------- Tasks ---------------------*/ +/*--------------------------------------------------*/ + +void TaskWriteToSerial(void *pvParameters){ // This is a task. + message_t message; + for (;;){ // A Task shall never return or exit. + // One approach would be to poll the function (uxQueueMessagesWaiting(QueueHandle) and call delay if nothing is waiting. + // The other approach is to use infinite time to wait defined by constant `portMAX_DELAY`: + if(QueueHandle != NULL){ // Sanity check just to make sure the queue actually exists + int ret = xQueueReceive(QueueHandle, &message, portMAX_DELAY); + if(ret == pdPASS){ + // The message was successfully received - send it back to Serial port and "Echo: " + Serial.printf("Echo line of size %d: \"%s\"\n", message.line_length, message.line); + // The item is queued by copy, not by reference, so lets free the buffer after use. + }else if(ret == pdFALSE){ + Serial.println("The `TaskWriteToSerial` was unable to receive data from the Queue"); + } + } // Sanity check + } // Infinite loop +} + +void TaskReadFromSerial(void *pvParameters){ // This is a task. + message_t message; + for (;;){ + // Check if any data are waiting in the Serial buffer + message.line_length = Serial.available(); + if(message.line_length > 0){ + // Check if the queue exists AND if there is any free space in the queue + if(QueueHandle != NULL && uxQueueSpacesAvailable(QueueHandle) > 0){ + int max_length = message.line_length < MAX_LINE_LENGTH ? message.line_length : MAX_LINE_LENGTH-1; + for(int i = 0; i < max_length; ++i){ + message.line[i] = Serial.read(); + } + message.line_length = max_length; + message.line[message.line_length] = 0; // Add the terminating nul char + + // The line needs to be passed as pointer to void. + // The last parameter states how many milliseconds should wait (keep trying to send) if is not possible to send right away. + // When the wait parameter is 0 it will not wait and if the send is not possible the function will return errQUEUE_FULL + int ret = xQueueSend(QueueHandle, (void*) &message, 0); + if(ret == pdTRUE){ + // The message was successfully sent. + }else if(ret == errQUEUE_FULL){ + // Since we are checking uxQueueSpacesAvailable this should not occur, however if more than one task should + // write into the same queue it can fill-up between the test and actual send attempt + Serial.println("The `TaskReadFromSerial` was unable to send data into the Queue"); + } // Queue send check + } // Queue sanity check + }else{ + delay(100); // Allow other tasks to run when there is nothing to read + } // Serial buffer check + } // Infinite loop +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Queue/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Queue/README.md new file mode 100644 index 0000000..745ce9e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Queue/README.md @@ -0,0 +1,75 @@ +# Queue Example + +This example demonstrates the basic usage of FreeRTOS Queues which enables tasks to pass data between each other in a secure asynchronous way. +Please refer to other examples in this folder to better understand the usage of tasks. +It is also advised to read the documentation on FreeRTOS web pages: +[https://www.freertos.org/a00106.html](https://www.freertos.org/a00106.html) + +This example reads data received on the serial port (sent by the user) pass it via queue to another task which will send it back on Serial Output. + +### Theory: +A queue is a simple-to-use data structure (in the most basic way) controlled by `xQueueSend` and `xQueueReceive` functions. +Usually, one task writes into the queue and the other task reads from it. +Usage of queues enables the reading task to yield the CPU until there are data in the queue and therefore not waste precious computation time. + +# Supported Targets + +This example supports all ESP32 SoCs. + +## How to Use Example + +Flash and write anything to serial input. + +* How to install the Arduino IDE: [Install Arduino IDE](https://github.com/espressif/arduino-esp32/tree/master/docs/arduino-ide). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. + +#### Using Platform IO + +* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file. + +## Example Log Output + +``` +Anything you write will return as echo. +Maximum line length is 63 characters (+ terminating '0'). +Anything longer will be sent as a separate line. + +``` +< Input text "Short input" + +``Echo line of size 11: "Short input"`` + +< Input text "An example of very long input which is longer than default 63 characters will be split." + +``` +Echo line of size 63: "An example of very long input which is longer than default 63 c" +Echo line of size 24: "haracters will be split." +``` + +## Troubleshooting + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) +* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) +* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) +* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md new file mode 100644 index 0000000..8f860a5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Semaphore/README.md @@ -0,0 +1,81 @@ +# Semaphore Example + +This example demonstrates the basic usage of FreeRTOS Semaphores and queue sets for coordination between tasks for multi-threading. +Please refer to other examples in this folder to better understand the usage of tasks. +It is also advised to read the documentation on FreeRTOS web pages: +[https://www.freertos.org/a00106.html](https://www.freertos.org/a00106.html) + +### Theory: +Semaphore is in essence a variable. Tasks can set the value, wait until one or more +semaphores are set and thus communicate between each other their state. +A binary semaphore is a semaphore that has a maximum count of 1, hence the 'binary' name. +A task can only 'take' the semaphore if it is available, and the semaphore is only available if its count is 1. + +Semaphores can be controlled by any number of tasks. If you use semaphore as a one-way +signalization with only one task giving and only one task taking there is a much faster option +called Task Notifications - please see FreeRTOS documentation and read more about them: [https://www.freertos.org/RTOS-task-notifications.html](https://www.freertos.org/RTOS-task-notifications.html) + +This example uses a semaphore to signal when a package is delivered to a warehouse by multiple +delivery trucks, and multiple workers are waiting to receive the package. + +# Supported Targets + +This example supports all ESP32 SoCs. + +## How to Use Example + +Read the code and try to understand it, then flash and observe the Serial output. + +* How to install the Arduino IDE: [Install Arduino IDE](https://github.com/espressif/arduino-esp32/tree/master/docs/arduino-ide). + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. + +#### Using Platform IO + +* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file. + +## Example Log Output + +``` +Anything you write will return as echo. +Maximum line length is 63 characters (+ terminating '0'). +Anything longer will be sent as a separate line. + +``` +< Input text "Short input" + +``Echo line of size 11: "Short input"`` + +< Input text "An example of very long input which is longer than default 63 characters will be split." + +``` +Echo line of size 63: "An example of very long input which is longer than default 63 c" +Echo line of size 24: "haracters will be split." +``` + +## Troubleshooting + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +## Contribute + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) +* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) +* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) +* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Semaphore/Semaphore.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Semaphore/Semaphore.ino new file mode 100644 index 0000000..ae3b3fd --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/FreeRTOS/Semaphore/Semaphore.ino @@ -0,0 +1,56 @@ +/* Basic Multi Threading Arduino Example + This example code is in the Public Domain (or CC0 licensed, at your option.) + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +// Please read file README.md in the folder containing this example. + +#include + +SemaphoreHandle_t package_delivered_semaphore; + +void delivery_truck_task(void *pvParameters) { + int truck_number = (int) pvParameters; + while(1) { + // Wait for a package to be delivered + // ... + // Notify the warehouse that a package has been delivered + xSemaphoreGive(package_delivered_semaphore); + Serial.printf("Package delivered by truck: %d\n", truck_number); + //wait for some time + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + +void warehouse_worker_task(void *pvParameters) { + int worker_number = (int) pvParameters; + while(1) { + // Wait for a package to be delivered + xSemaphoreTake(package_delivered_semaphore, portMAX_DELAY); + Serial.printf("Package received by worker: %d\n", worker_number); + // Receive the package + // ... + } +} + +void setup() { + Serial.begin(115200); + while(!Serial){ delay(100); } + // Create the semaphore + package_delivered_semaphore = xSemaphoreCreateCounting(10, 0); + + // Create multiple delivery truck tasks + for (int i = 0; i < 5; i++) { + xTaskCreate(delivery_truck_task, "Delivery Truck", 2048, (void *)i, tskIDLE_PRIORITY, NULL); + } + + // Create multiple warehouse worker tasks + for (int i = 0; i < 3; i++) { + xTaskCreate(warehouse_worker_task, "Warehouse Worker", 2048, (void *)i, tskIDLE_PRIORITY, NULL); + } +} + +void loop() { + // Empty loop +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/BlinkRGB/BlinkRGB.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/BlinkRGB/BlinkRGB.ino new file mode 100644 index 0000000..3bc0e6a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/BlinkRGB/BlinkRGB.ino @@ -0,0 +1,39 @@ +/* + BlinkRGB + + Demonstrates usage of onboard RGB LED on some ESP dev boards. + + Calling digitalWrite(RGB_BUILTIN, HIGH) will use hidden RGB driver. + + RGBLedWrite demonstrates controll of each channel: + void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) + + WARNING: After using digitalWrite to drive RGB LED it will be impossible to drive the same pin + with normal HIGH/LOW level +*/ +//#define RGB_BRIGHTNESS 64 // Change white brightness (max 255) + +// the setup function runs once when you press reset or power the board + +void setup() { + // No need to initialize the RGB LED +} + +// the loop function runs over and over again forever +void loop() { +#ifdef RGB_BUILTIN + digitalWrite(RGB_BUILTIN, HIGH); // Turn the RGB LED white + delay(1000); + digitalWrite(RGB_BUILTIN, LOW); // Turn the RGB LED off + delay(1000); + + neopixelWrite(RGB_BUILTIN,RGB_BRIGHTNESS,0,0); // Red + delay(1000); + neopixelWrite(RGB_BUILTIN,0,RGB_BRIGHTNESS,0); // Green + delay(1000); + neopixelWrite(RGB_BUILTIN,0,0,RGB_BRIGHTNESS); // Blue + delay(1000); + neopixelWrite(RGB_BUILTIN,0,0,0); // Off / black + delay(1000); +#endif +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino new file mode 100644 index 0000000..1a82532 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -0,0 +1,70 @@ +/* + * This example demonstrates usage of interrupt by detecting a button press. + * + * Setup: Connect first button between pin defined in BUTTON1 and GND + * Similarly connect second button between pin defined in BUTTON2 and GND. + * If you do not have a button simply connect a wire to those buttons + * - touching GND pin with other end of the wire will behave same as pressing the connected button. + * Wen using the bare wire be careful not to touch any other pin by accident. + * + * Note: There is no de-bounce implemented and the physical connection will normally + * trigger many more button presses than actually happened. + * This is completely normal and is not to be considered a fault. + */ + + +#include +#include + +#define BUTTON1 16 +#define BUTTON2 17 + +class Button{ +public: + Button(uint8_t reqPin) : PIN(reqPin){ + pinMode(PIN, INPUT_PULLUP); + }; + + void begin(){ + attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING); + Serial.printf("Started button interrupt on pin %d\n", PIN); + } + + ~Button(){ + detachInterrupt(PIN); + } + + void ARDUINO_ISR_ATTR isr() { + numberKeyPresses = numberKeyPresses + 1; + pressed = true; + } + + void checkPressed() { + if (pressed) { + Serial.printf("Button on pin %u has been pressed %lu times\n", PIN, numberKeyPresses); + pressed = false; + } + } + +private: + const uint8_t PIN; + volatile uint32_t numberKeyPresses; + volatile bool pressed; +}; + +Button button1(BUTTON1); +Button button2(BUTTON2); + +void setup() { + Serial.begin(115200); + while(!Serial) delay(10); + Serial.println("Starting Functional Interrupt example."); + button1.begin(); + button2.begin(); + Serial.println("Setup done."); +} + +void loop() { + button1.checkPressed(); + button2.checkPressed(); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/FunctionalInterruptStruct/FunctionalInterruptStruct.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/FunctionalInterruptStruct/FunctionalInterruptStruct.ino new file mode 100644 index 0000000..4e1f38d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/FunctionalInterruptStruct/FunctionalInterruptStruct.ino @@ -0,0 +1,39 @@ +#include + +#define BUTTON1 16 +#define BUTTON2 17 + +struct Button { + uint8_t PIN; + volatile uint32_t numberKeyPresses; + volatile int pressed; +}; + +void isr(void* param) { + struct Button *button = (struct Button*) param; + button->numberKeyPresses = button->numberKeyPresses + 1; + button->pressed = 1; +} + +void checkPressed(struct Button* button) { + if(button->pressed) { + Serial.printf("Button on pin %u has been pressed %lu times\n", button->PIN, button->numberKeyPresses); + button->pressed = 0; + } +} + +struct Button button1 = {BUTTON1, 0, 0}; +struct Button button2 = {BUTTON2, 0, 0}; + +void setup() { + Serial.begin(115200); + pinMode(button1.PIN, INPUT_PULLUP); + pinMode(button2.PIN, INPUT_PULLUP); + attachInterruptArg(button1.PIN, isr, (void*)&button1, FALLING); + attachInterruptArg(button2.PIN, isr, (void*)&button2, FALLING); +} + +void loop() { + checkPressed(&button1); + checkPressed(&button2); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/GPIOInterrupt/GPIOInterrupt.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/GPIOInterrupt/GPIOInterrupt.ino new file mode 100644 index 0000000..f208024 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/GPIO/GPIOInterrupt/GPIOInterrupt.ino @@ -0,0 +1,45 @@ +#include + +struct Button { + const uint8_t PIN; + uint32_t numberKeyPresses; + bool pressed; +}; + +Button button1 = {23, 0, false}; +Button button2 = {18, 0, false}; + +void ARDUINO_ISR_ATTR isr(void* arg) { + Button* s = static_cast(arg); + s->numberKeyPresses += 1; + s->pressed = true; +} + +void ARDUINO_ISR_ATTR isr() { + button2.numberKeyPresses += 1; + button2.pressed = true; +} + +void setup() { + Serial.begin(115200); + pinMode(button1.PIN, INPUT_PULLUP); + attachInterruptArg(button1.PIN, isr, &button1, FALLING); + pinMode(button2.PIN, INPUT_PULLUP); + attachInterrupt(button2.PIN, isr, FALLING); +} + +void loop() { + if (button1.pressed) { + Serial.printf("Button 1 has been pressed %lu times\n", button1.numberKeyPresses); + button1.pressed = false; + } + if (button2.pressed) { + Serial.printf("Button 2 has been pressed %lu times\n", button2.numberKeyPresses); + button2.pressed = false; + } + static uint32_t lastMillis = 0; + if (millis() - lastMillis > 10000) { + lastMillis = millis(); + detachInterrupt(button1.PIN); + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino new file mode 100644 index 0000000..a1f5c30 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino @@ -0,0 +1,136 @@ +/* + This example demonstrates I2S ADC capability to sample high frequency analog signals. + The PWM signal generated with ledc is only for ease of use when first trying out. + To sample the generated signal connect default pins 27(PWM) and 32(Sampling) together. + If you do not wish to generate PWM simply comment out the definition of constant GENERATE_PWM + Try to change the PWM_DUTY_PERCENT and see how to averaged value changes. + + The maximum for I2S ADC sampling frequency is 5MHz (value 5000000), however there will be many values repeated because the real + sampling frequency is much lower - + + By default this example will print values compatible with Arduino plotter + 1. signal - all values + 2. signal - averaged value + + You can change the number of sample over which is the signal averaged by changing value of AVERAGE_EVERY_N_SAMPLES + If you comment the definition altogether the averaging will not be performed nor printed. + + If you do not wish to print every value, simply comment definition of constant PRINT_ALL_VALUES + + Note: ESP prints messages at startup which will pollute Arduino IDE Serial plotter legend. + To avoid this pollution, start the plotter after startup (op restart) +*/ +#include + +// I2S +#define I2S_SAMPLE_RATE (277777) // Max sampling frequency = 277.777 kHz +#define ADC_INPUT (ADC1_CHANNEL_4) //pin 32 +#define I2S_DMA_BUF_LEN (1024) + +// PWM +#define GENERATE_PWM +#define OUTPUT_PIN (27) +#define PWM_FREQUENCY ((I2S_SAMPLE_RATE)/4) +#define PWM_DUTY_PERCENT (50) +#define PWM_RESOLUTION_BITS (2) // Lower bit resolution enables higher frequency +#define PWM_DUTY_VALUE ((((1<<(PWM_RESOLUTION_BITS)))*(PWM_DUTY_PERCENT))/100) // Duty value used for setup function based on resolution + +// Sample post processing +#define PRINT_ALL_VALUES +#define AVERAGE_EVERY_N_SAMPLES (100) + +void i2sInit(){ + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), + .sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 8, + .dma_buf_len = I2S_DMA_BUF_LEN, + .use_apll = false, + .tx_desc_auto_clear = false, + .fixed_mclk = 0, + .mclk_multiple = I2S_MCLK_MULTIPLE_128, + .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT + }; + Serial.printf("Attempting to setup I2S ADC with sampling frequency %d Hz\n", I2S_SAMPLE_RATE); + if(ESP_OK != i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL)){ + Serial.printf("Error installing I2S. Halt!"); + while(1); + } + if(ESP_OK != i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT)){ + Serial.printf("Error setting up ADC. Halt!"); + while(1); + } + if(ESP_OK != adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_DB_11)){ + Serial.printf("Error setting up ADC attenuation. Halt!"); + while(1); + } + + if(ESP_OK != i2s_adc_enable(I2S_NUM_0)){ + Serial.printf("Error enabling ADC. Halt!"); + while(1); + } + Serial.printf("I2S ADC setup ok\n"); +} + +void setup() { + Serial.begin(115200); + +#ifdef GENERATE_PWM + // PWM setup + Serial.printf("Setting up PWM: frequency = %d; resolution bits %d; Duty cycle = %d; duty value = %d, Output pin = %d\n", PWM_FREQUENCY, PWM_RESOLUTION_BITS, PWM_DUTY_PERCENT, PWM_DUTY_VALUE, OUTPUT_PIN); + ledcAttach(OUTPUT_PIN, PWM_FREQUENCY, PWM_RESOLUTION_BITS); + uint32_t freq = ledcReadFreq(OUTPUT_PIN); + + if(freq != PWM_FREQUENCY){ + Serial.printf("Error setting up PWM. Halt!"); + while(1); + } + ledcWrite(OUTPUT_PIN, PWM_DUTY_VALUE); + Serial.printf("PWM setup ok\n"); +#endif + + // Initialize the I2S peripheral + i2sInit(); +} + +void loop(){ +// The 4 high bits are the channel, and the data is inverted + size_t bytes_read; + uint16_t buffer[I2S_DMA_BUF_LEN] = {0}; + +#ifdef AVERAGE_EVERY_N_SAMPLES + uint32_t read_counter = 0; + uint32_t averaged_reading = 0; + uint64_t read_sum = 0; +#endif + + while(1){ + i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15); + //Serial.printf("read %d Bytes\n", bytes_read); + + for(int i = 0; i < bytes_read/2; ++i){ +#ifdef PRINT_ALL_VALUES + //Serial.printf("[%d] = %d\n", i, buffer[i] & 0x0FFF); // Print with indexes + Serial.printf("Signal:%d ", buffer[i] & 0x0FFF); // Print compatible with Arduino Plotter +#endif +#ifdef AVERAGE_EVERY_N_SAMPLES + read_sum += buffer[i] & 0x0FFF; + ++read_counter; + if(read_counter == AVERAGE_EVERY_N_SAMPLES){ + averaged_reading = read_sum / AVERAGE_EVERY_N_SAMPLES; + //Serial.printf("averaged_reading = %d over %d samples\n", averaged_reading, read_counter); // Print with additional info + Serial.printf("Averaged_signal:%ld", averaged_reading); // Print compatible with Arduino Plotter + read_counter = 0; + read_sum = 0; + } +#endif +#if defined(PRINT_ALL_VALUES) || defined (AVERAGE_EVERY_N_SAMPLES) + Serial.printf("\n"); +#endif + } // for + } // while +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino new file mode 100644 index 0000000..8a9a0ac --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino @@ -0,0 +1,98 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrate how to use a C++ Class to read several GPIO RMT signals + * calling a data processor when data is availble in background, using taks. + * + * The output is the last RMT data read in the GPIO, just to ilustrate how it works. + * + */ + + +class MyProcessor { + private: + uint32_t buff; // rolling buffer of most recent 32 bits. + int at = 0; + size_t rx_num_symbols = RMT_MEM_NUM_BLOCKS_1 * RMT_SYMBOLS_PER_CHANNEL_BLOCK; + rmt_data_t rx_symbols[RMT_MEM_NUM_BLOCKS_1 * RMT_SYMBOLS_PER_CHANNEL_BLOCK]; + + public: + int8_t gpio = -1; + + MyProcessor(uint8_t pin, uint32_t rmtFreqHz) { + if (!rmtInit(pin, RMT_RX_MODE, RMT_MEM_NUM_BLOCKS_1, rmtFreqHz)) + { + Serial.println("init receiver failed\n"); + return; + } + gpio = pin; + } + + void begin() { + // Creating RMT RX Callback Task + xTaskCreate(readTask, "MyProcessor", 2048, this, 4, NULL); + } + + static void readTask(void *args) { + MyProcessor *me = (MyProcessor *) args; + + while(1) { + // blocks until RMT has read data + rmtRead(me->gpio, me->rx_symbols, &me->rx_num_symbols, RMT_WAIT_FOR_EVER); + // process the data like a callback whenever there is data available + process(me->rx_symbols, me->rx_num_symbols, me); + } + vTaskDelete(NULL); + } + + static void process(rmt_data_t *data, size_t len, void *args) { + MyProcessor *me = (MyProcessor *) args; + uint32_t *buff = &me->buff; + + for (int i = 0; len; len--) { + if (data[i].duration0 == 0) + break; + *buff = (*buff << 1) | (data[i].level0 ? 1 : 0); + i++; + + if (data[i].duration1 == 0) + break; + *buff = (*buff << 1) | (data[i].level1 ? 1 : 0); + i++; + }; + } + + uint32_t val() { + return buff; + } +}; + +// Attach 3 processors to GPIO 4, 5 and 10 with different tick/speeds. +MyProcessor mp1 = MyProcessor(4, 1000000); +MyProcessor mp2 = MyProcessor(5, 1000000); +MyProcessor mp3 = MyProcessor(10, 2000000); + +void setup() { + Serial.begin(115200); + mp1.begin(); + mp2.begin(); + mp3.begin(); +} + +void loop() { + // The reading values will come from the 3 tasks started by setup() + Serial.printf("GPIO %d: %08lx | %d: %08lx | %d: %08lx\n", mp1.gpio, mp1.val(), mp2.gpio, mp2.val(), mp3.gpio, mp3.val()); + delay(500); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino new file mode 100644 index 0000000..c2d8a18 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopback.ino @@ -0,0 +1,94 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates usage of RMT for testing a circuit loopback + * using 2 GPIOs, one for sending RMT data and the other for receiving the data. + * Those 2 GPIO must be connected to each other. + * + * The output is the RMT data comparing what was sent and received + * + */ + +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +// ESP32 C3 has only 2 channels for RX and 2 for TX, thus MAX RMT_MEM is 128 +#define RMT_TX_PIN 4 +#define RMT_RX_PIN 5 +#define RMT_MEM_RX RMT_MEM_NUM_BLOCKS_2 +#else +#define RMT_TX_PIN 18 +#define RMT_RX_PIN 21 +#define RMT_MEM_RX RMT_MEM_NUM_BLOCKS_3 +#endif + +rmt_data_t my_data[256]; +rmt_data_t data[256]; + +static EventGroupHandle_t events; + +#define RMT_FREQ 10000000 // tick time is 100ns +#define RMT_NUM_EXCHANGED_DATA 30 + +void setup() { + Serial.begin(115200); + events = xEventGroupCreate(); + + if (!rmtInit(RMT_TX_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ)) { + Serial.println("init sender failed\n"); + } + if (!rmtInit(RMT_RX_PIN, RMT_RX_MODE, RMT_MEM_RX, RMT_FREQ)) { + Serial.println("init receiver failed\n"); + } + + // End of transmission shall be detected when line is idle for 2us = 20*100ns + rmtSetRxMaxThreshold(RMT_RX_PIN, 20); + // Disable Glitch filter + rmtSetRxMinThreshold(RMT_RX_PIN, 0); + + Serial.println("real tick set to: 100ns"); + Serial.printf("\nPlease connect GPIO %d to GPIO %d, now.\n", RMT_TX_PIN, RMT_RX_PIN); +} + +void loop() { + // Init data + int i; + for (i=0; i<255; i++) { + data[i].val = 0x80010001 + ((i%13)<<16) + 13-(i%13); + my_data[i].val = 0; + } + data[255].val = 0; + + // Start an async data read + size_t rx_num_symbols = RMT_NUM_EXCHANGED_DATA; + rmtReadAsync(RMT_RX_PIN, my_data, &rx_num_symbols); + + // Write blocking the data to the loopback + rmtWrite(RMT_TX_PIN, data, RMT_NUM_EXCHANGED_DATA, RMT_WAIT_FOR_EVER); + + // Wait until data is read + while (!rmtReceiveCompleted(RMT_RX_PIN)); + + // Once data is available, the number of RMT Symbols is stored in rx_num_symbols + // and the received data is copied to my_data + Serial.printf("Got %d RMT symbols\n", rx_num_symbols); + + // Printout the received data plus the original values + for (i=0; i<60; i++) { + Serial.printf("%08lx=%08lx ", my_data[i].val, data[i].val ); + if (!((i+1)%4)) Serial.println(""); + } + Serial.println("\n"); + + delay(500); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino new file mode 100644 index 0000000..78e7e0b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino @@ -0,0 +1,218 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates usage of RMT for receiving XJT D12 data + * + * The output is the RMT data read and processed + * + */ + +// +// Note: This example uses a FrSKY device communication +// using XJT D12 protocol +// +// ; 0 bit = 6us low/10us high +// ; 1 bit = 14us low/10us high +// ; +// ; --------+ +----------+ +----------+ +// ; | | | | | +// ; | 0 | | 1 | | +// ; | | | | | +// ; | | | | | +// ; +-------+ +-----------------+ +--------- +// ; +// ; | 6us 10us | 14us 10us | +// ; |-------|----------|-----------------|----------|-------- +// ; | 16us | 24us | + +// Typedef of received frame +// +// ; 0x00 - Sync, 0x7E (sync header ID) +// ; 0x01 - Rx ID, 0x?? (receiver ID number, 0x00-0x??) +// ; 0x02 - Flags 1, 0x?? (used for failsafe and binding) +// ; 0x03 - Flags 2, 0x00 (reserved) +// ; 0x04-0x06, Channels 1/9 and 2/10 +// ; 0x07-0x09, Channels 3/11 and 4/12 +// ; 0x0A-0x0C, Channels 5/13 and 6/14 +// ; 0x0D-0x0F, Channels 7/15 and 8/16 +// ; 0x10 - 0x00, always zero +// ; 0x11 - CRC-16 High +// ; 0x12 - CRC-16 Low +// ; 0x13 - Tail, 0x7E (tail ID) +typedef union { + struct { + uint8_t head;//0x7E + uint8_t rxid;//Receiver Number + uint8_t flags;//Range:0x20, Bind:0x01 + uint8_t reserved0;//0x00 + union { + struct { + uint8_t ch0_l; + uint8_t ch0_h: 4; + uint8_t ch1_l: 4; + uint8_t ch1_h; + }; + uint8_t bytes[3]; + } channels[4]; + uint8_t reserved1;//0x00 + uint8_t crc_h; + uint8_t crc_l; + uint8_t tail;//0x7E + }; + uint8_t buffer[20]; +} xjt_packet_t; + +#define XJT_VALID(i) (i->level0 && !i->level1 && i->duration0 >= 8 && i->duration0 <= 11) + +static uint32_t *s_channels; +static uint32_t channels[16]; +static uint8_t xjt_flags = 0x0; +static uint8_t xjt_rxid = 0x0; + +static bool xjtReceiveBit(size_t index, bool bit) { + static xjt_packet_t xjt; + static uint8_t xjt_bit_index = 8; + static uint8_t xht_byte_index = 0; + static uint8_t xht_ones = 0; + + if (!index) { + xjt_bit_index = 8; + xht_byte_index = 0; + xht_ones = 0; + } + + if (xht_byte_index > 19) { + //fail! + return false; + } + if (bit) { + xht_ones++; + if (xht_ones > 5 && xht_byte_index && xht_byte_index < 19) { + //fail! + return false; + } + //add bit + xjt.buffer[xht_byte_index] |= (1 << --xjt_bit_index); + } else if (xht_ones == 5 && xht_byte_index && xht_byte_index < 19) { + xht_ones = 0; + //skip bit + return true; + } else { + xht_ones = 0; + //add bit + xjt.buffer[xht_byte_index] &= ~(1 << --xjt_bit_index); + } + if ((!xjt_bit_index) || (xjt_bit_index == 1 && xht_byte_index == 19) ) { + xjt_bit_index = 8; + if (!xht_byte_index && xjt.buffer[0] != 0x7E) { + //fail! + return false; + } + xht_byte_index++; + if (xht_byte_index == 20) { + //done + if (xjt.buffer[19] != 0x7E) { + //fail! + return false; + } + //check crc? + + xjt_flags = xjt.flags; + xjt_rxid = xjt.rxid; + for (int i = 0; i < 4; i++) { + uint16_t ch0 = xjt.channels[i].ch0_l | ((uint16_t)(xjt.channels[i].ch0_h & 0x7) << 8); + ch0 = ((ch0 * 2) + 2452) / 3; + uint16_t ch1 = xjt.channels[i].ch1_l | ((uint16_t)(xjt.channels[i].ch1_h & 0x7F) << 4); + ch1 = ((ch1 * 2) + 2452) / 3; + uint8_t c0n = i * 2; + if (xjt.channels[i].ch0_h & 0x8) { + c0n += 8; + } + uint8_t c1n = i * 2 + 1; + if (xjt.channels[i].ch1_h & 0x80) { + c1n += 8; + } + s_channels[c0n] = ch0; + s_channels[c1n] = ch1; + } + } + } + return true; +} + +void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels) { + bool valid = true; + rmt_data_t* it = NULL; + + if (!channels) { + log_e("Please provide data block for storing channel info"); + return; + } + s_channels = channels; + + it = &items[0]; + for (size_t i = 0; i < len; i++) { + + if (!valid) { + break; + } + it = &items[i]; + if (XJT_VALID(it)) { + if (it->duration1 >= 5 && it->duration1 <= 8) { + valid = xjtReceiveBit(i, false); + } else if (it->duration1 >= 13 && it->duration1 <= 16) { + valid = xjtReceiveBit(i, true); + } else { + valid = false; + } + } else if (!it->duration1 && !it->level1 && it->duration0 >= 5 && it->duration0 <= 8) { + valid = xjtReceiveBit(i, false); + + } + } +} + +// Change the RMT reading GPIO here: +#define RMT_GPIO 21 + +void setup() { + Serial.begin(115200); + // Initialize the channel to capture up to 64*2 or 48*2 items - 1us tick + if (!rmtInit(RMT_GPIO, RMT_RX_MODE, RMT_MEM_NUM_BLOCKS_2, 1000000)) { + Serial.println("init receiver failed\n"); + } + Serial.println("real tick set to: 1us"); +} + +void loop() { + static rmt_data_t data[RMT_MEM_NUM_BLOCKS_2 * RMT_SYMBOLS_PER_CHANNEL_BLOCK]; + static size_t data_symbols = RMT_MEM_NUM_BLOCKS_2 * RMT_SYMBOLS_PER_CHANNEL_BLOCK; + + // Blocking read with timeout of 500ms + // If data is read, data_symbols will have the number of RMT symbols effectively read + // to check if something was read and it didn't just timeout, use rmtReceiveCompleted() + rmtRead(RMT_GPIO, data, &data_symbols, 500); + + // If read something, process the data + if (rmtReceiveCompleted(RMT_GPIO)) { + Serial.printf("Got %d RMT Symbols. Parsing data...\n", data_symbols); + parseRmt(data, data_symbols, channels); + } else { + Serial.println("No RMT data read..."); + } + + // printout some of the channels every 500ms + Serial.printf("%04lx %04lx %04lx %04lx\n", channels[0], channels[1], channels[2], channels[3]); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino new file mode 100644 index 0000000..9a381de --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino @@ -0,0 +1,103 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates usage of RGB LED driven by RMT + * + * The output is a visual WS2812 RGB LED color moving in a 8 x 4 LED matrix + * Parameters can be changed by the user. In a single LED circuit, it will just blink. + */ + +// The effect seen in ESP32C3, ESP32S2 and ESP32S3 is like a Blink of RGB LED +#if CONFIG_IDF_TARGET_ESP32S2 +#define BUILTIN_RGBLED_PIN 18 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define BUILTIN_RGBLED_PIN 48 // 48 or 38 +#elif CONFIG_IDF_TARGET_ESP32C3 +#define BUILTIN_RGBLED_PIN 8 +#else +#define BUILTIN_RGBLED_PIN 21 // ESP32 has no builtin RGB LED +#endif + +#define NR_OF_LEDS 8*4 +#define NR_OF_ALL_BITS 24*NR_OF_LEDS + +// +// Note: This example uses Neopixel LED board, 32 LEDs chained one +// after another, each RGB LED has its 24 bit value +// for color configuration (8b for each color) +// +// Bits encoded as pulses as follows: +// +// "0": +// +-------+ +-- +// | | | +// | | | +// | | | +// ---| |--------------| +// + + + +// | 0.4us | 0.85 0us | +// +// "1": +// +-------------+ +-- +// | | | +// | | | +// | | | +// | | | +// ---+ +-------+ +// | 0.8us | 0.4us | + +rmt_data_t led_data[NR_OF_ALL_BITS]; + +void setup() { + Serial.begin(115200); + if (!rmtInit(BUILTIN_RGBLED_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000)) { + Serial.println("init sender failed\n"); + } + Serial.println("real tick set to: 100ns"); +} + +int color[] = { 0x55, 0x11, 0x77 }; // Green Red Blue values +int led_index = 0; + +void loop() { + // Init data with only one led ON + int led, col, bit; + int i=0; + for (led=0; led=NR_OF_LEDS) { + led_index = 0; + } + // Send the data and wait until it is done + rmtWrite(BUILTIN_RGBLED_PIN, led_data, NR_OF_ALL_BITS, RMT_WAIT_FOR_EVER); + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMT_CPUFreq_Test/RMT_CPUFreq_Test.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMT_CPUFreq_Test/RMT_CPUFreq_Test.ino new file mode 100644 index 0000000..8150dcc --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMT_CPUFreq_Test/RMT_CPUFreq_Test.ino @@ -0,0 +1,90 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrates usage of RGB LED driven by RMT to verify + * that RMT works on any CPU/APB Frequency. + * + * It uses an ESP32 Arduino builtin RGB NeoLED function based on RMT: + * void neopixelWrite(uint8_t pin, uint8_t red_val, uint8_t green_val, uint8_t blue_val) + * + * The output is a visual WS2812 RGB LED color change routine using each time a + * different CPU Frequency, just to ilustrate how it works. Serial output indicates + * information about the CPU Frequency while controlling the RGB LED using RMT. + */ + + +// Default DevKit RGB LED GPIOs: +#if CONFIG_IDF_TARGET_ESP32S2 +#define MY_LED_GPIO 18 +#elif CONFIG_IDF_TARGET_ESP32S3 +#define MY_LED_GPIO 48 // 48 or 38 +#elif CONFIG_IDF_TARGET_ESP32C3 +#define MY_LED_GPIO 8 +#else +#define MY_LED_GPIO 21 // Any, ESP32 has no RGB LED - depends on circuit setup +#endif + +// Set the correct GPIO to any necessary by changing RGB_LED_GPIO value +#define RGB_LED_GPIO MY_LED_GPIO // Any GPIO valid in the board + +// Change the RGB Brightness to any value from 0 (off) to 255 (max) +#define BRIGHTNESS 20 // Change color brightness (max 255) + +void setup() { + Serial.begin(115200); + delay(500); + Serial.printf("\nUsing GPIO %d attached to the RGB LED.\nInitial CPU setup:\n", RGB_LED_GPIO); + + Serial.printf("CPU Freq = %lu MHz\n", getCpuFrequencyMhz()); + Serial.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz()); + Serial.printf("APB Freq = %lu Hz\n", getApbFrequency()); +} + +void loop() { + const uint8_t cpufreqs[] = {240, 160, 80, 40, 20, 10}; + static uint8_t i = 0; + + setCpuFrequencyMhz(cpufreqs[i]); + // moves to the next CPU freq for the next loop + i = (i + 1) % sizeof(cpufreqs); + + // Changing the CPU Freq demands RMT to reset internals parameters setting it correctly + // This is fixed by reinitializing the RMT peripheral as done below + // 100ns RMT Tick for driving the NeoLED as in the code of esp32-hal-rgb-led.c (github) + rmtInit(RGB_LED_GPIO, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 10000000); + + // resets also UART to adapt to the new CPU Freq + Serial.updateBaudRate(115200); + Serial.printf("\n--changed CPU Frequency to %lu MHz\n", getCpuFrequencyMhz()); + + neopixelWrite(RGB_LED_GPIO, BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); // White + Serial.println("White"); + delay(1000); + neopixelWrite(RGB_LED_GPIO, 0, 0, 0); // Off + Serial.println("Off"); + delay(1000); + neopixelWrite(RGB_LED_GPIO, BRIGHTNESS, 0, 0); // Red + Serial.println("Red"); + delay(1000); + neopixelWrite(RGB_LED_GPIO, 0, BRIGHTNESS, 0); // Green + Serial.println("Green"); + delay(1000); + neopixelWrite(RGB_LED_GPIO, 0, 0, BRIGHTNESS); // Blue + Serial.println("Blue"); + delay(1000); + neopixelWrite(RGB_LED_GPIO, 0, 0, 0); // Off + Serial.println("Off"); + delay(1000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino new file mode 100644 index 0000000..3232fb7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/RMT/RMT_LED_Blink/RMT_LED_Blink.ino @@ -0,0 +1,220 @@ +// Copyright 2023 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @brief This example demonstrate how to use RMT to just blink a regular LED (GPIO) + * It uses all the different RMT Writing APIs to blink the LED by hardware, not being + * necessary the regular Blink code in Arduino. + * + * The output is the Blinking LED in the GPIO and a serial output describing what is + * going on, along the execution. + * + * The circuit is just a LED and a resistor of 270 ohms connected to the GPIO + * GPIO ---> resistor 270 ohms ---> + LED - ---> GND + */ + +#define BLINK_GPIO 2 + +// RMT is at 400KHz with a 2.5us tick +// This RMT data sends a 0.5Hz pulse with 1s High and 1s Low signal +rmt_data_t blink_1s_rmt_data[] = { + // 400,000 x 2.5us = 1 second ON + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + // 400,000 x 2.5us = 1 second OFF + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + // Looping mode needs a Zero ending data to mark the EOF + {0, 0, 0, 0} +}; + +// RMT is at 400KHz with a 2.5us tick +// This RMT data sends a 1Hz pulse with 500ms High and 500ms Low signal +rmt_data_t blink_500ms_rmt_data[] = { + // 200,000 x 2.5us = 0.5 second ON + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + // 200,000 x 2.5us = 0.5 second OFF + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + // Looping mode needs a Zero ending data to mark the EOF + {0, 0, 0, 0} +}; + +// RMT is at 400KHz with a 2.5us tick +// This RMT data sends a 2Hz pulse with 250ms High and 250ms Low signal +rmt_data_t blink_250ms_rmt_data[] = { + // 100,000 x 2.5us = 0.25 second ON + {25000, 1, 25000, 1,}, + {25000, 1, 25000, 1,}, + // 100,000 x 2.5us = 0.25 second OFF + {25000, 0, 25000, 0,}, + {25000, 0, 25000, 0,}, + // Looping mode needs a Zero ending data to mark the EOF + {0, 0, 0, 0} +}; + +void RMT_Mixed_Write_Blink() { + Serial.println("===> rmtWriteLooping() to Blink the LED."); + Serial.println("Blinking at 1s on + 1s off :: 3 blinks"); + if (!rmtWriteLooping(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data))) { + Serial.println("===> rmtWriteLooping Blink 1s Error!"); + } + delay(6000); // blinking happens here, done by hardware! + + Serial.println("===> rmtWrite() (Blocking Mode) to Blink the LED."); + Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks"); + for (uint8_t i = 0; i < 4; i++) { + if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + Serial.println("===> rmtWrite Blink 0.5s Error!"); + } + } + + Serial.println("===> rmtWriteAsync() (Non-Blocking Mode) to Blink the LED."); + Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks"); + for (uint8_t i = 0; i < 5; i++) { + if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2)) { + Serial.println("===> rmtWrite Blink 0.25s Error!"); + } + // wait (blocks) until all the data is sent out + while (!rmtTransmitCompleted(BLINK_GPIO)); + } + Serial.println("Blinking OFF for 1 seconds"); + delay(1000); +} + +void RMT_Loop_Write_Blink() { + Serial.println("Using RMT Writing loop to blink an LED."); + Serial.println("Blinking at 1s on + 1s off :: 3 blinks"); + if (!rmtWriteLooping(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data))) { + Serial.println("===> rmtWriteLooping Blink 1s Error!"); + } + delay(6000); + Serial.println("Blinking at 500ms on + 500ms off :: 5 blinks"); + if (!rmtWriteLooping(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data))) { + Serial.println("===> rmtWriteLooping Blink 0.5s Error!"); + } + delay(5000); + Serial.println("Blinking at 250ms on + 250ms off :: 10 blinks"); + if (!rmtWriteLooping(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data))) { + Serial.println("===> rmtWriteLooping Blink 0.25s Error!"); + } + delay(5000); + Serial.println("Blinking OFF for 2 seconds"); + if (!rmtWriteLooping(BLINK_GPIO, NULL, 0)) { + Serial.println("===> rmtWriteLooping Blink OFF Error!"); + } + delay(2000); +} + +void RMT_Single_Write_Blocking_Blink() { + Serial.println("Using RMT Writing and its Completion to blink an LED."); + Serial.println("Blinking at 1s on + 1s off :: 2 blinks"); + for (uint8_t i = 0; i < 2; i++) { + if (!rmtWrite(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + Serial.println("===> rmtWrite Blink 1s Error!"); + } + } + Serial.println("Blinking at 500ms on + 500ms off :: 4 blinks"); + for (uint8_t i = 0; i < 4; i++) { + if (!rmtWrite(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + Serial.println("===> rmtWrite Blink 0.5s Error!"); + } + } + Serial.println("Blinking at 250ms on + 250ms off :: 8 blinks"); + for (uint8_t i = 0; i < 8; i++) { + if (!rmtWrite(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2, RMT_WAIT_FOR_EVER)) { + Serial.println("===> rmtWrite Blink 0.25s Error!"); + } + } + Serial.println("Blinking OFF for 3 seconds"); + delay(3000); +} + +void RMT_Write_Aync_Non_Blocking_Blink() { + Serial.println("Using RMT Async Writing and its Completion to blink an LED."); + Serial.println("Blinking at 1s on + 1s off :: 5 blinks"); + for (uint8_t i = 0; i < 5; i++) { + if (!rmtWriteAsync(BLINK_GPIO, blink_1s_rmt_data, RMT_SYMBOLS_OF(blink_1s_rmt_data) - 2)) { + Serial.println("===> rmtWrite Blink 1s Error!"); + } + // wait (blocks) until all the data is sent out + while (!rmtTransmitCompleted(BLINK_GPIO)); + } + Serial.println("Blinking at 500ms on + 500ms off :: 5 blinks"); + for (uint8_t i = 0; i < 5; i++) { + if (!rmtWriteAsync(BLINK_GPIO, blink_500ms_rmt_data, RMT_SYMBOLS_OF(blink_500ms_rmt_data) - 2)) { + Serial.println("===> rmtWrite Blink 0.5s Error!"); + } + // wait (blocks) until all the data is sent out + while (!rmtTransmitCompleted(BLINK_GPIO)); + } + Serial.println("Blinking at 250ms on + 250ms off :: 5 blinks"); + for (uint8_t i = 0; i < 5; i++) { + if (!rmtWriteAsync(BLINK_GPIO, blink_250ms_rmt_data, RMT_SYMBOLS_OF(blink_250ms_rmt_data) - 2)) { + Serial.println("===> rmtWrite Blink 0.25s Error!"); + } + // wait (blocks) until all the data is sent out + while (!rmtTransmitCompleted(BLINK_GPIO)); + } + Serial.println("Blinking OFF for 1 seconds"); + delay(1000); +} + +void setup() { + Serial.begin(115200); + Serial.println("Starting Blink testing..."); + Serial.flush(); + + // 1 RMT Block has 64 RMT_SYMBOLS (ESP32|ESP32S2) or 48 RMT_SYMBOLS (ESP32C3|ESP32S3) + if (!rmtInit(BLINK_GPIO, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, 400000)) { //2.5us tick + Serial.println("===> rmtInit Error!"); + } else { + Serial.println("===> rmtInit OK! Tick = 2.5us - OK for testing"); + } + Serial.println("\n======================================"); + Serial.println( "All set. Starting RMT testing Routine."); + Serial.println( "======================================\n"); + + RMT_Mixed_Write_Blink(); + Serial.println("End of Mixed Calls testing"); + delay(1000); + + Serial.println("\n==============================="); + Serial.println( "Starting a Blinking sequence..."); + Serial.println( "===============================\n"); +} + +void loop() { + RMT_Write_Aync_Non_Blocking_Blink(); + RMT_Loop_Write_Blink(); + RMT_Single_Write_Blocking_Blink(); + Serial.println("\nStarting OVER...\n"); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ResetReason/ResetReason.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ResetReason/ResetReason.ino new file mode 100644 index 0000000..4c3243d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/ResetReason/ResetReason.ino @@ -0,0 +1,167 @@ +/* +* Print last reset reason of ESP32 +* ================================= +* +* Use either of the methods print_reset_reason +* or verbose_print_reset_reason to display the +* cause for the last reset of this device. +* +* Public Domain License. +* +* Author: +* Evandro Luis Copercini - 2017 +*/ + +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#include "esp32/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/rtc.h" +#else +#error Target CONFIG_IDF_TARGET is not supported +#endif + +#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */ + +void print_reset_reason(int reason) +{ + switch ( reason) + { + case 1 : Serial.println ("POWERON_RESET");break; /**<1, Vbat power on reset*/ + case 3 : Serial.println ("SW_RESET");break; /**<3, Software reset digital core*/ + case 4 : Serial.println ("OWDT_RESET");break; /**<4, Legacy watch dog reset digital core*/ + case 5 : Serial.println ("DEEPSLEEP_RESET");break; /**<5, Deep Sleep reset digital core*/ + case 6 : Serial.println ("SDIO_RESET");break; /**<6, Reset by SLC module, reset digital core*/ + case 7 : Serial.println ("TG0WDT_SYS_RESET");break; /**<7, Timer Group0 Watch dog reset digital core*/ + case 8 : Serial.println ("TG1WDT_SYS_RESET");break; /**<8, Timer Group1 Watch dog reset digital core*/ + case 9 : Serial.println ("RTCWDT_SYS_RESET");break; /**<9, RTC Watch dog Reset digital core*/ + case 10 : Serial.println ("INTRUSION_RESET");break; /**<10, Instrusion tested to reset CPU*/ + case 11 : Serial.println ("TGWDT_CPU_RESET");break; /**<11, Time Group reset CPU*/ + case 12 : Serial.println ("SW_CPU_RESET");break; /**<12, Software reset CPU*/ + case 13 : Serial.println ("RTCWDT_CPU_RESET");break; /**<13, RTC Watch dog Reset CPU*/ + case 14 : Serial.println ("EXT_CPU_RESET");break; /**<14, for APP CPU, reseted by PRO CPU*/ + case 15 : Serial.println ("RTCWDT_BROWN_OUT_RESET");break;/**<15, Reset when the vdd voltage is not stable*/ + case 16 : Serial.println ("RTCWDT_RTC_RESET");break; /**<16, RTC Watch dog reset digital core and rtc module*/ + default : Serial.println ("NO_MEAN"); + } +} + +void verbose_print_reset_reason(int reason) +{ + switch ( reason) + { + case 1 : Serial.println ("Vbat power on reset");break; + case 3 : Serial.println ("Software reset digital core");break; + case 4 : Serial.println ("Legacy watch dog reset digital core");break; + case 5 : Serial.println ("Deep Sleep reset digital core");break; + case 6 : Serial.println ("Reset by SLC module, reset digital core");break; + case 7 : Serial.println ("Timer Group0 Watch dog reset digital core");break; + case 8 : Serial.println ("Timer Group1 Watch dog reset digital core");break; + case 9 : Serial.println ("RTC Watch dog Reset digital core");break; + case 10 : Serial.println ("Instrusion tested to reset CPU");break; + case 11 : Serial.println ("Time Group reset CPU");break; + case 12 : Serial.println ("Software reset CPU");break; + case 13 : Serial.println ("RTC Watch dog Reset CPU");break; + case 14 : Serial.println ("for APP CPU, reseted by PRO CPU");break; + case 15 : Serial.println ("Reset when the vdd voltage is not stable");break; + case 16 : Serial.println ("RTC Watch dog reset digital core and rtc module");break; + default : Serial.println ("NO_MEAN"); + } +} + +void setup() { + // put your setup code here, to run once: + Serial.begin(115200); + delay(2000); + + Serial.println("CPU0 reset reason:"); + print_reset_reason(rtc_get_reset_reason(0)); + verbose_print_reset_reason(rtc_get_reset_reason(0)); + + Serial.println("CPU1 reset reason:"); + print_reset_reason(rtc_get_reset_reason(1)); + verbose_print_reset_reason(rtc_get_reset_reason(1)); + +#ifndef CONFIG_IDF_TARGET_ESP32H2 + // Set ESP32 to go to deep sleep to see a variation + // in the reset reason. Device will sleep for 5 seconds. +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 + esp_sleep_pd_config(ESP_PD_DOMAIN_RC_FAST, ESP_PD_OPTION_OFF); +#else + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); +#endif + Serial.println("Going to sleep"); + esp_deep_sleep(5 * uS_TO_S_FACTOR); +#endif +} + +void loop() { + // put your main code here, to run repeatedly: + +} + +/* + Example Serial Log: + ==================== + +rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) +configsip: 0, SPIWP:0x00 +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:1 +load:0x3fff0008,len:8 +load:0x3fff0010,len:160 +load:0x40078000,len:10632 +load:0x40080000,len:252 +entry 0x40080034 +CPU0 reset reason: +RTCWDT_RTC_RESET +RTC Watch dog reset digital core and rtc module +CPU1 reset reason: +EXT_CPU_RESET +for APP CPU, reseted by PRO CPU +Going to sleep +ets Jun 8 2016 00:22:57 + +rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) +configsip: 0, SPIWP:0x00 +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:1 +load:0x3fff0008,len:8 +load:0x3fff0010,len:160 +load:0x40078000,len:10632 +load:0x40080000,len:252 +entry 0x40080034 +CPU0 reset reason: +DEEPSLEEP_RESET +Deep Sleep reset digital core +CPU1 reset reason: +EXT_CPU_RESET +for APP CPU, reseted by PRO CPU +Going to sleep +ets Jun 8 2016 00:22:57 + +rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) +configsip: 0, SPIWP:0x00 +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:1 +load:0x3fff0008,len:8 +load:0x3fff0010,len:160 +load:0x40078000,len:10632 +load:0x40080000,len:252 +entry 0x40080034 +CPU0 reset reason: +DEEPSLEEP_RESET +Deep Sleep reset digital core +CPU1 reset reason: +EXT_CPU_RESET +for APP CPU, reseted by PRO CPU +Going to sleep + +*/ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino new file mode 100644 index 0000000..3a71203 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/OnReceiveError_BREAK_Demo/OnReceiveError_BREAK_Demo.ino @@ -0,0 +1,163 @@ +/* + + This Sketch demonstrates how to use onReceiveError(callbackFunc) with HardwareSerial + + void HardwareSerial::onReceiveError(OnReceiveErrorCb function) + + It is possible to register a UART callback function that will be called + everytime that UART detects an error which is also associated to an interrupt. + + There are some possible UART errors: + + UART_BREAK_ERROR - when a BREAK event is detected in the UART line. In that case, a BREAK may + be read as one or more bytes ZERO as part of the data received by the UART peripheral. + + UART_BUFFER_FULL_ERROR - When the RX UART buffer is full. By default, Arduino will allocate a 256 bytes + RX buffer. As data is received, it is copied to the UART driver buffer, but when it is full and data can't + be copied anymore, this Error is issued. To prevent it the application can use + HardwareSerial::setRxBufferSize(size_t new_size), before using HardwareSerial::begin() + + UART_FIFO_OVF_ERROR - When the UART peripheral RX FIFO is full and data is still arriving, this error is issued. + The UART driver will stash RX FIFO and the data will be lost. In order to prevent, the application shall set a + good buffer size using HardwareSerial::setRxBufferSize(size_t new_size), before using HardwareSerial::begin() + + UART_FRAME_ERROR - When the UART peripheral detects a UART frame error, this error is issued. It may happen because + of line noise or bad impiedance. + + UART_PARITY_ERROR - When the UART peripheral detects a parity bit error, this error will be issued. + + + In summary, HardwareSerial::onReceiveError() works like an UART Error Notification callback. + + Errors have priority in the order of the callbacks, therefore, as soon as an error is detected, + the registered callback is executed firt, and only after that, the OnReceive() registered + callback function will be executed. This will give opportunity for the Application to take action + before reading data, if necessary. + + In long UART transmissions, some data will be received based on FIFO Full parameter, and whenever + an error ocurs, it will raise the UART error interrupt. + + This sketch produces BREAK UART error in the begining of a transmission and also at the end of a + transmission. It will be possible to understand the order of the events in the logs. + +*/ + +#include + +// There are two ways to make this sketch work: +// By physically connecting the pins 4 and 5 and then create a physical UART loopback, +// Or by using the internal IO_MUX to connect the TX signal to the RX pin, creating the +// same loopback internally. +#define USE_INTERNAL_PIN_LOOPBACK 1 // 1 uses the internal loopback, 0 for wiring pins 4 and 5 externally + +#define DATA_SIZE 26 // 26 bytes is a lower than RX FIFO size (127 bytes) +#define BAUD 9600 // Any baudrate from 300 to 115200 +#define TEST_UART 1 // Serial1 will be used for the loopback testing with different RX FIFO FULL values +#define RXPIN 4 // GPIO 4 => RX for Serial1 +#define TXPIN 5 // GPIO 5 => TX for Serial1 + +#define BREAK_BEFORE_MSG 0 +#define BREAK_AT_END_MSG 1 + + +uint8_t fifoFullTestCases[] = {120, 20, 5, 1}; +// volatile declaration will avoid any compiler optimization when reading variable values +volatile size_t sent_bytes = 0, received_bytes = 0; + +const char *uartErrorStrings[] = { + "UART_NO_ERROR", + "UART_BREAK_ERROR", + "UART_BUFFER_FULL_ERROR", + "UART_FIFO_OVF_ERROR", + "UART_FRAME_ERROR", + "UART_PARITY_ERROR" +}; + +// Callback function that will treat the UART errors +void onReceiveErrorFunction(hardwareSerial_error_t err) { + // This is a callback function that will be activated on UART RX Error Events + Serial.printf("\n-- onReceiveError [ERR#%d:%s] \n", err, uartErrorStrings[err]); + Serial.printf("-- onReceiveError:: There are %d bytes available.\n", Serial1.available()); +} + +// Callback function that will deal with arriving UART data +void onReceiveFunction() { + // This is a callback function that will be activated on UART RX events + size_t available = Serial1.available(); + received_bytes = received_bytes + available; + Serial.printf("onReceive Callback:: There are %d bytes available: {", available); + while (available --) { + Serial.print((char)Serial1.read()); + } + Serial.println("}"); +} + +void setup() { + // UART0 will be used to log information into Serial Monitor + Serial.begin(115200); + + // UART1 will have its RX<->TX cross connected + // GPIO4 <--> GPIO5 using external wire + Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3 +#if USE_INTERNAL_PIN_LOOPBACK + uart_internal_loopback(TEST_UART, RXPIN); +#endif + + for (uint8_t i = 0; i < sizeof(fifoFullTestCases); i++) { + Serial.printf("\n\n================================\nTest Case #%d BREAK at END\n================================\n", i + 1); + // First sending BREAK at the end of the UART data transmission + testAndReport(fifoFullTestCases[i], BREAK_AT_END_MSG); + Serial.printf("\n\n================================\nTest Case #%d BREAK at BEGINING\n================================\n", i + 1); + // Now sending BREAK at the begining of the UART data transmission + testAndReport(fifoFullTestCases[i], BREAK_BEFORE_MSG); + Serial.println("========================\nFinished!"); + } + +} + +void loop() { +} + +void testAndReport(uint8_t fifoFull, bool break_at_the_end) { + // Let's send 125 bytes from Serial1 rx<->tx and mesaure time using diferent FIFO Full configurations + received_bytes = 0; + sent_bytes = DATA_SIZE; // 26 characters + + uint8_t dataSent[DATA_SIZE + 1]; + dataSent[DATA_SIZE] = '\0'; // string null terminator, for easy printing. + + // initialize all data + for (uint8_t i = 0; i < DATA_SIZE; i++) { + dataSent[i] = 'A' + i; // fill it with characters A..Z + } + + Serial.printf("\nTesting onReceive for receiving %d bytes at %d baud, using RX FIFO Full = %d.\n", sent_bytes, BAUD, fifoFull); + Serial.println("onReceive is called on both FIFO Full and RX Timeout events."); + if (break_at_the_end) { + Serial.printf("BREAK event will be sent at the END of the %d bytes\n", sent_bytes); + } else { + Serial.printf("BREAK event will be sent at the BEGINING of the %d bytes\n", sent_bytes); + } + Serial.flush(); // wait Serial FIFO to be empty and then spend almost no time processing it + Serial1.setRxFIFOFull(fifoFull); // testing diferent result based on FIFO Full setup + Serial1.onReceive(onReceiveFunction); // sets a RX callback function for Serial 1 + Serial1.onReceiveError(onReceiveErrorFunction); // sets a RX callback function for Serial 1 + + if (break_at_the_end) { + sent_bytes = uart_send_msg_with_break(TEST_UART, dataSent, DATA_SIZE); + } else { + uart_send_break(TEST_UART); + sent_bytes = Serial1.write(dataSent, DATA_SIZE); + } + + Serial.printf("\nSent String: %s\n", dataSent); + while (received_bytes < sent_bytes) { + // just wait for receiving all byte in the callback... + } + + Serial.printf("\nIt has sent %d bytes from Serial1 TX to Serial1 RX\n", sent_bytes); + Serial.printf("onReceive() has read a total of %d bytes\n", received_bytes); + + Serial1.onReceiveError(NULL); // resets/disables the RX Error callback function for Serial 1 + Serial1.onReceive(NULL); // resets/disables the RX callback function for Serial 1 +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/OnReceive_Demo/OnReceive_Demo.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/OnReceive_Demo/OnReceive_Demo.ino new file mode 100644 index 0000000..fa16645 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/OnReceive_Demo/OnReceive_Demo.ino @@ -0,0 +1,133 @@ +/* + + This Sketch demonstrates how to use onReceive(callbackFunc) with HardwareSerial + + void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout = false) + + It is possible to register a UART callback function that will be called + everytime that UART receives data and an associated interrupt is generated. + + The receiving data interrupt can occur because of two possible events: + + 1- UART FIFO FULL: it happens when internal UART FIFO reaches a certain number of bytes. + Its full capacity is 127 bytes. The FIFO Full threshold for the interrupt can be changed + using HardwareSerial::setRxFIFOFull(uint8_t fifoFull). + Default FIFO Full Threshold is set at the UART initialzation using HardwareSerial::begin() + This will depend on the baud rate set with when begin() is executed. + For a baudrate of 115200 or lower, it it just 1 byte, mimicking original Arduino UART driver. + For a baudrate over 115200 it will be 120 bytes for higher performance. + Anyway it can be changed by the application at anytime. + + 2- UART RX Timeout: it happens, based on a timeout equivalent to a number of symbols at + the current baud rate. If the UART line is idle for this timeout, it will raise an interrupt. + This time can be changed by HardwareSerial::setRxTimeout(uint8_t rxTimeout) + + When any of those two interrupts occur, IDF UART driver will copy FIFO data to its internal + RingBuffer and then Arduino can read such data. At the same time, Arduino Layer will execute + the callback function defined with HardwareSerial::onReceive(). + + parameter (default false) can be used by the application to tell Arduino to + only execute the callback when the second event above happens (Rx Timeout). At this time all + received data will be available to be read by the Arduino application. But if the number of + received bytes is higher than the FIFO space, it will generate an error of FIFO overflow. + In order to avoid such problem, the application shall set an appropriate RX buffer size using + HardwareSerial::setRxBufferSize(size_t new_size) before executing begin() for the Serial port. + + In summary, HardwareSerial::onReceive() works like an RX Interrupt callback, that can be adjusted + using HardwareSerial::setRxFIFOFull() and HardwareSerial::setRxTimeout(). + +*/ + +#include + +// There are two ways to make this sketch work: +// By physically connecting the pins 4 and 5 and then create a physical UART loopback, +// Or by using the internal IO_MUX to connect the TX signal to the RX pin, creating the +// same loopback internally. +#define USE_INTERNAL_PIN_LOOPBACK 1 // 1 uses the internal loopback, 0 for wiring pins 4 and 5 externally + +#define DATA_SIZE 26 // 26 bytes is a lower than RX FIFO size (127 bytes) +#define BAUD 9600 // Any baudrate from 300 to 115200 +#define TEST_UART 1 // Serial1 will be used for the loopback testing with different RX FIFO FULL values +#define RXPIN 4 // GPIO 4 => RX for Serial1 +#define TXPIN 5 // GPIO 5 => TX for Serial1 + +uint8_t fifoFullTestCases[] = {120, 20, 5, 1}; +// volatile declaration will avoid any compiler optimization when reading variable values +volatile size_t sent_bytes = 0, received_bytes = 0; + + +void onReceiveFunction(void) { + // This is a callback function that will be activated on UART RX events + size_t available = Serial1.available(); + received_bytes = received_bytes + available; + Serial.printf("onReceive Callback:: There are %d bytes available: ", available); + while (available --) { + Serial.print((char)Serial1.read()); + } + Serial.println(); +} + +void setup() { + // UART0 will be used to log information into Serial Monitor + Serial.begin(115200); + + // UART1 will have its RX<->TX cross connected + // GPIO4 <--> GPIO5 using external wire + Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3 +#if USE_INTERNAL_PIN_LOOPBACK + uart_internal_loopback(TEST_UART, RXPIN); +#endif + + + for (uint8_t i = 0; i < sizeof(fifoFullTestCases); i++) { + Serial.printf("\n\n================================\nTest Case #%d\n================================\n", i + 1); + // onReceive callback will be called on FIFO Full and RX timeout - default behaviour + testAndReport(fifoFullTestCases[i], false); + } + + Serial.printf("\n\n================================\nTest Case #6\n================================\n"); + // onReceive callback will be called just on RX timeout - using onlyOnTimeout = true + // FIFO Full parameter (5 bytes) won't matter for the execution of this test case + // because onReceive() uses only RX Timeout to be activated + testAndReport(5, true); +} + +void loop() { +} + +void testAndReport(uint8_t fifoFull, bool onlyOnTimeOut) { + // Let's send 125 bytes from Serial1 rx<->tx and mesaure time using diferent FIFO Full configurations + received_bytes = 0; + sent_bytes = DATA_SIZE; // 26 characters + + uint8_t dataSent[DATA_SIZE + 1]; + dataSent[DATA_SIZE] = '\0'; // string null terminator, for easy printing. + + // initialize all data + for (uint8_t i = 0; i < DATA_SIZE; i++) { + dataSent[i] = 'A' + i; // fill it with characters A..Z + } + + Serial.printf("\nTesting onReceive for receiving %d bytes at %d baud, using RX FIFO Full = %d.\n", sent_bytes, BAUD, fifoFull); + if (onlyOnTimeOut) { + Serial.println("onReceive is called just on RX Timeout!"); + } else { + Serial.println("onReceive is called on both FIFO Full and RX Timeout events."); + } + Serial.flush(); // wait Serial FIFO to be empty and then spend almost no time processing it + Serial1.setRxFIFOFull(fifoFull); // testing diferent result based on FIFO Full setup + Serial1.onReceive(onReceiveFunction, onlyOnTimeOut); // sets a RX callback function for Serial 1 + + sent_bytes = Serial1.write(dataSent, DATA_SIZE); // ESP32 TX FIFO is about 128 bytes, 125 bytes will fit fine + Serial.printf("\nSent String: %s\n", dataSent); + while (received_bytes < sent_bytes) { + // just wait for receiving all byte in the callback... + } + + Serial.printf("\nIt has sent %d bytes from Serial1 TX to Serial1 RX\n", sent_bytes); + Serial.printf("onReceive() has read a total of %d bytes\n", received_bytes); + Serial.println("========================\nFinished!"); + + Serial1.onReceive(NULL); // resets/disables the RX callback function for Serial 1 +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/RxFIFOFull_Demo/RxFIFOFull_Demo.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/RxFIFOFull_Demo/RxFIFOFull_Demo.ino new file mode 100644 index 0000000..8781502 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/RxFIFOFull_Demo/RxFIFOFull_Demo.ino @@ -0,0 +1,103 @@ +/* + * + * This Sketch demonstrates the effect of changing RX FIFO Full parameter into HardwareSerial Class + * Serial.setRxFIFOFull(byte) is used to change it. + * By default, UART ISR will wait for 120 bytes to arrive into UART before making the data available + * to be read by an Arduino Sketch. It may also release fewer bytes after an RX Timeout equivalent by + * default to 2 UART symbols. + * + * The way we demonstrate the effect of this parameter is by measuring the time the Sketch takes + * to read data using Arduino HardwareSerial API. + * + * The higher RX FIFO Full is, the lower consumption of the core to process and make the data available. + * At the same time, it may take longer for the Sketch to be able to read it, because the data must first + * populate RX UART FIFO. + * + * The lower RX FIFO Full is, the higher consumption of the core to process and make the data available. + * This is because the core will be interrupted often and it will copy data from the RX FIFO to the Arduino + * internal buffer to be read by the sketch. By other hand, the data will be made available to the sketch + * faster, in a close to byte by byte communication. + * + * Therefore, it allows the decision of the architecture to be designed by the developer. + * Some application based on certain protocols may need the sketch to read the Serial Port byte by byte, for example. + * + */ + +#include + +// There are two ways to make this sketch work: +// By physically connecting the pins 4 and 5 and then create a physical UART loopback, +// Or by using the internal IO_MUX to connect the TX signal to the RX pin, creating the +// same loopback internally. +#define USE_INTERNAL_PIN_LOOPBACK 1 // 1 uses the internal loopback, 0 for wiring pins 4 and 5 externally + +#define DATA_SIZE 125 // 125 bytes is a bit higher than the default 120 bytes of RX FIFO FULL +#define BAUD 9600 // Any baudrate from 300 to 115200 +#define TEST_UART 1 // Serial1 will be used for the loopback testing with different RX FIFO FULL values +#define RXPIN 4 // GPIO 4 => RX for Serial1 +#define TXPIN 5 // GPIO 5 => TX for Serial1 + +uint8_t fifoFullTestCases[] = {120, 20, 5, 1}; + +void setup() { + // UART0 will be used to log information into Serial Monitor + Serial.begin(115200); + + // UART1 will have its RX<->TX cross connected + // GPIO4 <--> GPIO5 using external wire + Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3 +#if USE_INTERNAL_PIN_LOOPBACK + uart_internal_loopback(TEST_UART, RXPIN); +#endif + + for (uint8_t i = 0; i < sizeof(fifoFullTestCases); i++) { + Serial.printf("\n\n================================\nTest Case #%d\n================================\n", i + 1); + testAndReport(fifoFullTestCases[i]); + } + +} + +void loop() { +} + +void testAndReport(uint8_t fifoFull) { + // Let's send 125 bytes from Serial1 rx<->tx and mesaure time using diferent FIFO Full configurations + uint8_t bytesReceived = 0; + uint8_t dataSent[DATA_SIZE], dataReceived[DATA_SIZE]; + uint32_t timeStamp[DATA_SIZE], bytesJustReceived[DATA_SIZE]; + uint8_t i; + // initialize all data + for (i = 0; i < DATA_SIZE; i++) { + dataSent[i] = '0' + (i % 10); // fill it with a repeated sequence of 0..9 characters + dataReceived[i] = 0; + timeStamp[i] = 0; + bytesJustReceived[i] = 0; + } + + Serial.printf("Testing the time for receiving %d bytes at %d baud, using RX FIFO Full = %d:", DATA_SIZE, BAUD, fifoFull); + Serial.flush(); // wait Serial FIFO to be empty and then spend almost no time processing it + Serial1.setRxFIFOFull(fifoFull); // testing diferent result based on FIFO Full setup + + size_t sentBytes = Serial1.write(dataSent, sizeof(dataSent)); // ESP32 TX FIFO is about 128 bytes, 125 bytes will fit fine + uint32_t now = millis(); + i = 0; + while (bytesReceived < DATA_SIZE) { + bytesReceived += (bytesJustReceived[i] = Serial1.read(dataReceived + bytesReceived, DATA_SIZE)); + timeStamp[i] = millis(); + if (bytesJustReceived[i] > 0) i++; // next data only when we read something from Serial1 + // safety for array limit && timeout... in 5 seconds... + if (i == DATA_SIZE || millis() - now > 5000) break; + } + + uint32_t pastTime = millis() - now; + Serial.printf("\nIt has sent %d bytes from Serial1 TX to Serial1 RX\n", sentBytes); + Serial.printf("It took %lu milliseconds to read %d bytes\n", pastTime, bytesReceived); + Serial.printf("Per execution Serial.read() number of bytes data and time information:\n"); + for (i = 0; i < DATA_SIZE; i++) { + Serial.printf("#%03d - Received %03lu bytes after %lu ms.\n", i, bytesJustReceived[i], i > 0 ? timeStamp[i] - timeStamp[i - 1] : timeStamp[i] - now); + if (i != DATA_SIZE - 1 && bytesJustReceived[i + 1] == 0) break; + } + + Serial.println("========================\nFinished!"); +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino new file mode 100644 index 0000000..b4592f8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino @@ -0,0 +1,95 @@ +/* + + This Sketch demonstrates the effect of changing RX Timeout parameter into HardwareSerial Class + Serial.setRxTimeout(byte) is used to change it. + By default, UART ISR will wait for an RX Timeout equivalent to 2 UART symbols to understand that a flow. + of UART data has ended. For example, if just one byte is received, UART will send about 10 to + 11 bits depending of the configuration (parity, number of stopbits). The timeout is measured in + number of UART symbols, with 10 or 11 bits, in the current baudrate. + For 9600 baud, 1 bit takes 1/9600 of a second, equivalent to 104 microseconds, therefore, for 10 bits, + it takes about 1ms. A timeout of 2 UART symbols, with about 20 bits, would take about 2.1 milliseconds + for the ESP32 UART to trigger an IRQ telling the UART driver that the transmission has ended. + Just at this point, the data will be made available to Arduino HardwareSerial API (read(), available(), etc). + + The way we demonstrate the effect of this parameter is by measuring the time the Sketch takes + to read data using Arduino HardwareSerial API. + + The higher RX Timeout is, the longer it will take to make the data available, when a flow of data ends. + UART driver works copying data from UART FIFO to Arduino internal buffer. + The driver will copy data from FIFO when RX Timeout is detected or when FIFO is full. + ESP32 FIFO has 128 bytes and by default, the driver will copy the data when FIFO reaches 120 bytes. + If UART receives less than 120 bytes, it will wait RX Timeout to understand that the bus is IDLE and + then copy the data from the FIFO to the Arduino internal buffer, making it availble to the Arduino API. + +*/ + +#include + +// There are two ways to make this sketch work: +// By physically connecting the pins 4 and 5 and then create a physical UART loopback, +// Or by using the internal IO_MUX to connect the TX signal to the RX pin, creating the +// same loopback internally. +#define USE_INTERNAL_PIN_LOOPBACK 1 // 1 uses the internal loopback, 0 for wiring pins 4 and 5 externally + +#define DATA_SIZE 10 // 10 bytes is lower than the default 120 bytes of RX FIFO FULL +#define BAUD 9600 // Any baudrate from 300 to 115200 +#define TEST_UART 1 // Serial1 will be used for the loopback testing with different RX FIFO FULL values +#define RXPIN 4 // GPIO 4 => RX for Serial1 +#define TXPIN 5 // GPIO 5 => TX for Serial1 + +uint8_t rxTimeoutTestCases[] = {50, 20, 10, 5, 1}; + +void setup() { + // UART0 will be used to log information into Serial Monitor + Serial.begin(115200); + + // UART1 will have its RX<->TX cross connected + // GPIO4 <--> GPIO5 using external wire + Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3 +#if USE_INTERNAL_PIN_LOOPBACK + uart_internal_loopback(TEST_UART, RXPIN); +#endif + + for (uint8_t i = 0; i < sizeof(rxTimeoutTestCases); i++) { + Serial.printf("\n\n================================\nTest Case #%d\n================================\n", i + 1); + testAndReport(rxTimeoutTestCases[i]); + } + +} + +void loop() { +} + +void testAndReport(uint8_t rxTimeout) { + // Let's send 10 bytes from Serial1 rx<->tx and mesaure time using diferent Rx Timeout configurations + uint8_t bytesReceived = 0; + uint8_t dataSent[DATA_SIZE], dataReceived[DATA_SIZE]; + uint8_t i; + // initialize all data + for (i = 0; i < DATA_SIZE; i++) { + dataSent[i] = '0' + (i % 10); // fill it with a repeated sequence of 0..9 characters + dataReceived[i] = 0; + } + + Serial.printf("Testing the time for receiving %d bytes at %d baud, using RX Timeout = %d:", DATA_SIZE, BAUD, rxTimeout); + Serial.flush(); // wait Serial FIFO to be empty and then spend almost no time processing it + Serial1.setRxTimeout(rxTimeout); // testing diferent results based on Rx Timeout setup + // For baud rates lower or equal to 57600, ESP32 Arduino makes it get byte-by-byte from FIFO, thus we will change it here: + Serial1.setRxFIFOFull(120); // forces it to wait receiving 120 bytes in FIFO before making it availble to Arduino + + size_t sentBytes = Serial1.write(dataSent, sizeof(dataSent)); // ESP32 TX FIFO is about 128 bytes, 10 bytes will fit fine + uint32_t now = millis(); + while (bytesReceived < DATA_SIZE) { + bytesReceived += Serial1.read(dataReceived, DATA_SIZE); + // safety for array limit && timeout... in 5 seconds... + if (millis() - now > 5000) break; + } + + uint32_t pastTime = millis() - now; + Serial.printf("\nIt has sent %d bytes from Serial1 TX to Serial1 RX\n", sentBytes); + Serial.printf("It took %lu milliseconds to read %d bytes\n", pastTime, bytesReceived); + Serial.print("Received data: ["); + Serial.write(dataReceived, DATA_SIZE); + Serial.println("]"); + Serial.println("========================\nFinished!"); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/Serial_All_CPU_Freqs/Serial_All_CPU_Freqs.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/Serial_All_CPU_Freqs/Serial_All_CPU_Freqs.ino new file mode 100644 index 0000000..26a5125 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/Serial_All_CPU_Freqs/Serial_All_CPU_Freqs.ino @@ -0,0 +1,75 @@ +/* + Simple Sketch for testing HardwareSerial with different CPU Frequencies + Changing the CPU Frequency may affect peripherals and Wireless functionality + In ESP32 Arduino, UART shall work correctly in order to let the user see DGB info + and other application messages. + + CPU Frequency is usually lowered in sleep modes + and some other Low Power configurations + +*/ + +int cpufreqs[6] = {240, 160, 80, 40, 20, 10}; +#define NUM_CPU_FREQS (sizeof(cpufreqs) / sizeof(int)) + +void setup() { + + Serial.begin(115200); + delay(1000); + Serial.println("\n Starting...\n"); + Serial.flush(); + + // initial information + uint32_t Freq = getCpuFrequencyMhz(); + Serial.print("CPU Freq = "); + Serial.print(Freq); + Serial.println(" MHz"); + Freq = getXtalFrequencyMhz(); + Serial.print("XTAL Freq = "); + Serial.print(Freq); + Serial.println(" MHz"); + Freq = getApbFrequency(); + Serial.print("APB Freq = "); + Serial.print(Freq); + Serial.println(" Hz"); + delay(500); + + // ESP32-C3 and other RISC-V target may not support 240MHz +#ifdef CONFIG_IDF_TARGET_ESP32C3 + uint8_t firstFreq = 1; +#else + uint8_t firstFreq = 0; +#endif + + // testing HardwareSerial for all possible CPU/APB Frequencies + for (uint8_t i = firstFreq; i < NUM_CPU_FREQS; i++) { + Serial.printf("\n------- Trying CPU Freq = %d ---------\n", cpufreqs[i]); + Serial.flush(); // wait to empty the UART FIFO before changing the CPU Freq. + setCpuFrequencyMhz(cpufreqs[i]); + Serial.updateBaudRate(115200); + + Freq = getCpuFrequencyMhz(); + Serial.print("CPU Freq = "); + Serial.print(Freq); + Serial.println(" MHz"); + Freq = getXtalFrequencyMhz(); + Serial.print("XTAL Freq = "); + Serial.print(Freq); + Serial.println(" MHz"); + Freq = getApbFrequency(); + Serial.print("APB Freq = "); + Serial.print(Freq); + Serial.println(" Hz"); + if (i < NUM_CPU_FREQS - 1) { + Serial.println("Moving to the next frequency after a pause of 2 seconds."); + delay(2000); + } + } + Serial.println("\n-------------------\n"); + Serial.println("End of testing..."); + Serial.println("\n-------------------\n"); +} + +void loop() { + // Nothing here so far +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino new file mode 100644 index 0000000..be5eb0a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Serial/Serial_STD_Func_OnReceive/Serial_STD_Func_OnReceive.ino @@ -0,0 +1,133 @@ +/* + * This is C++ example that demonstrates the usage of a std::function as OnReceive Callback function to all the UARTs + * It basically defines a general onReceive function that receives an extra parameter, the Serial pointer that is + * executing the callback. + * + * For each HardwareSerial object (Serial, Serial1, Serial2), it is necessary to set the callback with + * the repective Serial pointer. It is done using lambda expression as a std::function. + * Example: + * Serial1.onReceive([]() { processOnReceiving(&Serial1); }); + * + */ + +// soc/soc_caps.h has information about each SoC target +// in this example, we use SOC_UART_NUM that goes from 1 to 3, +// depending on the number of available UARTs in the ESP32xx +// This makes the code transparent to what SoC is used. +#include "soc/soc_caps.h" + +// In case that the target has USB CDC and it has being selected to be enable on boot, +// the console output will into USB (Serial). +// Otherwise the output will be sent to UART0 (Serial) and we have to redefine Serial0 +#ifndef ARDUINO_USB_CDC_ON_BOOT +#define ARDUINO_USB_CDC_ON_BOOT 0 +#endif +#if ARDUINO_USB_CDC_ON_BOOT == 0 // No USB CDC +#define Serial0 Serial // redefine the symbol Serial0 to the default Arduino +#endif + +// This example shall use UART1 or UART2 for testing and UART0 for console messages +// If UART0 is used for testing, it is necessary to manually send data to it, using the Serial Monitor/Terminal +// In case that USB CDC is available, it may be used as console for messages. +#define TEST_UART 1 // Serial# (0, 1 or 2) will be used for the loopback +#define RXPIN 4 // GPIO 4 => RX for Serial1 or Serial2 +#define TXPIN 5 // GPIO 5 => TX for Serial1 or Serial2 + +// declare testingSerial (as reference) related to TEST_UART number defined above (only for Serial1 and Serial2) +#if SOC_UART_NUM > 1 && TEST_UART == 1 + HardwareSerial &testingSerial = Serial1; +#elif SOC_UART_NUM > 2 && TEST_UART == 2 + HardwareSerial &testingSerial = Serial2; +#endif + +// General callback function for any UART -- used with a lambda std::function within HardwareSerial::onReceive() +void processOnReceiving(HardwareSerial &mySerial) { + // detects which Serial# is being used here + int8_t uart_num = -1; + if (&mySerial == &Serial0) { + uart_num = 0; +#if SOC_UART_NUM > 1 + } else if (&mySerial == &Serial1) { + uart_num = 1; +#endif +#if SOC_UART_NUM > 2 + } else if (&mySerial == &Serial2) { + uart_num = 2; +#endif + } + + //Prints some information on the current Serial (UART0 or USB CDC) + if (uart_num == -1) { + Serial.println("This is not a know Arduino Serial# object..."); + return; + } + Serial.printf("\nOnReceive Callback --> Received Data from UART%d\n", uart_num); + Serial.printf("Received %d bytes\n", mySerial.available()); + Serial.printf("First byte is '%c' [0x%02x]\n", mySerial.peek(), mySerial.peek()); + uint8_t charPerLine = 0; + while(mySerial.available()) { + char c = mySerial.read(); + Serial.printf("'%c' [0x%02x] ", c, c); + if (++charPerLine == 10) { + charPerLine = 0; + Serial.println(); + } + } +} + +void setup() { + // Serial can be the USB or UART0, depending on the settings and which SoC is used + Serial.begin(115200); + + // when data is received from UART0, it will call the general function + // passing Serial0 as parameter for processing +#if TEST_UART == 0 + Serial0.begin(115200); // keeps default GPIOs + Serial0.onReceive([]() { + processOnReceiving(Serial0); + }); +#else + // and so on for the other UARTs (Serial1 and Serial2) + // Rx = 4, Tx = 5 will work for ESP32, S2, S3, C3, C6 and H2 + testingSerial.begin(115200, SERIAL_8N1, RXPIN, TXPIN); + testingSerial.onReceive([]() { + processOnReceiving(testingSerial); + }); +#endif + + // this helper function will connect TX pin (from TEST_UART number) to its RX pin + // creating a loopback that will allow to write to TEST_UART number + // and send it to RX with no need to physically connect both pins +#if TEST_UART > 0 + uart_internal_loopback(TEST_UART, RXPIN); +#else + // when UART0 is used for testing, it is necessary to send data using the Serial Monitor/Terminal + // Data must be sent by the CP2102, manually using the Serial Monitor/Terminal +#endif + + delay(500); + Serial.printf("\nSend bytes to UART%d in order to\n", TEST_UART); + Serial.println("see a single processing fuction display information about"); + Serial.println("the received data.\n"); + +} + +void loop() { + // All done by the UART callback functions + // just write a random number of bytes into the testing UART + char serial_data[24]; + size_t len = random(sizeof(serial_data) - 1) + 1; // at least 1 byte will be sent + for (uint8_t i = 0; i < len; i++) serial_data[i] = 'A' + i; + +#if TEST_UART > 0 + Serial.println("\n\n=================================="); + Serial.printf("Sending %d bytes to UART%d...\n", len, TEST_UART); + testingSerial.write(serial_data, len); +#else + // when UART0 is used for testing, it is necessary to send data using the Serial Monitor/Terminal + Serial.println("Use the Serial Monitor/Terminal to send data to UART0"); +#endif + Serial.println("pausing for 15 seconds."); + delay(15000); +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/TWAI/TWAIreceive/TWAIreceive.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/TWAI/TWAIreceive/TWAIreceive.ino new file mode 100644 index 0000000..ebf9f85 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/TWAI/TWAIreceive/TWAIreceive.ino @@ -0,0 +1,128 @@ +/* ESP32 TWAI receive example. + Receive messages and sends them over serial. + + Connect a CAN bus transceiver to the RX/TX pins. + For example: SN65HVD230 + + TWAI_MODE_LISTEN_ONLY is used so that the TWAI controller will not influence the bus. + + The API gives other possible speeds and alerts: + https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html + + Example output from a can bus message: + -> Message received + -> Message is in Standard Format + -> ID: 604 + -> Byte: 0 = 00, 1 = 0f, 2 = 13, 3 = 02, 4 = 00, 5 = 00, 6 = 08, 7 = 00 + + Example output with alerts: + -> Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus. + -> Bus error count: 171 + -> Alert: The RX queue is full causing a received frame to be lost. + -> RX buffered: 4 RX missed: 46 RX overrun 0 + + created 05-11-2022 by Stephan Martin (designer2k2) +*/ + +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#include "driver/twai.h" + +// Pins used to connect to CAN bus transceiver: +#define RX_PIN 21 +#define TX_PIN 22 + +// Intervall: +#define POLLING_RATE_MS 1000 + +static bool driver_installed = false; + +void setup() { + // Start Serial: + Serial.begin(115200); + + // Initialize configuration structures using macro initializers + twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_LISTEN_ONLY); + twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS(); //Look in the api-reference for other speed sets. + twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); + + // Install TWAI driver + if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) { + Serial.println("Driver installed"); + } else { + Serial.println("Failed to install driver"); + return; + } + + // Start TWAI driver + if (twai_start() == ESP_OK) { + Serial.println("Driver started"); + } else { + Serial.println("Failed to start driver"); + return; + } + + // Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states + uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL; + if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) { + Serial.println("CAN Alerts reconfigured"); + } else { + Serial.println("Failed to reconfigure alerts"); + return; + } + + // TWAI driver is now successfully installed and started + driver_installed = true; +} + +static void handle_rx_message(twai_message_t& message) { + // Process received message + if (message.extd) { + Serial.println("Message is in Extended Format"); + } else { + Serial.println("Message is in Standard Format"); + } + Serial.printf("ID: %lx\nByte:", message.identifier); + if (!(message.rtr)) { + for (int i = 0; i < message.data_length_code; i++) { + Serial.printf(" %d = %02x,", i, message.data[i]); + } + Serial.println(""); + } +} + +void loop() { + if (!driver_installed) { + // Driver not installed + delay(1000); + return; + } + // Check if alert happened + uint32_t alerts_triggered; + twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS)); + twai_status_info_t twaistatus; + twai_get_status_info(&twaistatus); + + // Handle alerts + if (alerts_triggered & TWAI_ALERT_ERR_PASS) { + Serial.println("Alert: TWAI controller has become error passive."); + } + if (alerts_triggered & TWAI_ALERT_BUS_ERROR) { + Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus."); + Serial.printf("Bus error count: %lu\n", twaistatus.bus_error_count); + } + if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) { + Serial.println("Alert: The RX queue is full causing a received frame to be lost."); + Serial.printf("RX buffered: %lu\t", twaistatus.msgs_to_rx); + Serial.printf("RX missed: %lu\t", twaistatus.rx_missed_count); + Serial.printf("RX overrun %lu\n", twaistatus.rx_overrun_count); + } + + // Check if message is received + if (alerts_triggered & TWAI_ALERT_RX_DATA) { + // One or more messages received. Handle all. + twai_message_t message; + while (twai_receive(&message, 0) == ESP_OK) { + handle_rx_message(message); + } + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/TWAI/TWAItransmit/TWAItransmit.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/TWAI/TWAItransmit/TWAItransmit.ino new file mode 100644 index 0000000..d8fba7f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/TWAI/TWAItransmit/TWAItransmit.ino @@ -0,0 +1,123 @@ +/* ESP32 TWAI transmit example. + This transmits a message every second. + + Connect a CAN bus transceiver to the RX/TX pins. + For example: SN65HVD230 + + The API gives other possible speeds and alerts: + https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html + + created 27-06-2023 by Stephan Martin (designer2k2) +*/ + +#include "driver/twai.h" + +// Pins used to connect to CAN bus transceiver: +#define RX_PIN 21 +#define TX_PIN 22 + +// Intervall: +#define TRANSMIT_RATE_MS 1000 + +#define POLLING_RATE_MS 1000 + +static bool driver_installed = false; + +unsigned long previousMillis = 0; // will store last time a message was send + + +void setup() { + // Start Serial: + Serial.begin(115200); + + // Initialize configuration structures using macro initializers + twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_NORMAL); + twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS(); //Look in the api-reference for other speed sets. + twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); + + // Install TWAI driver + if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) { + Serial.println("Driver installed"); + } else { + Serial.println("Failed to install driver"); + return; + } + + // Start TWAI driver + if (twai_start() == ESP_OK) { + Serial.println("Driver started"); + } else { + Serial.println("Failed to start driver"); + return; + } + + // Reconfigure alerts to detect TX alerts and Bus-Off errors + uint32_t alerts_to_enable = TWAI_ALERT_TX_IDLE | TWAI_ALERT_TX_SUCCESS | TWAI_ALERT_TX_FAILED | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR; + if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) { + Serial.println("CAN Alerts reconfigured"); + } else { + Serial.println("Failed to reconfigure alerts"); + return; + } + + // TWAI driver is now successfully installed and started + driver_installed = true; +} + +static void send_message() { + // Send message + + // Configure message to transmit + twai_message_t message; + message.identifier = 0x0F6; + message.data_length_code = 4; + for (int i = 0; i < 4; i++) { + message.data[i] = 0; + } + + // Queue message for transmission + if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) { + printf("Message queued for transmission\n"); + } else { + printf("Failed to queue message for transmission\n"); + } +} + +void loop() { + if (!driver_installed) { + // Driver not installed + delay(1000); + return; + } + // Check if alert happened + uint32_t alerts_triggered; + twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS)); + twai_status_info_t twaistatus; + twai_get_status_info(&twaistatus); + + // Handle alerts + if (alerts_triggered & TWAI_ALERT_ERR_PASS) { + Serial.println("Alert: TWAI controller has become error passive."); + } + if (alerts_triggered & TWAI_ALERT_BUS_ERROR) { + Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus."); + Serial.printf("Bus error count: %lu\n", twaistatus.bus_error_count); + } + if (alerts_triggered & TWAI_ALERT_TX_FAILED) { + Serial.println("Alert: The Transmission failed."); + Serial.printf("TX buffered: %lu\t", twaistatus.msgs_to_tx); + Serial.printf("TX error: %lu\t", twaistatus.tx_error_counter); + Serial.printf("TX failed: %lu\n", twaistatus.tx_failed_count); + } + if (alerts_triggered & TWAI_ALERT_TX_SUCCESS) { + Serial.println("Alert: The Transmission was successful."); + Serial.printf("TX buffered: %lu\t", twaistatus.msgs_to_tx); + } + + // Send message + unsigned long currentMillis = millis(); + if (currentMillis - previousMillis >= TRANSMIT_RATE_MS) { + previousMillis = currentMillis; + send_message(); + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Template/ExampleTemplate/ExampleTemplate.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Template/ExampleTemplate/ExampleTemplate.ino new file mode 100644 index 0000000..ff9733d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Template/ExampleTemplate/ExampleTemplate.ino @@ -0,0 +1,16 @@ +/* Arduino Example Template + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +void setup() { + +} + +void loop() { + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Template/ExampleTemplate/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Template/ExampleTemplate/README.md new file mode 100644 index 0000000..f5aa7b3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Template/ExampleTemplate/README.md @@ -0,0 +1,123 @@ +# Arduino-ESP32 Example/Library Name ==(REQUIRED)== + +==*Add a brief description of this example/library here!*== + +This example/library demonstrates how to create a new example README file. + +# Supported Targets ==(REQUIRED)== + +==*Add the supported devices here!*== + +Currently, this example supports the following targets. + +| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | +| ----------------- | ----- | -------- | -------- | + +## How to Use Example/Library ==(OPTIONAL)== + +==*Add a brief description of how to use this example.*== + +* How to install the Arduino IDE: [Install Arduino IDE](https://github.com/espressif/arduino-esp32/tree/master/docs/arduino-ide). + +### Hardware Connection ==(OPTIONAL)== + +==*Add a brief description of wiring or any other hardware-specific connection.*== + +To use this example, you need to connect the LED to the `GPIOx`. + +SDCard GPIO connection scheme: + +| SDCard Pin | Function | GPIO | +| ----------- | -------- | ------ | +| 1 | CS | GPIO5 | +| 2 | DI/MOSI | GPIO23 | +| 3 | VSS/GND | GND | +| 4 | VDD/3V3 | 3V3 | +| 5 | SCLK | GPIO18 | +| 6 | VSS/GND | GND | +| 7 | DO/MISO | GPIO19 | + +To add images, please create a folder `_asset` inside the example folder to add the relevant images. + +### Configure the Project ==(OPTIONAL)== + +==*Add a brief description of this example here!*== + +Set the LED GPIO by changing the `LED_BUILTIN` value in the function `pinMode(LED_BUILTIN, OUTPUT);`. By default, the GPIO is: `GPIOx`. + +#### Example for the GPIO4: + +==*Add some code explanation if relevant to the example.*== + +```cpp +// the setup function runs once when you press reset or power the board +void setup() { +// initialize digital pin 4 as an output. +pinMode(4, OUTPUT); +} +``` + +#### Using Arduino IDE + +To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits). + +* Before Compile/Verify, select the correct board: `Tools -> Board`. +* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port. + +#### Using Platform IO + +* Select the COM port: `Devices` or set the `upload_port` option on the `platformio.ini` file. + +## Example/Log Output ==(OPTIONAL)== + +==*Add the log/serial output here!*== + +``` +ets Jul 29 2019 12:21:46 + +rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) +configsip: 0, SPIWP:0xee +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:1 +load:0x3fff0030,len:1412 +load:0x40078000,len:13400 +load:0x40080400,len:3672 +entry 0x400805f8 +ESP32 Chip model = ESP32-D0WDQ5 Rev 3 +This chip has 2 cores +Chip ID: 3957392 +``` + +## Troubleshooting ==(REQUIRED)== + +==*Add specific issues you may find by using this example here!*== + +***Important: Make sure you are using a good quality USB cable and that you have a reliable power source*** + +* **LED not blinking:** Check the wiring connection and the IO selection. +* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed. +* **COM port not detected:** Check the USB cable and the USB to Serial driver installation. + +If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute). + +## Contribute ==(REQUIRED)== + +==*Do not change! Keep it as is.*== + +To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst) + +If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome! + +Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else. + +## Resources ==(REQUIRED)== + +==*Do not change here! Keep it as is or add only relevant documents/info for this example. Do not add any purchase link/marketing stuff*== + +* Official ESP32 Forum: [Link](https://esp32.com) +* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) +* ESP32 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf) +* ESP32-S2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf) +* ESP32-C3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf) +* ESP32-S3 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) +* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com) diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Time/SimpleTime/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Time/SimpleTime/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Time/SimpleTime/SimpleTime.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Time/SimpleTime/SimpleTime.ino new file mode 100644 index 0000000..f8b2e43 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Time/SimpleTime/SimpleTime.ino @@ -0,0 +1,78 @@ +#include +#include "time.h" +#include "esp_sntp.h" + +const char* ssid = "YOUR_SSID"; +const char* password = "YOUR_PASS"; + +const char* ntpServer1 = "pool.ntp.org"; +const char* ntpServer2 = "time.nist.gov"; +const long gmtOffset_sec = 3600; +const int daylightOffset_sec = 3600; + +const char* time_zone = "CET-1CEST,M3.5.0,M10.5.0/3"; // TimeZone rule for Europe/Rome including daylight adjustment rules (optional) + +void printLocalTime() +{ + struct tm timeinfo; + if(!getLocalTime(&timeinfo)){ + Serial.println("No time available (yet)"); + return; + } + Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); +} + +// Callback function (get's called when time adjusts via NTP) +void timeavailable(struct timeval *t) +{ + Serial.println("Got time adjustment from NTP!"); + printLocalTime(); +} + +void setup() +{ + Serial.begin(115200); + + // set notification call-back function + sntp_set_time_sync_notification_cb( timeavailable ); + + /** + * NTP server address could be aquired via DHCP, + * + * NOTE: This call should be made BEFORE esp32 aquires IP address via DHCP, + * otherwise SNTP option 42 would be rejected by default. + * NOTE: configTime() function call if made AFTER DHCP-client run + * will OVERRIDE aquired NTP server address + */ + esp_sntp_servermode_dhcp(1);// (optional) + + /** + * This will set configured ntp servers and constant TimeZone/daylightOffset + * should be OK if your time zone does not need to adjust daylightOffset twice a year, + * in such a case time adjustment won't be handled automagicaly. + */ + configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2); + + /** + * A more convenient approach to handle TimeZones with daylightOffset + * would be to specify a environmnet variable with TimeZone definition including daylight adjustmnet rules. + * A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h + */ + //configTzTime(time_zone, ntpServer1, ntpServer2); + + //connect to WiFi + Serial.printf("Connecting to %s ", ssid); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(" CONNECTED"); + +} + +void loop() +{ + delay(5000); + printLocalTime(); // it will take some time to sync time :) +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Timer/RepeatTimer/RepeatTimer.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Timer/RepeatTimer/RepeatTimer.ino new file mode 100644 index 0000000..275cd0f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Timer/RepeatTimer/RepeatTimer.ino @@ -0,0 +1,77 @@ +/* + Repeat timer example + + This example shows how to use hardware timer in ESP32. The timer calls onTimer + function every second. The timer can be stopped with button attached to PIN 0 + (IO0). + + This example code is in the public domain. + */ + +// Stop button is attached to PIN 0 (IO0) +#define BTN_STOP_ALARM 0 + +hw_timer_t * timer = NULL; +volatile SemaphoreHandle_t timerSemaphore; +portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; + +volatile uint32_t isrCounter = 0; +volatile uint32_t lastIsrAt = 0; + +void ARDUINO_ISR_ATTR onTimer(){ + // Increment the counter and set the time of ISR + portENTER_CRITICAL_ISR(&timerMux); + isrCounter = isrCounter + 1; + lastIsrAt = millis(); + portEXIT_CRITICAL_ISR(&timerMux); + // Give a semaphore that we can check in the loop + xSemaphoreGiveFromISR(timerSemaphore, NULL); + // It is safe to use digitalRead/Write here if you want to toggle an output +} + +void setup() { + Serial.begin(115200); + + // Set BTN_STOP_ALARM to input mode + pinMode(BTN_STOP_ALARM, INPUT); + + // Create semaphore to inform us when the timer has fired + timerSemaphore = xSemaphoreCreateBinary(); + + // Set timer frequency to 1Mhz + timer = timerBegin(1000000); + + // Attach onTimer function to our timer. + timerAttachInterrupt(timer, &onTimer); + + // Set alarm to call onTimer function every second (value in microseconds). + // Repeat the alarm (third parameter) with unlimited count = 0 (fourth parameter). + timerAlarm(timer, 1000000, true, 0); +} + +void loop() { + // If Timer has fired + if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){ + uint32_t isrCount = 0, isrTime = 0; + // Read the interrupt count and time + portENTER_CRITICAL(&timerMux); + isrCount = isrCounter; + isrTime = lastIsrAt; + portEXIT_CRITICAL(&timerMux); + // Print it + Serial.print("onTimer no. "); + Serial.print(isrCount); + Serial.print(" at "); + Serial.print(isrTime); + Serial.println(" ms"); + } + // If button is pressed + if (digitalRead(BTN_STOP_ALARM) == LOW) { + // If timer is still running + if (timer) { + // Stop and free timer + timerEnd(timer); + timer = NULL; + } + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Timer/WatchdogTimer/WatchdogTimer.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Timer/WatchdogTimer/WatchdogTimer.ino new file mode 100644 index 0000000..d1a70f8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Timer/WatchdogTimer/WatchdogTimer.ino @@ -0,0 +1,39 @@ +#include "esp_system.h" +#include "rom/ets_sys.h" + +const int button = 0; //gpio to use to trigger delay +const int wdtTimeout = 3000; //time in ms to trigger the watchdog +hw_timer_t * timer = NULL; + +void ARDUINO_ISR_ATTR resetModule() { + ets_printf("reboot\n"); + esp_restart(); +} + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.println("running setup"); + + pinMode(button, INPUT_PULLUP); //init control pin + timer = timerBegin(1000000); //timer 1Mhz resolution + timerAttachInterrupt(timer, &resetModule); //attach callback + timerAlarm(timer, wdtTimeout * 1000, false, 0); //set time in us +} + +void loop() { + Serial.println("running main loop"); + + timerWrite(timer, 0); //reset timer (feed watchdog) + long loopTime = millis(); + //while button is pressed, delay up to 3 seconds to trigger the timer + while (!digitalRead(button)) { + Serial.println("button pressed"); + delay(500); + } + delay(1000); //simulate work + loopTime = millis() - loopTime; + + Serial.print("loop time is = "); + Serial.println(loopTime); //should be under 3000 +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/TouchButton.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/TouchButton.ino new file mode 100644 index 0000000..b1dbc63 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButton/TouchButton.ino @@ -0,0 +1,46 @@ +/* + +This is an example how to use Touch Intrrerupts +The sketh will tell when it is touched and then relesased as like a push-button + +This method based on touchInterruptSetThresholdDirection() is only available for ESP32 +*/ + +#include "Arduino.h" + +int threshold = 40; +bool touchActive = false; +bool lastTouchActive = false; +bool testingLower = true; + +void gotTouchEvent(){ + if (lastTouchActive != testingLower) { + touchActive = !touchActive; + testingLower = !testingLower; + // Touch ISR will be inverted: Lower <--> Higher than the Threshold after ISR event is noticed + touchInterruptSetThresholdDirection(testingLower); + } +} + +void setup() { + Serial.begin(115200); + delay(1000); // give me time to bring up serial monitor + Serial.println("ESP32 Touch Interrupt Test"); + touchAttachInterrupt(T2, gotTouchEvent, threshold); + + // Touch ISR will be activated when touchRead is lower than the Threshold + touchInterruptSetThresholdDirection(testingLower); +} + +void loop(){ + if(lastTouchActive != touchActive){ + lastTouchActive = touchActive; + if (touchActive) { + Serial.println(" ---- Touch was Pressed"); + } else { + Serial.println(" ---- Touch was Released"); + } + } + Serial.printf("T2 pin2 = %d \n", touchRead(T2)); + delay(125); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/TouchButtonV2.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/TouchButtonV2.ino new file mode 100644 index 0000000..9c489c2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchButtonV2/TouchButtonV2.ino @@ -0,0 +1,51 @@ +/* + +This is an example how to use Touch Intrrerupts +The sketh will tell when it is touched and then relesased as like a push-button + +This method based on touchInterruptGetLastStatus() is only available for ESP32 S2 and S3 +*/ + +#include "Arduino.h" + +int threshold = 1500; // ESP32S2 +bool touch1detected = false; +bool touch2detected = false; + +void gotTouch1() { + touch1detected = true; +} + +void gotTouch2() { + touch2detected = true; +} + +void setup() { + Serial.begin(115200); + delay(1000); // give me time to bring up serial monitor + + Serial.println("\n ESP32 Touch Interrupt Test\n"); + touchAttachInterrupt(T1, gotTouch1, threshold); + touchAttachInterrupt(T2, gotTouch2, threshold); +} + +void loop() { + if (touch1detected) { + touch1detected = false; + if (touchInterruptGetLastStatus(T1)) { + Serial.println(" --- T1 Touched"); + } else { + Serial.println(" --- T1 Released"); + } + } + if (touch2detected) { + touch2detected = false; + if (touchInterruptGetLastStatus(T2)) { + Serial.println(" --- T2 Touched"); + } else { + Serial.println(" --- T2 Released"); + } + } + + delay(80); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino new file mode 100644 index 0000000..20bee46 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchInterrupt/TouchInterrupt.ino @@ -0,0 +1,35 @@ +/* +This is an example how to use Touch Intrrerupts +The bigger the threshold, the more sensible is the touch +*/ + +int threshold = 40; +bool touch1detected = false; +bool touch2detected = false; + +void gotTouch1(){ + touch1detected = true; +} + +void gotTouch2(){ + touch2detected = true; +} + +void setup() { + Serial.begin(115200); + delay(1000); // give me time to bring up serial monitor + Serial.println("ESP32 Touch Interrupt Test"); + touchAttachInterrupt(T2, gotTouch1, threshold); + touchAttachInterrupt(T3, gotTouch2, threshold); +} + +void loop(){ + if(touch1detected){ + touch1detected = false; + Serial.println("Touch 1 detected"); + } + if(touch2detected){ + touch2detected = false; + Serial.println("Touch 2 detected"); + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/TouchRead.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/TouchRead.ino new file mode 100644 index 0000000..57312c6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/examples/Touch/TouchRead/TouchRead.ino @@ -0,0 +1,15 @@ +// ESP32 Touch Test +// Just test touch pin - Touch0 is T0 which is on GPIO 4. + +void setup() +{ + Serial.begin(115200); + delay(1000); // give me time to bring up serial monitor + Serial.println("ESP32 Touch Test"); +} + +void loop() +{ + Serial.println(touchRead(T1)); // get value using T0 + delay(1000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/keywords.txt new file mode 100644 index 0000000..631ad8f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/keywords.txt @@ -0,0 +1,17 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + +RGB_BUILTIN LITERAL1 \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/library.properties new file mode 100644 index 0000000..c928bcf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/library.properties @@ -0,0 +1,9 @@ +name=ESP32 +version=2.0.0 +author=Hristo Gochkov, Ivan Grokhtkov +maintainer=Hristo Gochkov +sentence=ESP32 sketches examples +paragraph= +category=Other +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/src/dummy.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/src/dummy.h new file mode 100644 index 0000000..d8a140e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESP32/src/dummy.h @@ -0,0 +1,2 @@ +// This file is here only to silence warnings from Arduino IDE +// Currently IDE doesn't support no-code libraries, like this collection of example sketches. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS-SD_Extended/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS-SD_Extended/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino new file mode 100644 index 0000000..6f2dfdd --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino @@ -0,0 +1,80 @@ +/* + ESP8266 mDNS-SD responder and query sample + + This is an example of announcing and finding services. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to two ESP8266 boards + - The last one powered on should now find the other. + */ + +#include +#include + +const char* ssid = "..."; +const char* password = "..."; + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(250); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (!MDNS.begin("ESP32_Browser")) { + Serial.println("Error setting up MDNS responder!"); + while(1){ + delay(1000); + } + } +} + +void loop() { + browseService("http", "tcp"); + delay(1000); + browseService("arduino", "tcp"); + delay(1000); + browseService("workstation", "tcp"); + delay(1000); + browseService("smb", "tcp"); + delay(1000); + browseService("afpovertcp", "tcp"); + delay(1000); + browseService("ftp", "tcp"); + delay(1000); + browseService("ipp", "tcp"); + delay(1000); + browseService("printer", "tcp"); + delay(10000); +} + +void browseService(const char * service, const char * proto){ + Serial.printf("Browsing for service _%s._%s.local. ... ", service, proto); + int n = MDNS.queryService(service, proto); + if (n == 0) { + Serial.println("no services found"); + } else { + Serial.print(n); + Serial.println(" service(s) found"); + for (int i = 0; i < n; ++i) { + // Print details for each service found + Serial.print(" "); + Serial.print(i + 1); + Serial.print(": "); + Serial.print(MDNS.hostname(i)); + Serial.print(" ("); + Serial.print(MDNS.IP(i)); + Serial.print(":"); + Serial.print(MDNS.port(i)); + Serial.println(")"); + } + } + Serial.println(); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS_Web_Server/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS_Web_Server/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino new file mode 100644 index 0000000..946f51a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino @@ -0,0 +1,120 @@ +/* + ESP32 mDNS responder sample + + This is an example of an HTTP server that is accessible + via http://esp32.local URL thanks to mDNS responder. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP32 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Point your browser to http://esp32.local, you should see a response. + + */ + + +#include +#include +#include + +const char* ssid = "............"; +const char* password = ".............."; + +// TCP server at port 80 will respond to HTTP requests +WiFiServer server(80); + +void setup(void) +{ + Serial.begin(115200); + + // Connect to WiFi network + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Set up mDNS responder: + // - first argument is the domain name, in this example + // the fully-qualified domain name is "esp32.local" + // - second argument is the IP address to advertise + // we send our IP address on the WiFi network + if (!MDNS.begin("esp32")) { + Serial.println("Error setting up MDNS responder!"); + while(1) { + delay(1000); + } + } + Serial.println("mDNS responder started"); + + // Start TCP (HTTP) server + server.begin(); + Serial.println("TCP server started"); + + // Add service to MDNS-SD + MDNS.addService("http", "tcp", 80); +} + +void loop(void) +{ + // Check if a client has connected + WiFiClient client = server.available(); + if (!client) { + return; + } + Serial.println(""); + Serial.println("New client"); + + // Wait for data from client to become available + while(client.connected() && !client.available()){ + delay(1); + } + + // Read the first line of HTTP request + String req = client.readStringUntil('\r'); + + // First line of HTTP request looks like "GET /path HTTP/1.1" + // Retrieve the "/path" part by finding the spaces + int addr_start = req.indexOf(' '); + int addr_end = req.indexOf(' ', addr_start + 1); + if (addr_start == -1 || addr_end == -1) { + Serial.print("Invalid request: "); + Serial.println(req); + return; + } + req = req.substring(addr_start + 1, addr_end); + Serial.print("Request: "); + Serial.println(req); + + String s; + if (req == "/") + { + IPAddress ip = WiFi.localIP(); + String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]); + s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\nHello from ESP32 at "; + s += ipStr; + s += "\r\n\r\n"; + Serial.println("Sending 200"); + } + else + { + s = "HTTP/1.1 404 Not Found\r\n\r\n"; + Serial.println("Sending 404"); + } + client.print(s); + + client.stop(); + Serial.println("Done with client"); +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/keywords.txt new file mode 100644 index 0000000..c012cb5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/keywords.txt @@ -0,0 +1,25 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ESPmDNS KEYWORD1 +MDNS KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +addService KEYWORD2 +enableArduino KEYWORD2 +disableArduino KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/library.properties new file mode 100644 index 0000000..6f1281a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/library.properties @@ -0,0 +1,9 @@ +name=ESPmDNS +version=2.0.0 +author=Hristo Gochkov, Ivan Grokhtkov +maintainer=Hristo Gochkov +sentence=ESP32 mDNS Library +paragraph= +category=Communication +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/src/ESPmDNS.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/src/ESPmDNS.cpp new file mode 100644 index 0000000..bccc4de --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/src/ESPmDNS.cpp @@ -0,0 +1,360 @@ +/* + +ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) +Version 1.1 +Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) +ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) +MDNS-SD Suport 2015 Hristo Gochkov (hristo@espressif.com) +Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) + + +License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + */ + +// Important RFC's for reference: +// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt +// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt +// - MDNS-SD: https://tools.ietf.org/html/rfc6763 + +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +#include "ESPmDNS.h" +#include "WiFi.h" +#include +#include "esp_wifi.h" +#include "esp_wifi_types.h" + +// Add quotes around defined value +#ifdef __IN_ECLIPSE__ +#define STR_EXPAND(tok) #tok +#define STR(tok) STR_EXPAND(tok) +#else +#define STR(tok) tok +#endif + +// static void _on_sys_event(arduino_event_t *event){ +// mdns_handle_system_event(NULL, event); +// } + +MDNSResponder::MDNSResponder() :results(NULL) {} +MDNSResponder::~MDNSResponder() { + end(); +} + +bool MDNSResponder::begin(const String& hostName){ + if(mdns_init()){ + log_e("Failed starting MDNS"); + return false; + } + //WiFi.onEvent(_on_sys_event); + _hostname = hostName; + _hostname.toLowerCase(); + if(mdns_hostname_set(hostName.c_str())) { + log_e("Failed setting MDNS hostname"); + return false; + } + return true; +} + +void MDNSResponder::end() { + mdns_free(); +} + +void MDNSResponder::setInstanceName(String name) { + if (name.length() > 63) return; + if(mdns_instance_name_set(name.c_str())){ + log_e("Failed setting MDNS instance"); + return; + } +} + + +void MDNSResponder::enableArduino(uint16_t port, bool auth){ + mdns_txt_item_t arduTxtData[4] = { + {(char*)"board" ,(char*)STR(ARDUINO_VARIANT)}, + {(char*)"tcp_check" ,(char*)"no"}, + {(char*)"ssh_upload" ,(char*)"no"}, + {(char*)"auth_upload" ,(char*)"no"} + }; + + if(mdns_service_add(NULL, "_arduino", "_tcp", port, arduTxtData, 4)) { + log_e("Failed adding Arduino service"); + } + + if(auth && mdns_service_txt_item_set("_arduino", "_tcp", "auth_upload", "yes")){ + log_e("Failed setting Arduino txt item"); + } +} + +void MDNSResponder::disableArduino(){ + if(mdns_service_remove("_arduino", "_tcp")) { + log_w("Failed removing Arduino service"); + } +} + +void MDNSResponder::enableWorkstation(esp_interface_t interface){ + char winstance[21+_hostname.length()]; + uint8_t mac[6]; + esp_wifi_get_mac((wifi_interface_t)interface, mac); + sprintf(winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", _hostname.c_str(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + if(mdns_service_add(NULL, "_workstation", "_tcp", 9, NULL, 0)) { + log_e("Failed adding Workstation service"); + } else if(mdns_service_instance_name_set("_workstation", "_tcp", winstance)) { + log_e("Failed setting Workstation service instance name"); + } +} + +void MDNSResponder::disableWorkstation(){ + if(mdns_service_remove("_workstation", "_tcp")) { + log_w("Failed removing Workstation service"); + } +} + +bool MDNSResponder::addService(char *name, char *proto, uint16_t port){ + char _name[strlen(name)+2]; + char _proto[strlen(proto)+2]; + if (name[0] == '_') { + sprintf(_name, "%s", name); + } else { + sprintf(_name, "_%s", name); + } + if (proto[0] == '_') { + sprintf(_proto, "%s", proto); + } else { + sprintf(_proto, "_%s", proto); + } + + if(mdns_service_add(NULL, _name, _proto, port, NULL, 0)) { + log_e("Failed adding service %s.%s.\n", name, proto); + return false; + } + return true; +} + +bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *value){ + char _name[strlen(name)+2]; + char _proto[strlen(proto)+2]; + if (name[0] == '_') { + sprintf(_name, "%s", name); + } else { + sprintf(_name, "_%s", name); + } + if (proto[0] == '_') { + sprintf(_proto, "%s", proto); + } else { + sprintf(_proto, "_%s", proto); + } + + if(mdns_service_txt_item_set(_name, _proto, key, value)) { + log_e("Failed setting service TXT"); + return false; + } + return true; +} + +IPAddress MDNSResponder::queryHost(char *host, uint32_t timeout){ + esp_ip4_addr_t addr; + addr.addr = 0; + + esp_err_t err = mdns_query_a(host, timeout, &addr); + if(err){ + if(err == ESP_ERR_NOT_FOUND){ + log_w("Host was not found!"); + return IPAddress(); + } + log_e("Query Failed"); + return IPAddress(); + } + return IPAddress(addr.addr); +} + + +int MDNSResponder::queryService(char *service, char *proto) { + if(!service || !service[0] || !proto || !proto[0]){ + log_e("Bad Parameters"); + return 0; + } + + if(results){ + mdns_query_results_free(results); + results = NULL; + } + + char srv[strlen(service)+2]; + char prt[strlen(proto)+2]; + if (service[0] == '_') { + sprintf(srv, "%s", service); + } else { + sprintf(srv, "_%s", service); + } + if (proto[0] == '_') { + sprintf(prt, "%s", proto); + } else { + sprintf(prt, "_%s", proto); + } + + esp_err_t err = mdns_query_ptr(srv, prt, 3000, 20, &results); + if(err){ + log_e("Query Failed"); + return 0; + } + if(!results){ + log_w("No results found!"); + return 0; + } + + mdns_result_t * r = results; + int i = 0; + while(r){ + i++; + r = r->next; + } + return i; +} + +mdns_result_t * MDNSResponder::_getResult(int idx){ + mdns_result_t * result = results; + int i = 0; + while(result){ + if(i == idx){ + break; + } + i++; + result = result->next; + } + return result; +} + +mdns_txt_item_t * MDNSResponder::_getResultTxt(int idx, int txtIdx){ + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return NULL; + } + if (txtIdx >= result->txt_count) return NULL; + return &result->txt[txtIdx]; +} + +String MDNSResponder::hostname(int idx) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return String(); + } + return String(result->hostname); +} + +IPAddress MDNSResponder::IP(int idx) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return IPAddress(); + } + mdns_ip_addr_t * addr = result->addr; + while(addr){ + if(addr->addr.type == MDNS_IP_PROTOCOL_V4){ + return IPAddress(addr->addr.u_addr.ip4.addr); + } + addr = addr->next; + } + return IPAddress(); +} + +IPv6Address MDNSResponder::IPv6(int idx) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return IPv6Address(); + } + mdns_ip_addr_t * addr = result->addr; + while(addr){ + if(addr->addr.type == MDNS_IP_PROTOCOL_V6){ + return IPv6Address(addr->addr.u_addr.ip6.addr); + } + addr = addr->next; + } + return IPv6Address(); +} + +uint16_t MDNSResponder::port(int idx) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return 0; + } + return result->port; +} + +int MDNSResponder::numTxt(int idx) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return 0; + } + return result->txt_count; +} + +bool MDNSResponder::hasTxt(int idx, const char * key) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return false; + } + int i = 0; + while(i < result->txt_count) { + if (strcmp(result->txt[i].key, key) == 0) return true; + i++; + } + return false; +} + +String MDNSResponder::txt(int idx, const char * key) { + mdns_result_t * result = _getResult(idx); + if(!result){ + log_e("Result %d not found", idx); + return ""; + } + int i = 0; + while(i < result->txt_count) { + if (strcmp(result->txt[i].key, key) == 0) return result->txt[i].value; + i++; + } + return ""; +} + +String MDNSResponder::txt(int idx, int txtIdx) { + mdns_txt_item_t * resultTxt = _getResultTxt(idx, txtIdx); + return !resultTxt + ? "" + : resultTxt->value; +} + +String MDNSResponder::txtKey(int idx, int txtIdx) { + mdns_txt_item_t * resultTxt = _getResultTxt(idx, txtIdx); + return !resultTxt + ? "" + : resultTxt->key; +} + +MDNSResponder MDNS; diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/src/ESPmDNS.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/src/ESPmDNS.h new file mode 100644 index 0000000..6a5cb56 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/ESPmDNS/src/ESPmDNS.h @@ -0,0 +1,129 @@ +/* +ESP8266 Multicast DNS (port of CC3000 Multicast DNS library) +Version 1.1 +Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) +ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com) +MDNS-SD Suport 2015 Hristo Gochkov (hristo@espressif.com) +Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com) +Rewritten for ESP32 by Hristo Gochkov (hristo@espressif.com) + +This is a simple implementation of multicast DNS query support for an Arduino +running on ESP32 chip. + +Usage: +- Include the ESP32 Multicast DNS library in the sketch. +- Call the begin method in the sketch's setup and provide a domain name (without + the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the + Adafruit CC3000 class instance. Optionally provide a time to live (in seconds) + for the DNS record--the default is 1 hour. +- Call the update method in each iteration of the sketch's loop function. + +License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ +#ifndef ESP32MDNS_H +#define ESP32MDNS_H + +#include "Arduino.h" +#include "IPv6Address.h" +#include "mdns.h" +#include "esp_interface.h" + +//this should be defined at build time +#ifndef ARDUINO_VARIANT +#define ARDUINO_VARIANT "esp32" +#endif + +class MDNSResponder { +public: + MDNSResponder(); + ~MDNSResponder(); + bool begin(const String& hostName); + bool begin(const char* hostName){ + return begin(String(hostName)); + } + void end(); + + void setInstanceName(String name); + void setInstanceName(const char * name){ + setInstanceName(String(name)); + } + void setInstanceName(char * name){ + setInstanceName(String(name)); + } + + bool addService(char *service, char *proto, uint16_t port); + bool addService(const char *service, const char *proto, uint16_t port){ + return addService((char *)service, (char *)proto, port); + } + bool addService(String service, String proto, uint16_t port){ + return addService(service.c_str(), proto.c_str(), port); + } + + bool addServiceTxt(char *name, char *proto, char * key, char * value); + void addServiceTxt(const char *name, const char *proto, const char *key,const char * value){ + addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value); + } + void addServiceTxt(String name, String proto, String key, String value){ + addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str()); + } + + void enableArduino(uint16_t port=3232, bool auth=false); + void disableArduino(); + + void enableWorkstation(esp_interface_t interface=ESP_IF_WIFI_STA); + void disableWorkstation(); + + IPAddress queryHost(char *host, uint32_t timeout=2000); + IPAddress queryHost(const char *host, uint32_t timeout=2000){ + return queryHost((char *)host, timeout); + } + IPAddress queryHost(String host, uint32_t timeout=2000){ + return queryHost(host.c_str(), timeout); + } + + int queryService(char *service, char *proto); + int queryService(const char *service, const char *proto){ + return queryService((char *)service, (char *)proto); + } + int queryService(String service, String proto){ + return queryService(service.c_str(), proto.c_str()); + } + + String hostname(int idx); + IPAddress IP(int idx); + IPv6Address IPv6(int idx); + uint16_t port(int idx); + int numTxt(int idx); + bool hasTxt(int idx, const char * key); + String txt(int idx, const char * key); + String txt(int idx, int txtIdx); + String txtKey(int idx, int txtIdx); + +private: + String _hostname; + mdns_result_t * results; + mdns_result_t * _getResult(int idx); + mdns_txt_item_t * _getResultTxt(int idx, int txtIdx); +}; + +extern MDNSResponder MDNS; + +#endif //ESP32MDNS_H diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino new file mode 100644 index 0000000..8622639 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_LAN8720/ETH_LAN8720.ino @@ -0,0 +1,86 @@ +/* + This sketch shows the Ethernet event usage + +*/ + +// Important to be defined BEFORE including ETH.h for ETH.begin() to work. +// Example RMII LAN8720 (Olimex, etc.) +#define ETH_PHY_TYPE ETH_PHY_LAN8720 +#define ETH_PHY_ADDR 0 +#define ETH_PHY_MDC 23 +#define ETH_PHY_MDIO 18 +#define ETH_PHY_POWER -1 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN + +#include + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname("esp32-ethernet"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.println("ETH Got IP"); + ETH.printInfo(Serial); + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) +{ + Serial.print("\nconnecting to "); + Serial.println(host); + + WiFiClient client; + if (!client.connect(host, port)) { + Serial.println("connection failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + Serial.write(client.read()); + } + + Serial.println("closing connection\n"); + client.stop(); +} + +void setup() +{ + Serial.begin(115200); + WiFi.onEvent(onEvent); + ETH.begin(); +} + + +void loop() +{ + if (eth_connected) { + testClient("google.com", 80); + } + delay(10000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32s3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/.skip.esp32s3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino new file mode 100644 index 0000000..9558889 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_TLK110/ETH_TLK110.ino @@ -0,0 +1,84 @@ +/* + This sketch shows the Ethernet event usage + +*/ + +#include + +#define ETH_TYPE ETH_PHY_TLK110 +#define ETH_ADDR 31 +#define ETH_MDC_PIN 23 +#define ETH_MDIO_PIN 18 +#define ETH_POWER_PIN 17 +#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname("esp32-ethernet"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.println("ETH Got IP"); + ETH.printInfo(Serial); + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) +{ + Serial.print("\nconnecting to "); + Serial.println(host); + + WiFiClient client; + if (!client.connect(host, port)) { + Serial.println("connection failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + Serial.write(client.read()); + } + + Serial.println("closing connection\n"); + client.stop(); +} + +void setup() +{ + Serial.begin(115200); + WiFi.onEvent(onEvent); + ETH.begin(ETH_TYPE, ETH_ADDR, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_POWER_PIN, ETH_CLK_MODE); +} + + +void loop() +{ + if (eth_connected) { + testClient("google.com", 80); + } + delay(10000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino new file mode 100644 index 0000000..0b7e3cf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_Arduino_SPI/ETH_W5500_Arduino_SPI.ino @@ -0,0 +1,110 @@ +/* + This sketch shows the Ethernet event usage + +*/ + +#include +#include + +// Set this to 1 to enable dual Ethernet support +#define USE_TWO_ETH_PORTS 0 + +#define ETH_TYPE ETH_PHY_W5500 +#define ETH_ADDR 1 +#define ETH_CS 15 +#define ETH_IRQ 4 +#define ETH_RST 5 + +// SPI pins +#define ETH_SPI_SCK 14 +#define ETH_SPI_MISO 12 +#define ETH_SPI_MOSI 13 + +#if USE_TWO_ETH_PORTS +// Second port on shared SPI bus +#define ETH1_TYPE ETH_PHY_W5500 +#define ETH1_ADDR 1 +#define ETH1_CS 32 +#define ETH1_IRQ 33 +#define ETH1_RST 18 +ETHClass ETH1(1); +#endif + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname("esp32-eth0"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); + ETH.printInfo(Serial); +#if USE_TWO_ETH_PORTS + ETH1.printInfo(Serial); +#endif + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) +{ + Serial.print("\nconnecting to "); + Serial.println(host); + + WiFiClient client; + if (!client.connect(host, port)) { + Serial.println("connection failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + Serial.write(client.read()); + } + + Serial.println("closing connection\n"); + client.stop(); +} + +void setup() +{ + Serial.begin(115200); + WiFi.onEvent(onEvent); + + SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI); + ETH.begin(ETH_TYPE, ETH_ADDR, ETH_CS, ETH_IRQ, ETH_RST, SPI); +#if USE_TWO_ETH_PORTS + ETH1.begin(ETH1_TYPE, ETH1_ADDR, ETH1_CS, ETH1_IRQ, ETH1_RST, SPI); +#endif +} + + +void loop() +{ + if (eth_connected) { + testClient("google.com", 80); + } + delay(10000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino new file mode 100644 index 0000000..d68b3e1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/examples/ETH_W5500_IDF_SPI/ETH_W5500_IDF_SPI.ino @@ -0,0 +1,107 @@ +/* + This sketch shows the Ethernet event usage + +*/ + +#include + +// Set this to 1 to enable dual Ethernet support +#define USE_TWO_ETH_PORTS 0 + +#define ETH_TYPE ETH_PHY_W5500 +#define ETH_ADDR 1 +#define ETH_CS 15 +#define ETH_IRQ 4 +#define ETH_RST 5 +#define ETH_SPI_HOST SPI2_HOST +#define ETH_SPI_SCK 14 +#define ETH_SPI_MISO 12 +#define ETH_SPI_MOSI 13 + +#if USE_TWO_ETH_PORTS +// Second port on shared SPI bus +#define ETH1_TYPE ETH_PHY_W5500 +#define ETH1_ADDR 1 +#define ETH1_CS 32 +#define ETH1_IRQ 33 +#define ETH1_RST 18 +ETHClass ETH1(1); +#endif + +static bool eth_connected = false; + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + //set eth hostname here + ETH.setHostname("esp32-eth0"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.printf("ETH Got IP: '%s'\n", esp_netif_get_desc(info.got_ip.esp_netif)); + ETH.printInfo(Serial); +#if USE_TWO_ETH_PORTS + ETH1.printInfo(Serial); +#endif + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_LOST_IP: + Serial.println("ETH Lost IP"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) +{ + Serial.print("\nconnecting to "); + Serial.println(host); + + WiFiClient client; + if (!client.connect(host, port)) { + Serial.println("connection failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + Serial.write(client.read()); + } + + Serial.println("closing connection\n"); + client.stop(); +} + +void setup() +{ + Serial.begin(115200); + WiFi.onEvent(onEvent); + ETH.begin(ETH_TYPE, ETH_ADDR, ETH_CS, ETH_IRQ, ETH_RST, ETH_SPI_HOST, ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI); +#if USE_TWO_ETH_PORTS + // Since SPI bus is shared, we should skip the SPI pins when calling ETH1.begin() + ETH1.begin(ETH1_TYPE, ETH1_ADDR, ETH1_CS, ETH1_IRQ, ETH1_RST, ETH_SPI_HOST); +#endif +} + + +void loop() +{ + if (eth_connected) { + testClient("google.com", 80); + } + delay(10000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/library.properties new file mode 100644 index 0000000..c32adf1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/library.properties @@ -0,0 +1,9 @@ +name=Ethernet +version=2.0.0 +author=Hristo Gochkov +maintainer=Hristo Gochkov +sentence=Enables network connection (local and Internet) using the ESP32 Ethernet. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through Ethernet. The IP address can be assigned statically or through a DHCP. The library can also manage DNS. +category=Communication +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/src/ETH.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/src/ETH.cpp new file mode 100644 index 0000000..b0a80fd --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/src/ETH.cpp @@ -0,0 +1,1248 @@ +/* + ETH.h - espre ETH PHY support. + Based on WiFi.h from Arduino WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ETH.h" +#include "esp_system.h" +#include "esp_event.h" +#include "esp_eth.h" +#include "esp_eth_mac.h" +#include "esp_eth_com.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#if CONFIG_ETH_USE_ESP32_EMAC +#include "soc/emac_ext_struct.h" +#include "soc/rtc.h" +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +#include "esp32-hal-periman.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include "esp_netif_types.h" +#include "esp_netif_defaults.h" +#include "esp_eth_phy.h" + +extern void tcpipInit(); +extern void add_esp_interface_netif(esp_interface_t interface, esp_netif_t *esp_netif); /* from WiFiGeneric */ + +ETHClass::ETHClass(uint8_t eth_index) + : _eth_started(false), _eth_handle(NULL), _esp_netif(NULL), _eth_index(eth_index), _phy_type(ETH_PHY_MAX) +#if ETH_SPI_SUPPORTS_CUSTOM + , + _spi(NULL) +#endif + , + _spi_freq_mhz(20), _pin_cs(-1), _pin_irq(-1), _pin_rst(-1), _pin_sck(-1), _pin_miso(-1), _pin_mosi(-1) +#if CONFIG_ETH_USE_ESP32_EMAC + , + _pin_mcd(-1), _pin_mdio(-1), _pin_power(-1), _pin_rmii_clock(-1) +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +{ +} + +ETHClass::~ETHClass() +{ +} + +bool ETHClass::ethDetachBus(void *bus_pointer) +{ + ETHClass *bus = (ETHClass *)bus_pointer; + if (bus->_eth_started) + { + bus->end(); + } + return true; +} + +#if CONFIG_ETH_USE_ESP32_EMAC +bool ETHClass::begin(eth_phy_type_t type, uint8_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clock_mode) +{ + esp_err_t ret = ESP_OK; + if (_esp_netif != NULL) + { + return true; + } + perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET, ETHClass::ethDetachBus); + + tcpipInit(); + + eth_esp32_emac_config_t mac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); + mac_config.clock_config.rmii.clock_mode = (clock_mode) ? EMAC_CLK_OUT : EMAC_CLK_EXT_IN; + mac_config.clock_config.rmii.clock_gpio = (1 == clock_mode) ? EMAC_APPL_CLK_OUT_GPIO : (2 == clock_mode) ? EMAC_CLK_OUT_GPIO + : (3 == clock_mode) ? EMAC_CLK_OUT_180_GPIO + : EMAC_CLK_IN_GPIO; + mac_config.smi_mdc_gpio_num = mdc; + mac_config.smi_mdio_gpio_num = mdio; + + _pin_mcd = mdc; + _pin_mdio = mdio; + _pin_rmii_clock = mac_config.clock_config.rmii.clock_gpio; + _pin_power = power; + + if (!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (!perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + if (_pin_power != -1) + { + if (!perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + + eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG(); + eth_mac_config.sw_reset_timeout_ms = 1000; + + esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config, ð_mac_config); + if (mac == NULL) + { + log_e("esp_eth_mac_new_esp32 failed"); + return false; + } + + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.phy_addr = phy_addr; + phy_config.reset_gpio_num = power; + + esp_eth_phy_t *phy = NULL; + switch (type) + { + case ETH_PHY_LAN8720: + phy = esp_eth_phy_new_lan87xx(&phy_config); + break; + case ETH_PHY_TLK110: + phy = esp_eth_phy_new_ip101(&phy_config); + break; + case ETH_PHY_RTL8201: + phy = esp_eth_phy_new_rtl8201(&phy_config); + break; + case ETH_PHY_DP83848: + phy = esp_eth_phy_new_dp83848(&phy_config); + break; + case ETH_PHY_KSZ8041: + phy = esp_eth_phy_new_ksz80xx(&phy_config); + break; + case ETH_PHY_KSZ8081: + phy = esp_eth_phy_new_ksz80xx(&phy_config); + break; + default: + log_e("Unsupported PHY %d", type); + break; + } + if (phy == NULL) + { + log_e("esp_eth_phy_new failed"); + return false; + } + + _eth_handle = NULL; + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + ret = esp_eth_driver_install(ð_config, &_eth_handle); + if (ret != ESP_OK) + { + log_e("SPI Ethernet driver install failed: %d", ret); + return false; + } + if (_eth_handle == NULL) + { + log_e("esp_eth_driver_install failed! eth_handle is NULL"); + return false; + } + + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + + // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify + // esp-netif configuration parameters for each interface (name, priority, etc.). + char if_key_str[10]; + char if_desc_str[10]; + char num_str[3]; + itoa(_eth_index, num_str, 10); + strcat(strcpy(if_key_str, "ETH_"), num_str); + strcat(strcpy(if_desc_str, "eth"), num_str); + + esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); + esp_netif_config.if_key = if_key_str; + esp_netif_config.if_desc = if_desc_str; + esp_netif_config.route_prio -= _eth_index * 5; + + cfg.base = &esp_netif_config; + + _esp_netif = esp_netif_new(&cfg); + + /* attach Ethernet driver to TCP/IP stack */ + ret = esp_netif_attach(_esp_netif, esp_eth_new_netif_glue(_eth_handle)); + if (ret != ESP_OK) + { + log_e("esp_netif_attach failed: %d", ret); + return false; + } + + /* attach to WiFiGeneric to receive events */ + add_esp_interface_netif(ESP_IF_ETH, _esp_netif); + + ret = esp_eth_start(_eth_handle); + if (ret != ESP_OK) + { + log_e("esp_eth_start failed: %d", ret); + return false; + } + _eth_started = true; + + if (!perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + + if (!perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + if (!perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + + if (_pin_power != -1) + { + if (!perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + } + // holds a few milliseconds to let DHCP start and enter into a good state + // FIX ME -- adresses issue https://github.com/espressif/arduino-esp32/issues/5733 + delay(50); + + return true; + +err: + log_e("Failed to set all pins bus to ETHERNET"); + ETHClass::ethDetachBus((void *)(this)); + return false; +} +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + +#if ETH_SPI_SUPPORTS_CUSTOM +static void *_eth_spi_init(const void *ctx) +{ + return (void *)ctx; +} + +static esp_err_t _eth_spi_deinit(void *ctx) +{ + return ESP_OK; +} + +esp_err_t ETHClass::_eth_spi_read(void *ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len) +{ + return ((ETHClass *)ctx)->eth_spi_read(cmd, addr, data, data_len); +} + +esp_err_t ETHClass::_eth_spi_write(void *ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len) +{ + return ((ETHClass *)ctx)->eth_spi_write(cmd, addr, data, data_len); +} + +esp_err_t ETHClass::eth_spi_read(uint32_t cmd, uint32_t addr, void *data, uint32_t data_len) +{ + if (_spi == NULL) + { + return ESP_FAIL; + } + // log_i(" 0x%04lx 0x%04lx %lu", cmd, addr, data_len); + _spi->beginTransaction(SPISettings(_spi_freq_mhz * 1000 * 1000, MSBFIRST, SPI_MODE0)); + digitalWrite(_pin_cs, LOW); + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if (_phy_type == ETH_PHY_DM9051) + { + _spi->write(((cmd & 0x01) << 7) | (addr & 0x7F)); + } + else +#endif +#if CONFIG_ETH_SPI_ETHERNET_W5500 + if (_phy_type == ETH_PHY_W5500) + { + _spi->write16(cmd); + _spi->write(addr); + } + else +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + if (_phy_type == ETH_PHY_KSZ8851) + { + if (cmd > 1) + { + _spi->write(cmd << 6 | addr); + } + else + { + _spi->write16(cmd << 14 | addr); + } + } + else +#endif + { + log_e("Unsupported PHY module: %d", _phy_type); + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_FAIL; + } + _spi->transferBytes(NULL, (uint8_t *)data, data_len); + + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_OK; +} + +esp_err_t ETHClass::eth_spi_write(uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len) +{ + if (_spi == NULL) + { + return ESP_FAIL; + } + // log_i("0x%04lx 0x%04lx %lu", cmd, addr, data_len); + _spi->beginTransaction(SPISettings(_spi_freq_mhz * 1000 * 1000, MSBFIRST, SPI_MODE0)); + digitalWrite(_pin_cs, LOW); + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if (_phy_type == ETH_PHY_DM9051) + { + _spi->write(((cmd & 0x01) << 7) | (addr & 0x7F)); + } + else +#endif +#if CONFIG_ETH_SPI_ETHERNET_W5500 + if (_phy_type == ETH_PHY_W5500) + { + _spi->write16(cmd); + _spi->write(addr); + } + else +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + if (_phy_type == ETH_PHY_KSZ8851) + { + if (cmd > 1) + { + _spi->write(cmd << 6 | addr); + } + else + { + _spi->write16(cmd << 14 | addr); + } + } + else +#endif + { + log_e("Unsupported PHY module: %d", _phy_type); + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_FAIL; + } + _spi->writeBytes((const uint8_t *)data, data_len); + + digitalWrite(_pin_cs, HIGH); + _spi->endTransaction(); + return ESP_OK; +} +#endif + +bool ETHClass::beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, +#if ETH_SPI_SUPPORTS_CUSTOM + SPIClass *spi, +#endif + int sck, int miso, int mosi, spi_host_device_t spi_host, uint8_t spi_freq_mhz) +{ + esp_err_t ret = ESP_OK; + + if (_eth_started || _esp_netif != NULL || _eth_handle != NULL) + { + log_w("ETH Already Started"); + return true; + } + if (cs < 0 || irq < 0) + { + log_e("CS and IRQ pins must be defined!"); + return false; + } + + perimanSetBusDeinit(ESP32_BUS_TYPE_ETHERNET, ETHClass::ethDetachBus); + + if (_pin_cs != -1) + { + if (!perimanSetPinBus(_pin_cs, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + if (_pin_rst != -1) + { + if (!perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + if (_pin_irq != -1) + { + if (!perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + if (_pin_sck != -1) + { + if (!perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + if (_pin_miso != -1) + { + if (!perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + if (_pin_mosi != -1) + { + if (!perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_INIT, NULL)) + { + return false; + } + } + +#if ETH_SPI_SUPPORTS_CUSTOM + _spi = spi; +#endif + if (spi_freq_mhz) + { + _spi_freq_mhz = spi_freq_mhz; + } + _phy_type = type; + _pin_cs = cs; + _pin_irq = irq; + _pin_rst = rst; + _pin_sck = sck; + _pin_miso = miso; + _pin_mosi = mosi; + +#if ETH_SPI_SUPPORTS_CUSTOM + if (_spi != NULL) + { + pinMode(_pin_cs, OUTPUT); + digitalWrite(_pin_cs, HIGH); + } +#endif + + // Init SPI bus + if (_pin_sck >= 0 && _pin_miso >= 0 && _pin_mosi >= 0) + { + spi_bus_config_t buscfg = { + .mosi_io_num = _pin_mosi, + .miso_io_num = _pin_miso, + .sclk_io_num = _pin_sck, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO); + if (ret != ESP_OK) + { + log_e("SPI bus initialize failed: %d", ret); + return false; + } + } + + tcpipInit(); + + // Install GPIO ISR handler to be able to service SPI Eth modules interrupts + ret = gpio_install_isr_service(0); + if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) + { + log_e("GPIO ISR handler install failed: %d", ret); + return false; + } + + // Init common MAC and PHY configs to default + eth_mac_config_t eth_mac_config = ETH_MAC_DEFAULT_CONFIG(); + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + + // Update PHY config based on board specific configuration + phy_config.phy_addr = phy_addr; + phy_config.reset_gpio_num = _pin_rst; + + // Configure SPI interface for specific SPI module + spi_device_interface_config_t spi_devcfg = { + .mode = 0, + .clock_speed_hz = _spi_freq_mhz * 1000 * 1000, + .input_delay_ns = 20, + .spics_io_num = _pin_cs, + .queue_size = 20, + }; + + esp_eth_mac_t *mac = NULL; + esp_eth_phy_t *phy = NULL; +#if CONFIG_ETH_SPI_ETHERNET_W5500 + if (type == ETH_PHY_W5500) + { + eth_w5500_config_t mac_config = ETH_W5500_DEFAULT_CONFIG(spi_host, &spi_devcfg); + mac_config.int_gpio_num = _pin_irq; + // #if ETH_SPI_SUPPORTS_CUSTOM + // if(_spi != NULL){ + // mac_config.custom_spi_driver.config = this; + // mac_config.custom_spi_driver.init = _eth_spi_init; + // mac_config.custom_spi_driver.deinit = _eth_spi_deinit; + // mac_config.custom_spi_driver.read = _eth_spi_read; + // mac_config.custom_spi_driver.write = _eth_spi_write; + // } + // #endif + mac = esp_eth_mac_new_w5500(&mac_config, ð_mac_config); + phy = esp_eth_phy_new_w5500(&phy_config); + } + else +#endif +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + if (type == ETH_PHY_DM9051) + { + eth_dm9051_config_t mac_config = ETH_DM9051_DEFAULT_CONFIG(spi_host, &spi_devcfg); + mac_config.int_gpio_num = _pin_irq; +#if ETH_SPI_SUPPORTS_CUSTOM + if (_spi != NULL) + { + mac_config.custom_spi_driver.config = this; + mac_config.custom_spi_driver.init = _eth_spi_init; + mac_config.custom_spi_driver.deinit = _eth_spi_deinit; + mac_config.custom_spi_driver.read = _eth_spi_read; + mac_config.custom_spi_driver.write = _eth_spi_write; + } +#endif + mac = esp_eth_mac_new_dm9051(&mac_config, ð_mac_config); + phy = esp_eth_phy_new_dm9051(&phy_config); + } + else +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + if (type == ETH_PHY_KSZ8851) + { + eth_ksz8851snl_config_t mac_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, &spi_devcfg); + mac_config.int_gpio_num = _pin_irq; +#if ETH_SPI_SUPPORTS_CUSTOM + if (_spi != NULL) + { + mac_config.custom_spi_driver.config = this; + mac_config.custom_spi_driver.init = _eth_spi_init; + mac_config.custom_spi_driver.deinit = _eth_spi_deinit; + mac_config.custom_spi_driver.read = _eth_spi_read; + mac_config.custom_spi_driver.write = _eth_spi_write; + } +#endif + mac = esp_eth_mac_new_ksz8851snl(&mac_config, ð_mac_config); + phy = esp_eth_phy_new_ksz8851snl(&phy_config); + } + else +#endif + { + log_e("Unsupported PHY module: %d", (int)type); + return false; + } + + // Init Ethernet driver to default and install it + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + ret = esp_eth_driver_install(ð_config, &_eth_handle); + if (ret != ESP_OK) + { + log_e("SPI Ethernet driver install failed: %d", ret); + return false; + } + if (_eth_handle == NULL) + { + log_e("esp_eth_driver_install failed! eth_handle is NULL"); + return false; + } + + // Derive a new MAC address for this interface + uint8_t base_mac_addr[ETH_ADDR_LEN]; + ret = esp_efuse_mac_get_default(base_mac_addr); + if (ret != ESP_OK) + { + log_e("Get EFUSE MAC failed: %d", ret); + return false; + } + uint8_t mac_addr[ETH_ADDR_LEN]; + base_mac_addr[ETH_ADDR_LEN - 1] += _eth_index; // Increment by the ETH number + esp_derive_local_mac(mac_addr, base_mac_addr); + + ret = esp_eth_ioctl(_eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr); + if (ret != ESP_OK) + { + log_e("SPI Ethernet MAC address config failed: %d", ret); + return false; + } + + // Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and you don't need to modify + // default esp-netif configuration parameters. + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); + + // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify + // esp-netif configuration parameters for each interface (name, priority, etc.). + char if_key_str[10]; + char if_desc_str[10]; + char num_str[3]; + itoa(_eth_index, num_str, 10); + strcat(strcpy(if_key_str, "ETH_"), num_str); + strcat(strcpy(if_desc_str, "eth"), num_str); + + esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); + esp_netif_config.if_key = if_key_str; + esp_netif_config.if_desc = if_desc_str; + esp_netif_config.route_prio -= _eth_index * 5; + + cfg.base = &esp_netif_config; + + _esp_netif = esp_netif_new(&cfg); + if (_esp_netif == NULL) + { + log_e("esp_netif_new failed"); + return false; + } + // Attach Ethernet driver to TCP/IP stack + esp_eth_netif_glue_handle_t new_netif_glue = esp_eth_new_netif_glue(_eth_handle); + if (new_netif_glue == NULL) + { + log_e("esp_eth_new_netif_glue failed"); + return false; + } + + ret = esp_netif_attach(_esp_netif, new_netif_glue); + if (ret != ESP_OK) + { + log_e("esp_netif_attach failed: %d", ret); + return false; + } + + // attach to WiFiGeneric to receive events + add_esp_interface_netif(ESP_IF_ETH, _esp_netif); + + // Start Ethernet driver state machine + ret = esp_eth_start(_eth_handle); + if (ret != ESP_OK) + { + log_e("esp_eth_start failed: %d", ret); + return false; + } + + _eth_started = true; + + // If Arduino's SPI is used, cs pin is in GPIO mode +#if ETH_SPI_SUPPORTS_CUSTOM + if (_spi == NULL) + { +#endif + if (!perimanSetPinBus(_pin_cs, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } +#if ETH_SPI_SUPPORTS_CUSTOM + } +#endif + if (!perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + + if (_pin_sck != -1) + { + if (!perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + } + if (_pin_miso != -1) + { + if (!perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + } + if (_pin_mosi != -1) + { + if (!perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + } + if (_pin_rst != -1) + { + if (!perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_ETHERNET, (void *)(this))) + { + goto err; + } + } + + return true; + +err: + log_e("Failed to set all pins bus to ETHERNET"); + ETHClass::ethDetachBus((void *)(this)); + return false; +} + +#if ETH_SPI_SUPPORTS_CUSTOM +bool ETHClass::begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, SPIClass &spi, uint8_t spi_freq_mhz) +{ + + return beginSPI(type, phy_addr, cs, irq, rst, &spi, -1, -1, -1, SPI2_HOST, spi_freq_mhz); +} +#endif + +bool ETHClass::begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, spi_host_device_t spi_host, int sck, int miso, int mosi, uint8_t spi_freq_mhz) +{ + + return beginSPI(type, phy_addr, cs, irq, rst, +#if ETH_SPI_SUPPORTS_CUSTOM + NULL, +#endif + sck, miso, mosi, spi_host, spi_freq_mhz); +} + +void ETHClass::end(void) +{ + _eth_started = false; + + if (_esp_netif != NULL) + { + esp_netif_destroy(_esp_netif); + _esp_netif = NULL; + } + + if (_eth_handle != NULL) + { + if (esp_eth_stop(_eth_handle) != ESP_OK) + { + log_e("Failed to stop Ethernet"); + return; + } + if (esp_eth_driver_uninstall(_eth_handle) != ESP_OK) + { + log_e("Failed to stop Ethernet"); + return; + } + _eth_handle = NULL; + } + +#if ETH_SPI_SUPPORTS_CUSTOM + _spi = NULL; +#endif + +#if CONFIG_ETH_USE_ESP32_EMAC + if (_pin_rmii_clock != -1 && _pin_mcd != -1 && _pin_mdio != -1) + { + perimanSetPinBus(_pin_rmii_clock, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_mcd, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_mdio, ESP32_BUS_TYPE_INIT, NULL); + + perimanSetPinBus(ETH_RMII_TX_EN, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_TX0, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_TX1, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_RX0, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_RX1_EN, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(ETH_RMII_CRS_DV, ESP32_BUS_TYPE_INIT, NULL); + + _pin_rmii_clock = -1; + _pin_mcd = -1; + _pin_mdio = -1; + } + + if (_pin_power != -1) + { + perimanSetPinBus(_pin_power, ESP32_BUS_TYPE_INIT, NULL); + _pin_power = -1; + } +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + if (_pin_cs != -1) + { + perimanSetPinBus(_pin_cs, ESP32_BUS_TYPE_INIT, NULL); + _pin_cs = -1; + } + if (_pin_irq != -1) + { + perimanSetPinBus(_pin_irq, ESP32_BUS_TYPE_INIT, NULL); + _pin_irq = -1; + } + if (_pin_sck != -1) + { + perimanSetPinBus(_pin_sck, ESP32_BUS_TYPE_INIT, NULL); + _pin_sck = -1; + } + if (_pin_miso != -1) + { + perimanSetPinBus(_pin_miso, ESP32_BUS_TYPE_INIT, NULL); + _pin_miso = -1; + } + if (_pin_mosi != -1) + { + perimanSetPinBus(_pin_mosi, ESP32_BUS_TYPE_INIT, NULL); + _pin_mosi = -1; + } + if (_pin_rst != -1) + { + perimanSetPinBus(_pin_rst, ESP32_BUS_TYPE_INIT, NULL); + _pin_rst = -1; + } +} + +bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) +{ + if (_esp_netif == NULL) + { + return false; + } + esp_err_t err = ESP_OK; + esp_netif_ip_info_t info; + esp_netif_dns_info_t d1; + esp_netif_dns_info_t d2; + d1.ip.type = IPADDR_TYPE_V4; + d2.ip.type = IPADDR_TYPE_V4; + + if (static_cast(local_ip) != 0) + { + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + d1.ip.u_addr.ip4.addr = static_cast(dns1); + d2.ip.u_addr.ip4.addr = static_cast(dns2); + } + else + { + info.ip.addr = 0; + info.gw.addr = 0; + info.netmask.addr = 0; + d1.ip.u_addr.ip4.addr = 0; + d2.ip.u_addr.ip4.addr = 0; + } + + // Stop DHCPC + err = esp_netif_dhcpc_stop(_esp_netif); + if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) + { + log_e("DHCP could not be stopped! Error: %d", err); + return false; + } + + // Set IPv4, Netmask, Gateway + err = esp_netif_set_ip_info(_esp_netif, &info); + if (err != ERR_OK) + { + log_e("ETH IP could not be configured! Error: %d", err); + return false; + } + + // Set DNS1-Server + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d1); + + // Set DNS2-Server + esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_BACKUP, &d2); + + // Start DHCPC if static IP was set + if (info.ip.addr == 0) + { + err = esp_netif_dhcpc_start(_esp_netif); + if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) + { + log_w("DHCP could not be started! Error: %d", err); + return false; + } + } + + return true; +} + +IPAddress ETHClass::localIP() +{ + if (_esp_netif == NULL) + { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) + { + return IPAddress(); + } + return IPAddress(ip.ip.addr); +} + +IPAddress ETHClass::subnetMask() +{ + if (_esp_netif == NULL) + { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) + { + return IPAddress(); + } + return IPAddress(ip.netmask.addr); +} + +IPAddress ETHClass::gatewayIP() +{ + if (_esp_netif == NULL) + { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) + { + return IPAddress(); + } + return IPAddress(ip.gw.addr); +} + +IPAddress ETHClass::dnsIP(uint8_t dns_no) +{ + if (_esp_netif == NULL) + { + return IPAddress(); + } + esp_netif_dns_info_t d; + if (esp_netif_get_dns_info(_esp_netif, dns_no ? ESP_NETIF_DNS_BACKUP : ESP_NETIF_DNS_MAIN, &d) != ESP_OK) + { + return IPAddress(); + } + return IPAddress(d.ip.u_addr.ip4.addr); +} + +IPAddress ETHClass::broadcastIP() +{ + if (_esp_netif == NULL) + { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) + { + return IPAddress(); + } + return WiFiGenericClass::calculateBroadcast(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr)); +} + +IPAddress ETHClass::networkID() +{ + if (_esp_netif == NULL) + { + return IPAddress(); + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) + { + return IPAddress(); + } + return WiFiGenericClass::calculateNetworkID(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr)); +} + +uint8_t ETHClass::subnetCIDR() +{ + if (_esp_netif == NULL) + { + return (uint8_t)0; + } + esp_netif_ip_info_t ip; + if (esp_netif_get_ip_info(_esp_netif, &ip)) + { + return (uint8_t)0; + } + return WiFiGenericClass::calculateSubnetCIDR(IPAddress(ip.netmask.addr)); +} + +const char *ETHClass::getHostname() +{ + if (_esp_netif == NULL) + { + return ""; + } + const char *hostname; + if (esp_netif_get_hostname(_esp_netif, &hostname)) + { + return NULL; + } + return hostname; +} + +bool ETHClass::setHostname(const char *hostname) +{ + if (_esp_netif == NULL) + { + return false; + } + return esp_netif_set_hostname(_esp_netif, hostname) == 0; +} + +bool ETHClass::enableIpV6() +{ + if (_esp_netif == NULL) + { + return false; + } + return esp_netif_create_ip6_linklocal(_esp_netif) == 0; +} + +IPv6Address ETHClass::localIPv6() +{ + if (_esp_netif == NULL) + { + return IPv6Address(); + } + static esp_ip6_addr_t addr; + if (esp_netif_get_ip6_linklocal(_esp_netif, &addr)) + { + return IPv6Address(); + } + return IPv6Address(addr.addr); +} + +const char *ETHClass::ifkey(void) +{ + if (_esp_netif == NULL) + { + return ""; + } + return esp_netif_get_ifkey(_esp_netif); +} + +const char *ETHClass::desc(void) +{ + if (_esp_netif == NULL) + { + return ""; + } + return esp_netif_get_desc(_esp_netif); +} + +String ETHClass::impl_name(void) +{ + if (_esp_netif == NULL) + { + return String(""); + } + char netif_name[8]; + esp_err_t err = esp_netif_get_netif_impl_name(_esp_netif, netif_name); + if (err != ESP_OK) + { + log_e("Failed to get netif impl_name: %d", err); + return String(""); + } + return String(netif_name); +} + +bool ETHClass::connected() +{ + return WiFiGenericClass::getStatusBits() & ETH_CONNECTED_BIT; +} + +bool ETHClass::hasIP() +{ + return WiFiGenericClass::getStatusBits() & ETH_HAS_IP_BIT; +} + +bool ETHClass::linkUp() +{ + if (_esp_netif == NULL) + { + return false; + } + return esp_netif_is_netif_up(_esp_netif); +} + +bool ETHClass::fullDuplex() +{ + if (_eth_handle == NULL) + { + return false; + } + eth_duplex_t link_duplex; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_DUPLEX_MODE, &link_duplex); + return (link_duplex == ETH_DUPLEX_FULL); +} + +bool ETHClass::autoNegotiation() +{ + if (_eth_handle == NULL) + { + return false; + } + bool auto_nego; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_AUTONEGO, &auto_nego); + return auto_nego; +} + +uint32_t ETHClass::phyAddr() +{ + if (_eth_handle == NULL) + { + return 0; + } + uint32_t phy_addr; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_PHY_ADDR, &phy_addr); + return phy_addr; +} + +uint8_t ETHClass::linkSpeed() +{ + if (_eth_handle == NULL) + { + return 0; + } + eth_speed_t link_speed; + esp_eth_ioctl(_eth_handle, ETH_CMD_G_SPEED, &link_speed); + return (link_speed == ETH_SPEED_10M) ? 10 : 100; +} + +uint8_t *ETHClass::macAddress(uint8_t *mac) +{ + if (_eth_handle == NULL) + { + return NULL; + } + if (!mac) + { + return NULL; + } + esp_eth_ioctl(_eth_handle, ETH_CMD_G_MAC_ADDR, mac); + return mac; +} + +String ETHClass::macAddress(void) +{ + uint8_t mac[6] = {0, 0, 0, 0, 0, 0}; + char macStr[18] = {0}; + macAddress(mac); + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + +void ETHClass::printInfo(Print &out) +{ + out.print(desc()); + out.print(":"); + if (linkUp()) + { + out.print(" "); + + out.print(" "); + out.print("ether "); + out.print(macAddress()); + out.printf(" phy 0x%lX", phyAddr()); + out.println(); + + out.print(" "); + out.print("inet "); + out.print(localIP()); + out.print(" netmask "); + out.print(subnetMask()); + out.print(" broadcast "); + out.print(broadcastIP()); + out.println(); + + out.print(" "); + out.print("gateway "); + out.print(gatewayIP()); + out.print(" dns "); + out.print(dnsIP()); + out.println(); + + out.println(); +} + +ETHClass ETH; diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/src/ETH.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/src/ETH.h new file mode 100644 index 0000000..7ef39ef --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Ethernet/src/ETH.h @@ -0,0 +1,219 @@ +/* + ETH.h - espre ETH PHY support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ETH_H_ +#define _ETH_H_ + +// +// Example configurations for pins_arduino.h to allow starting with ETH.begin(); +// + +// // Example RMII LAN8720 (Olimex, etc.) +// #define ETH_PHY_TYPE ETH_PHY_LAN8720 +// #define ETH_PHY_ADDR 0 +// #define ETH_PHY_MDC 23 +// #define ETH_PHY_MDIO 18 +// #define ETH_PHY_POWER -1 +// #define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN + +// // Example RMII ESP32_Ethernet_V4 +// #define ETH_PHY_TYPE ETH_PHY_TLK110 +// #define ETH_PHY_ADDR 1 +// #define ETH_PHY_MDC 23 +// #define ETH_PHY_MDIO 18 +// #define ETH_PHY_POWER -1 +// #define ETH_CLK_MODE ETH_CLOCK_GPIO0_OUT + +// // Example SPI using ESP-IDF's driver +// #define ETH_PHY_TYPE ETH_PHY_W5500 +// #define ETH_PHY_ADDR 1 +// #define ETH_PHY_CS 15 +// #define ETH_PHY_IRQ 4 +// #define ETH_PHY_RST 5 +// #define ETH_PHY_SPI_HOST SPI2_HOST +// #define ETH_PHY_SPI_SCK 14 +// #define ETH_PHY_SPI_MISO 12 +// #define ETH_PHY_SPI_MOSI 13 + +// // Example SPI using Arduino's driver +// #define ETH_PHY_TYPE ETH_PHY_W5500 +// #define ETH_PHY_ADDR 1 +// #define ETH_PHY_CS 15 +// #define ETH_PHY_IRQ 4 +// #define ETH_PHY_RST 5 +// #define ETH_PHY_SPI SPI + +// This will be uncommented once custom SPI support is available in ESP-IDF +#define ETH_SPI_SUPPORTS_CUSTOM 1 + +#include "WiFi.h" +#if ETH_SPI_SUPPORTS_CUSTOM +#include "SPI.h" +#endif +#include "esp_system.h" +#include "esp_eth.h" +#include "esp_netif.h" + +#if CONFIG_ETH_USE_ESP32_EMAC +#define ETH_PHY_IP101 ETH_PHY_TLK110 +typedef enum { ETH_CLOCK_GPIO0_IN, ETH_CLOCK_GPIO0_OUT, ETH_CLOCK_GPIO16_OUT, ETH_CLOCK_GPIO17_OUT } eth_clock_mode_t; +//Dedicated GPIOs for RMII +#define ETH_RMII_TX_EN 21 +#define ETH_RMII_TX0 19 +#define ETH_RMII_TX1 22 +#define ETH_RMII_RX0 25 +#define ETH_RMII_RX1_EN 26 +#define ETH_RMII_CRS_DV 27 +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + +#ifndef ETH_PHY_SPI_FREQ_MHZ +#define ETH_PHY_SPI_FREQ_MHZ 20 +#endif /* ETH_PHY_SPI_FREQ_MHZ */ + +typedef enum { +#if CONFIG_ETH_USE_ESP32_EMAC + ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_RTL8201, ETH_PHY_DP83848, ETH_PHY_KSZ8041, ETH_PHY_KSZ8081, +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +#if CONFIG_ETH_SPI_ETHERNET_DM9051 + ETH_PHY_DM9051, +#endif +#if CONFIG_ETH_SPI_ETHERNET_W5500 + ETH_PHY_W5500, +#endif +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL + ETH_PHY_KSZ8851, +#endif + ETH_PHY_MAX +} eth_phy_type_t; + +class ETHClass { + public: + ETHClass(uint8_t eth_index=0); + ~ETHClass(); + +#if CONFIG_ETH_USE_ESP32_EMAC + bool begin(eth_phy_type_t type, uint8_t phy_addr, int mdc, int mdio, int power, eth_clock_mode_t clk_mode); +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ +#if ETH_SPI_SUPPORTS_CUSTOM + bool begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, SPIClass &spi, uint8_t spi_freq_mhz=ETH_PHY_SPI_FREQ_MHZ); +#endif + bool begin(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, spi_host_device_t spi_host, int sck=-1, int miso=-1, int mosi=-1, uint8_t spi_freq_mhz=ETH_PHY_SPI_FREQ_MHZ); + + bool begin(){ +#if defined(ETH_PHY_TYPE) && defined(ETH_PHY_ADDR) + #if defined(CONFIG_ETH_USE_ESP32_EMAC) && defined(ETH_PHY_POWER) && defined(ETH_PHY_MDC) && defined(ETH_PHY_MDIO) && defined(ETH_CLK_MODE) + return begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER, ETH_CLK_MODE); + #elif defined(ETH_PHY_CS) && defined(ETH_PHY_IRQ) && defined(ETH_PHY_RST) + #if ETH_SPI_SUPPORTS_CUSTOM && defined(ETH_PHY_SPI) + return begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, ETH_PHY_SPI, ETH_PHY_SPI_FREQ_MHZ); + #elif defined(ETH_PHY_SPI_HOST) && defined(ETH_PHY_SPI_SCK) && defined(ETH_PHY_SPI_MISO) && defined(ETH_PHY_SPI_MOSI) + return begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, ETH_PHY_SPI_HOST, ETH_PHY_SPI_SCK, ETH_PHY_SPI_MISO, ETH_PHY_SPI_MOSI, ETH_PHY_SPI_FREQ_MHZ); + #endif + #endif +#endif + return false; + } + + void end(); + + // Netif APIs + esp_netif_t * netif(void){ return _esp_netif; } + bool config(IPAddress local_ip = (uint32_t)0x00000000, IPAddress gateway = (uint32_t)0x00000000, IPAddress subnet = (uint32_t)0x00000000, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000); + const char * getHostname(); + bool setHostname(const char * hostname); + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsIP(uint8_t dns_no = 0); + IPAddress broadcastIP(); + IPAddress networkID(); + uint8_t subnetCIDR(); + bool enableIpV6(); + IPv6Address localIPv6(); + const char * ifkey(void); + const char * desc(void); + String impl_name(void); + + // Event based getters + bool connected(); + bool hasIP(); + + // ETH Handle APIs + uint8_t * macAddress(uint8_t* mac); + String macAddress(); + bool fullDuplex(); + bool linkUp(); + uint8_t linkSpeed(); + bool autoNegotiation(); + uint32_t phyAddr(); + + // Info APIs + void printInfo(Print & out); + + friend class WiFiClient; + friend class WiFiServer; + +#if ETH_SPI_SUPPORTS_CUSTOM + static esp_err_t _eth_spi_read(void *ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); + static esp_err_t _eth_spi_write(void *ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); +#endif + + protected: +#if ETH_SPI_SUPPORTS_CUSTOM + esp_err_t eth_spi_read(uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); + esp_err_t eth_spi_write(uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); +#endif + + static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); + + private: + bool _eth_started; + esp_eth_handle_t _eth_handle; + esp_netif_t *_esp_netif; + uint8_t _eth_index; + eth_phy_type_t _phy_type; +#if ETH_SPI_SUPPORTS_CUSTOM + SPIClass * _spi; +#endif + uint8_t _spi_freq_mhz; + int8_t _pin_cs; + int8_t _pin_irq; + int8_t _pin_rst; + int8_t _pin_sck; + int8_t _pin_miso; + int8_t _pin_mosi; +#if CONFIG_ETH_USE_ESP32_EMAC + int8_t _pin_mcd; + int8_t _pin_mdio; + int8_t _pin_power; + int8_t _pin_rmii_clock; +#endif /* CONFIG_ETH_USE_ESP32_EMAC */ + + static bool ethDetachBus(void * bus_pointer); + bool beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, int rst, +#if ETH_SPI_SUPPORTS_CUSTOM + SPIClass * spi, +#endif + int sck, int miso, int mosi, spi_host_device_t spi_host, uint8_t spi_freq_mhz); +}; + +extern ETHClass ETH; + +#endif /* _ETH_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_Test/FFat_Test.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_Test/FFat_Test.ino new file mode 100644 index 0000000..d31637a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_Test/FFat_Test.ino @@ -0,0 +1,188 @@ +#include "FS.h" +#include "FFat.h" + +// This file should be compiled with 'Partition Scheme' (in Tools menu) +// set to 'Default with ffat' if you have a 4MB ESP32 dev module or +// set to '16M Fat' if you have a 16MB ESP32 dev module. + +// You only need to format FFat the first time you run a test +#define FORMAT_FFAT true + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("- failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print("\tSIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + + File file = fs.open(path); + if(!file || file.isDirectory()){ + Serial.println("- failed to open file for reading"); + return; + } + + Serial.println("- read from file:"); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\r\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("- failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("- message appended"); + } else { + Serial.println("- append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\r\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("- file renamed"); + } else { + Serial.println("- rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\r\n", path); + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + Serial.printf("Testing file I/O with %s\r\n", path); + + static uint8_t buf[512]; + size_t len = 0; + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + + size_t i; + Serial.print("- writing" ); + uint32_t start = millis(); + for(i=0; i<2048; i++){ + if ((i & 0x001F) == 0x001F){ + Serial.print("."); + } + file.write(buf, 512); + } + Serial.println(""); + uint32_t end = millis() - start; + Serial.printf(" - %u bytes written in %lu ms\r\n", 2048 * 512, end); + file.close(); + + file = fs.open(path); + start = millis(); + end = start; + i = 0; + if(file && !file.isDirectory()){ + len = file.size(); + size_t flen = len; + start = millis(); + Serial.print("- reading" ); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + if ((i++ & 0x001F) == 0x001F){ + Serial.print("."); + } + len -= toRead; + } + Serial.println(""); + end = millis() - start; + Serial.printf("- %u bytes read in %lu ms\r\n", flen, end); + file.close(); + } else { + Serial.println("- failed to open file for reading"); + } +} + +void setup(){ + Serial.begin(115200); + Serial.setDebugOutput(true); + if (FORMAT_FFAT) FFat.format(); + if(!FFat.begin()){ + Serial.println("FFat Mount Failed"); + return; + } + + Serial.printf("Total space: %10u\n", FFat.totalBytes()); + Serial.printf("Free space: %10u\n", FFat.freeBytes()); + listDir(FFat, "/", 0); + writeFile(FFat, "/hello.txt", "Hello "); + appendFile(FFat, "/hello.txt", "World!\r\n"); + readFile(FFat, "/hello.txt"); + renameFile(FFat, "/hello.txt", "/foo.txt"); + readFile(FFat, "/foo.txt"); + deleteFile(FFat, "/foo.txt"); + testFileIO(FFat, "/test.txt"); + Serial.printf("Free space: %10u\n", FFat.freeBytes()); + deleteFile(FFat, "/test.txt"); + Serial.println( "Test complete" ); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_time/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_time/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_time/FFat_time.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_time/FFat_time.ino new file mode 100644 index 0000000..475cfea --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/examples/FFat_time/FFat_time.ino @@ -0,0 +1,177 @@ +#include "FS.h" +#include "FFat.h" +#include +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +long timezone = 1; +byte daysavetime = 1; + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.print (file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup(){ + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + + if(!FFat.begin(true)){ + Serial.println("FFat Mount Failed"); + return; + } + + listDir(FFat, "/", 0); + removeDir(FFat, "/mydir"); + createDir(FFat, "/mydir"); + deleteFile(FFat, "/hello.txt"); + writeFile(FFat, "/hello.txt", "Hello "); + appendFile(FFat, "/hello.txt", "World!\n"); + listDir(FFat, "/", 0); +} + +void loop(){ + +} + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/library.properties new file mode 100644 index 0000000..ec5e030 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/library.properties @@ -0,0 +1,9 @@ +name=FFat +version=2.0.0 +author=Hristo Gochkov, Ivan Grokhtkov, Larry Bernstone +maintainer=Hristo Gochkov +sentence=ESP32 FAT on Flash File System +paragraph= +category=Data Storage +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/src/FFat.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/src/FFat.cpp new file mode 100644 index 0000000..e312e7f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/src/FFat.cpp @@ -0,0 +1,183 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "vfs_api.h" +extern "C" { +#include "esp_vfs_fat.h" +#include "diskio.h" +#include "diskio_wl.h" +#include "vfs_fat_internal.h" +} +#include "FFat.h" + +using namespace fs; + +F_Fat::F_Fat(FSImplPtr impl) + : FS(impl) +{} + +const esp_partition_t *check_ffat_partition(const char* label) +{ + const esp_partition_t* ck_part = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, label); + if (!ck_part) { + log_e("No FAT partition found with label %s", label); + return NULL; + } + return ck_part; +} + +bool F_Fat::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFiles, const char * partitionLabel) +{ + if(_wl_handle != WL_INVALID_HANDLE){ + log_w("Already Mounted!"); + return true; + } + + if (!check_ffat_partition(partitionLabel)){ + log_e("No fat partition found on flash"); + return false; + } + + esp_vfs_fat_mount_config_t conf = { + .format_if_mount_failed = formatOnFail, + .max_files = maxOpenFiles, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, + .disk_status_check_enable = false + }; + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(basePath, partitionLabel, &conf, &_wl_handle); + if(err){ + log_e("Mounting FFat partition failed! Error: %d", err); + esp_vfs_fat_spiflash_unmount_rw_wl(basePath, _wl_handle); + _wl_handle = WL_INVALID_HANDLE; + return false; + } + _impl->mountpoint(basePath); + return true; +} + +void F_Fat::end() +{ + if(_wl_handle != WL_INVALID_HANDLE){ + esp_err_t err = esp_vfs_fat_spiflash_unmount_rw_wl(_impl->mountpoint(), _wl_handle); + if(err){ + log_e("Unmounting FFat partition failed! Error: %d", err); + return; + } + _wl_handle = WL_INVALID_HANDLE; + _impl->mountpoint(NULL); + } +} + +bool F_Fat::format(bool full_wipe, char* partitionLabel) +{ + esp_err_t result; + bool res = true; + if(_wl_handle != WL_INVALID_HANDLE){ + log_w("Already Mounted!"); + return false; + } + wl_handle_t temp_handle; +// Attempt to mount to see if there is already data + const esp_partition_t *ffat_partition = check_ffat_partition(partitionLabel); + if (!ffat_partition){ + log_w("No partition!"); + return false; + } + result = wl_mount(ffat_partition, &temp_handle); + + if (result == ESP_OK) { +// Wipe disk- quick just wipes the FAT. Full zeroes the whole disk + uint32_t wipe_size = full_wipe ? wl_size(temp_handle) : 16384; + wl_erase_range(temp_handle, 0, wipe_size); + wl_unmount(temp_handle); + } else { + res = false; + log_w("wl_mount failed!"); + } +// Now do a mount with format_if_fail (which it will) + esp_vfs_fat_mount_config_t conf = { + .format_if_mount_failed = true, + .max_files = 1, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE, + .disk_status_check_enable = false + }; + result = esp_vfs_fat_spiflash_mount_rw_wl("/format_ffat", partitionLabel, &conf, &temp_handle); + esp_vfs_fat_spiflash_unmount_rw_wl("/format_ffat", temp_handle); + if (result != ESP_OK){ + res = false; + log_w("esp_vfs_fat_spiflash_mount_rw_wl failed!"); + } + return res; +} + +size_t F_Fat::totalBytes() +{ + FATFS *fs; + DWORD free_clust, tot_sect, sect_size; + + BYTE pdrv = ff_diskio_get_pdrv_wl(_wl_handle); + char drv[3] = {(char)(48+pdrv), ':', 0}; + if ( f_getfree(drv, &free_clust, &fs) != FR_OK){ + return 0; + } + tot_sect = (fs->n_fatent - 2) * fs->csize; + sect_size = CONFIG_WL_SECTOR_SIZE; + return tot_sect * sect_size; +} + +size_t F_Fat::usedBytes() +{ + FATFS *fs; + DWORD free_clust, used_sect, sect_size; + + BYTE pdrv = ff_diskio_get_pdrv_wl(_wl_handle); + char drv[3] = {(char)(48+pdrv), ':', 0}; + if ( f_getfree(drv, &free_clust, &fs) != FR_OK){ + return 0; + } + used_sect = (fs->n_fatent - 2 - free_clust) * fs->csize; + sect_size = CONFIG_WL_SECTOR_SIZE; + return used_sect * sect_size; +} + +size_t F_Fat::freeBytes() +{ + + FATFS *fs; + DWORD free_clust, free_sect, sect_size; + + BYTE pdrv = ff_diskio_get_pdrv_wl(_wl_handle); + char drv[3] = {(char)(48+pdrv), ':', 0}; + if ( f_getfree(drv, &free_clust, &fs) != FR_OK){ + return 0; + } + free_sect = free_clust * fs->csize; + sect_size = CONFIG_WL_SECTOR_SIZE; + return free_sect * sect_size; +} + +bool F_Fat::exists(const char* path) +{ + File f = open(path, "r",false); + return (f == true) && !f.isDirectory(); +} + +bool F_Fat::exists(const String& path) +{ + return exists(path.c_str()); +} + + +F_Fat FFat = F_Fat(FSImplPtr(new VFSImpl())); diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/src/FFat.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/src/FFat.h new file mode 100644 index 0000000..ed20e23 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FFat/src/FFat.h @@ -0,0 +1,48 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _FFAT_H_ +#define _FFAT_H_ + +#include "FS.h" +#include "wear_levelling.h" + +#define FFAT_WIPE_QUICK 0 +#define FFAT_WIPE_FULL 1 +#define FFAT_PARTITION_LABEL "ffat" + +namespace fs +{ + +class F_Fat : public FS +{ +public: + F_Fat(FSImplPtr impl); + bool begin(bool formatOnFail=false, const char * basePath="/ffat", uint8_t maxOpenFiles=10, const char * partitionLabel = (char*)FFAT_PARTITION_LABEL); + bool format(bool full_wipe = FFAT_WIPE_QUICK, char* partitionLabel = (char*)FFAT_PARTITION_LABEL); + size_t totalBytes(); + size_t usedBytes(); + size_t freeBytes(); + void end(); + bool exists(const char* path); + bool exists(const String& path); + +private: + wl_handle_t _wl_handle = WL_INVALID_HANDLE; +}; + +} + +extern fs::F_Fat FFat; + +#endif /* _FFAT_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/library.properties new file mode 100644 index 0000000..2018a1a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/library.properties @@ -0,0 +1,9 @@ +name=FS +version=2.0.0 +author=Hristo Gochkov, Ivan Grokhtkov +maintainer=Hristo Gochkov +sentence=ESP32 File System +paragraph= +category=Data Storage +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FS.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FS.cpp new file mode 100644 index 0000000..e0a0a0a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FS.cpp @@ -0,0 +1,320 @@ +/* + FS.cpp - file system wrapper + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "FS.h" +#include "FSImpl.h" + +using namespace fs; + +size_t File::write(uint8_t c) +{ + if (!*this) { + return 0; + } + + return _p->write(&c, 1); +} + +time_t File::getLastWrite() +{ + if (!*this) { + return 0; + } + + return _p->getLastWrite(); +} + +size_t File::write(const uint8_t *buf, size_t size) +{ + if (!*this) { + return 0; + } + + return _p->write(buf, size); +} + +int File::available() +{ + if (!*this) { + return false; + } + + return _p->size() - _p->position(); +} + +int File::read() +{ + if (!*this) { + return -1; + } + + uint8_t result; + if (_p->read(&result, 1) != 1) { + return -1; + } + + return result; +} + +size_t File::read(uint8_t* buf, size_t size) +{ + if (!*this) { + return -1; + } + + return _p->read(buf, size); +} + +int File::peek() +{ + if (!*this) { + return -1; + } + + size_t curPos = _p->position(); + int result = read(); + seek(curPos, SeekSet); + return result; +} + +void File::flush() +{ + if (!*this) { + return; + } + + _p->flush(); +} + +bool File::seek(uint32_t pos, SeekMode mode) +{ + if (!*this) { + return false; + } + + return _p->seek(pos, mode); +} + +size_t File::position() const +{ + if (!*this) { + return 0; + } + + return _p->position(); +} + +size_t File::size() const +{ + if (!*this) { + return 0; + } + + return _p->size(); +} + +bool File::setBufferSize(size_t size) +{ + if (!*this) { + return 0; + } + + return _p->setBufferSize(size); +} + +void File::close() +{ + if (_p) { + _p->close(); + _p = nullptr; + } +} + +File::operator bool() const +{ + return _p != nullptr && *_p != false; +} + +const char* File::path() const +{ + if (!*this) { + return nullptr; + } + + return _p->path(); +} + +const char* File::name() const +{ + if (!*this) { + return nullptr; + } + + return _p->name(); +} + +//to implement +boolean File::isDirectory(void) +{ + if (!*this) { + return false; + } + return _p->isDirectory(); +} + +File File::openNextFile(const char* mode) +{ + if (!*this) { + return File(); + } + return _p->openNextFile(mode); +} + +boolean File::seekDir(long position){ + if(!_p){ + return false; + } + return _p->seekDir(position); +} + +String File::getNextFileName(void) +{ + if (!_p) { + return ""; + } + return _p->getNextFileName(); + +} + +String File::getNextFileName(bool *isDir) +{ + if (!_p) { + return ""; + } + return _p->getNextFileName(isDir); + +} + +void File::rewindDirectory(void) +{ + if (!*this) { + return; + } + _p->rewindDirectory(); +} + +File FS::open(const String& path, const char* mode, const bool create) +{ + return open(path.c_str(), mode, create); +} + +File FS::open(const char* path, const char* mode, const bool create) +{ + if (!_impl) { + return File(); + } + + return File(_impl->open(path, mode, create)); +} + +bool FS::exists(const char* path) +{ + if (!_impl) { + return false; + } + return _impl->exists(path); +} + +bool FS::exists(const String& path) +{ + return exists(path.c_str()); +} + +bool FS::remove(const char* path) +{ + if (!_impl) { + return false; + } + return _impl->remove(path); +} + +bool FS::remove(const String& path) +{ + return remove(path.c_str()); +} + +bool FS::rename(const char* pathFrom, const char* pathTo) +{ + if (!_impl) { + return false; + } + return _impl->rename(pathFrom, pathTo); +} + +bool FS::rename(const String& pathFrom, const String& pathTo) +{ + return rename(pathFrom.c_str(), pathTo.c_str()); +} + + +bool FS::mkdir(const char *path) +{ + if (!_impl) { + return false; + } + return _impl->mkdir(path); +} + +bool FS::mkdir(const String &path) +{ + return mkdir(path.c_str()); +} + +bool FS::rmdir(const char *path) +{ + if (!_impl) { + return false; + } + return _impl->rmdir(path); +} + +bool FS::rmdir(const String &path) +{ + return rmdir(path.c_str()); +} + +const char * FS::mountpoint() +{ + if (!_impl) { + return NULL; + } + return _impl->mountpoint(); +} + + +void FSImpl::mountpoint(const char * mp) +{ + _mountpoint = mp; +} + +const char * FSImpl::mountpoint() +{ + return _mountpoint; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FS.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FS.h new file mode 100644 index 0000000..bd04b49 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FS.h @@ -0,0 +1,132 @@ +/* + FS.h - file system wrapper + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef FS_H +#define FS_H + +#include +#include + +namespace fs +{ + +#define FILE_READ "r" +#define FILE_WRITE "w" +#define FILE_APPEND "a" + +class File; + +class FileImpl; +typedef std::shared_ptr FileImplPtr; +class FSImpl; +typedef std::shared_ptr FSImplPtr; + +enum SeekMode { + SeekSet = 0, + SeekCur = 1, + SeekEnd = 2 +}; + +class File : public Stream +{ +public: + File(FileImplPtr p = FileImplPtr()) : _p(p) { + _timeout = 0; + } + + size_t write(uint8_t) override; + size_t write(const uint8_t *buf, size_t size) override; + int available() override; + int read() override; + int peek() override; + void flush() override; + size_t read(uint8_t* buf, size_t size); + size_t readBytes(char *buffer, size_t length) + { + return read((uint8_t*)buffer, length); + } + + bool seek(uint32_t pos, SeekMode mode); + bool seek(uint32_t pos) + { + return seek(pos, SeekSet); + } + size_t position() const; + size_t size() const; + bool setBufferSize(size_t size); + void close(); + operator bool() const; + time_t getLastWrite(); + const char* path() const; + const char* name() const; + + boolean isDirectory(void); + boolean seekDir(long position); + File openNextFile(const char* mode = FILE_READ); + String getNextFileName(void); + String getNextFileName(boolean *isDir); + void rewindDirectory(void); + +protected: + FileImplPtr _p; +}; + +class FS +{ +public: + FS(FSImplPtr impl) : _impl(impl) { } + + File open(const char* path, const char* mode = FILE_READ, const bool create = false); + File open(const String& path, const char* mode = FILE_READ, const bool create = false); + + bool exists(const char* path); + bool exists(const String& path); + + bool remove(const char* path); + bool remove(const String& path); + + bool rename(const char* pathFrom, const char* pathTo); + bool rename(const String& pathFrom, const String& pathTo); + + bool mkdir(const char *path); + bool mkdir(const String &path); + + bool rmdir(const char *path); + bool rmdir(const String &path); + + const char * mountpoint(); + + +protected: + FSImplPtr _impl; +}; + +} // namespace fs + +#ifndef FS_NO_GLOBALS +using fs::FS; +using fs::File; +using fs::SeekMode; +using fs::SeekSet; +using fs::SeekCur; +using fs::SeekEnd; +#endif //FS_NO_GLOBALS + +#endif //FS_H diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FSImpl.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FSImpl.h new file mode 100644 index 0000000..dc7b81b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/FSImpl.h @@ -0,0 +1,72 @@ +/* + FSImpl.h - base file system interface + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef FSIMPL_H +#define FSIMPL_H + +#include +#include + +namespace fs +{ + +class FileImpl +{ +public: + virtual ~FileImpl() { } + virtual size_t write(const uint8_t *buf, size_t size) = 0; + virtual size_t read(uint8_t* buf, size_t size) = 0; + virtual void flush() = 0; + virtual bool seek(uint32_t pos, SeekMode mode) = 0; + virtual size_t position() const = 0; + virtual size_t size() const = 0; + virtual bool setBufferSize(size_t size) = 0; + virtual void close() = 0; + virtual time_t getLastWrite() = 0; + virtual const char* path() const = 0; + virtual const char* name() const = 0; + virtual boolean isDirectory(void) = 0; + virtual FileImplPtr openNextFile(const char* mode) = 0; + virtual boolean seekDir(long position); + virtual String getNextFileName(void); + virtual String getNextFileName(bool *isDir); + virtual void rewindDirectory(void) = 0; + virtual operator bool() = 0; +}; + +class FSImpl +{ +protected: + const char * _mountpoint; +public: + FSImpl() : _mountpoint(NULL) { } + virtual ~FSImpl() { } + virtual FileImplPtr open(const char* path, const char* mode, const bool create) = 0; + virtual bool exists(const char* path) = 0; + virtual bool rename(const char* pathFrom, const char* pathTo) = 0; + virtual bool remove(const char* path) = 0; + virtual bool mkdir(const char *path) = 0; + virtual bool rmdir(const char *path) = 0; + void mountpoint(const char *); + const char * mountpoint(); +}; + +} // namespace fs + +#endif //FSIMPL_H diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/vfs_api.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/vfs_api.cpp new file mode 100644 index 0000000..1dd8da9 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/vfs_api.cpp @@ -0,0 +1,575 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "vfs_api.h" + +using namespace fs; + +#define DEFAULT_FILE_BUFFER_SIZE 4096 + +FileImplPtr VFSImpl::open(const char* fpath, const char* mode, const bool create) +{ + if(!_mountpoint) { + log_e("File system is not mounted"); + return FileImplPtr(); + } + + if(!fpath || fpath[0] != '/') { + log_e("%s does not start with /", fpath); + return FileImplPtr(); + } + + char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+2); + if(!temp) { + log_e("malloc failed"); + return FileImplPtr(); + } + + strcpy(temp, _mountpoint); + strcat(temp, fpath); + + struct stat st; + //file found + if(!stat(temp, &st)) { + free(temp); + if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { + return std::make_shared(this, fpath, mode); + } + log_e("%s has wrong mode 0x%08X", fpath, st.st_mode); + return FileImplPtr(); + } + + //try to open this as directory (might be mount point) + DIR * d = opendir(temp); + if(d) { + closedir(d); + free(temp); + return std::make_shared(this, fpath, mode); + } + + //file not found but mode permits file creation without folder creation + if((mode && mode[0] != 'r') && (!create)){ + free(temp); + return std::make_shared(this, fpath, mode); + } + + ////file not found but mode permits file creation and folder creation + if((mode && mode[0] != 'r') && create){ + + char *token; + char *folder = (char *)malloc(strlen(fpath)); + + int start_index = 0; + int end_index = 0; + + token = strchr(fpath+1,'/'); + end_index = (token-fpath); + + while (token != NULL) + { + memcpy(folder,fpath + start_index, end_index-start_index); + folder[end_index-start_index] = '\0'; + + if(!VFSImpl::mkdir(folder)) + { + log_e("Creating folder: %s failed!",folder); + return FileImplPtr(); + } + + token=strchr(token+1,'/'); + if(token != NULL) + { + end_index = (token-fpath); + memset(folder, 0, strlen(folder)); + } + + } + + free(folder); + free(temp); + return std::make_shared(this, fpath, mode); + + } + + log_e("%s does not exist, no permits for creation", temp); + free(temp); + return FileImplPtr(); +} + +bool VFSImpl::exists(const char* fpath) +{ + if(!_mountpoint) { + log_e("File system is not mounted"); + return false; + } + + VFSFileImpl f(this, fpath, "r"); + if(f) { + f.close(); + return true; + } + return false; +} + +bool VFSImpl::rename(const char* pathFrom, const char* pathTo) +{ + if(!_mountpoint) { + log_e("File system is not mounted"); + return false; + } + + if(!pathFrom || pathFrom[0] != '/' || !pathTo || pathTo[0] != '/') { + log_e("bad arguments"); + return false; + } + if(!exists(pathFrom)) { + log_e("%s does not exists", pathFrom); + return false; + } + size_t mountpointLen = strlen(_mountpoint); + char * temp1 = (char *)malloc(strlen(pathFrom)+mountpointLen+1); + if(!temp1) { + log_e("malloc failed"); + return false; + } + char * temp2 = (char *)malloc(strlen(pathTo)+mountpointLen+1); + if(!temp2) { + free(temp1); + log_e("malloc failed"); + return false; + } + + strcpy(temp1, _mountpoint); + strcat(temp1, pathFrom); + + strcpy(temp2, _mountpoint); + strcat(temp2, pathTo); + + auto rc = ::rename(temp1, temp2); + free(temp1); + free(temp2); + return rc == 0; +} + +bool VFSImpl::remove(const char* fpath) +{ + if(!_mountpoint) { + log_e("File system is not mounted"); + return false; + } + + if(!fpath || fpath[0] != '/') { + log_e("bad arguments"); + return false; + } + + VFSFileImpl f(this, fpath, "r"); + if(!f || f.isDirectory()) { + if(f) { + f.close(); + } + log_e("%s does not exists or is directory", fpath); + return false; + } + f.close(); + + char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+1); + if(!temp) { + log_e("malloc failed"); + return false; + } + + strcpy(temp, _mountpoint); + strcat(temp, fpath); + + auto rc = unlink(temp); + free(temp); + return rc == 0; +} + +bool VFSImpl::mkdir(const char *fpath) +{ + if(!_mountpoint) { + log_e("File system is not mounted"); + return false; + } + + VFSFileImpl f(this, fpath, "r"); + if(f && f.isDirectory()) { + f.close(); + //log_w("%s already exists", fpath); + return true; + } else if(f) { + f.close(); + log_e("%s is a file", fpath); + return false; + } + + char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+1); + if(!temp) { + log_e("malloc failed"); + return false; + } + + strcpy(temp, _mountpoint); + strcat(temp, fpath); + + auto rc = ::mkdir(temp, ACCESSPERMS); + free(temp); + return rc == 0; +} + +bool VFSImpl::rmdir(const char *fpath) +{ + if(!_mountpoint) { + log_e("File system is not mounted"); + return false; + } + + if (strcmp(_mountpoint, "/spiffs") == 0) { + log_e("rmdir is unnecessary in SPIFFS"); + return false; + } + + VFSFileImpl f(this, fpath, "r"); + if(!f || !f.isDirectory()) { + if(f) { + f.close(); + } + log_e("%s does not exists or is a file", fpath); + return false; + } + f.close(); + + char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+1); + if(!temp) { + log_e("malloc failed"); + return false; + } + + strcpy(temp, _mountpoint); + strcat(temp, fpath); + + auto rc = ::rmdir(temp); + free(temp); + return rc == 0; +} + + + + +VFSFileImpl::VFSFileImpl(VFSImpl* fs, const char* fpath, const char* mode) + : _fs(fs) + , _f(NULL) + , _d(NULL) + , _path(NULL) + , _isDirectory(false) + , _written(false) +{ + char * temp = (char *)malloc(strlen(fpath)+strlen(_fs->_mountpoint)+1); + if(!temp) { + return; + } + + strcpy(temp, _fs->_mountpoint); + strcat(temp, fpath); + + _path = strdup(fpath); + if(!_path) { + log_e("strdup(%s) failed", fpath); + free(temp); + return; + } + + if(!stat(temp, &_stat)) { + //file found + if (S_ISREG(_stat.st_mode)) { + _isDirectory = false; + _f = fopen(temp, mode); + if(!_f) { + log_e("fopen(%s) failed", temp); + } + if(_f && (_stat.st_blksize == 0)) + { + setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE); + } + } else if(S_ISDIR(_stat.st_mode)) { + _isDirectory = true; + _d = opendir(temp); + if(!_d) { + log_e("opendir(%s) failed", temp); + } + } else { + log_e("Unknown type 0x%08X for file %s", ((_stat.st_mode)&_IFMT), temp); + } + } else { + //file not found + if(!mode || mode[0] == 'r') { + //try to open as directory + _d = opendir(temp); + if(_d) { + _isDirectory = true; + } else { + _isDirectory = false; + //log_w("stat(%s) failed", temp); + } + } else { + //lets create this new file + _isDirectory = false; + _f = fopen(temp, mode); + if(!_f) { + log_e("fopen(%s) failed", temp); + } + if(_f && (_stat.st_blksize == 0)) + { + setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE); + } + } + } + free(temp); +} + +VFSFileImpl::~VFSFileImpl() +{ + close(); +} + +void VFSFileImpl::close() +{ + if(_path) { + free(_path); + _path = NULL; + } + if(_isDirectory && _d) { + closedir(_d); + _d = NULL; + _isDirectory = false; + } else if(_f) { + fclose(_f); + _f = NULL; + } +} + +VFSFileImpl::operator bool() +{ + return (_isDirectory && _d != NULL) || _f != NULL; +} + +time_t VFSFileImpl::getLastWrite() { + _getStat() ; + return _stat.st_mtime; +} + +void VFSFileImpl::_getStat() const +{ + if(!_path) { + return; + } + char * temp = (char *)malloc(strlen(_path)+strlen(_fs->_mountpoint)+1); + if(!temp) { + return; + } + + strcpy(temp, _fs->_mountpoint); + strcat(temp, _path); + + if(!stat(temp, &_stat)) { + _written = false; + } + free(temp); +} + +size_t VFSFileImpl::write(const uint8_t *buf, size_t size) +{ + if(_isDirectory || !_f || !buf || !size) { + return 0; + } + _written = true; + return fwrite(buf, 1, size, _f); +} + +size_t VFSFileImpl::read(uint8_t* buf, size_t size) +{ + if(_isDirectory || !_f || !buf || !size) { + return 0; + } + + return fread(buf, 1, size, _f); +} + +void VFSFileImpl::flush() +{ + if(_isDirectory || !_f) { + return; + } + fflush(_f); + // workaround for https://github.com/espressif/arduino-esp32/issues/1293 + fsync(fileno(_f)); +} + +bool VFSFileImpl::seek(uint32_t pos, SeekMode mode) +{ + if(_isDirectory || !_f) { + return false; + } + auto rc = fseek(_f, pos, mode); + return rc == 0; +} + +size_t VFSFileImpl::position() const +{ + if(_isDirectory || !_f) { + return 0; + } + return ftell(_f); +} + +size_t VFSFileImpl::size() const +{ + if(_isDirectory || !_f) { + return 0; + } + if (_written) { + _getStat(); + } + return _stat.st_size; +} + +/* +* Change size of files internal buffer used for read / write operations. +* Need to be called right after opening file before any other operation! +*/ +bool VFSFileImpl::setBufferSize(size_t size) +{ + if(_isDirectory || !_f) { + return 0; + } + int res = setvbuf(_f,NULL,_IOFBF,size); + return res == 0; +} + +const char* VFSFileImpl::path() const +{ + return (const char*) _path; +} + +const char* VFSFileImpl::name() const +{ + return pathToFileName(path()); +} + +//to implement +boolean VFSFileImpl::isDirectory(void) +{ + return _isDirectory; +} + +FileImplPtr VFSFileImpl::openNextFile(const char* mode) +{ + if(!_isDirectory || !_d) { + return FileImplPtr(); + } + struct dirent *file = readdir(_d); + if(file == NULL) { + return FileImplPtr(); + } + if(file->d_type != DT_REG && file->d_type != DT_DIR) { + return openNextFile(mode); + } + + size_t pathLen = strlen(_path); + size_t fileNameLen = strlen(file->d_name); + char * name = (char *)malloc(pathLen+fileNameLen+2); + + if(name == NULL) { + return FileImplPtr(); + } + + strcpy(name, _path); + + if ((file->d_name[0] != '/') && (_path[pathLen - 1] != '/')) + { + strcat(name, "/"); + } + + strcat(name, file->d_name); + + FileImplPtr fileImplPtr = std::make_shared(_fs, name, mode); + free(name); + return fileImplPtr; +} + +boolean VFSFileImpl::seekDir(long position){ + if(!_d){ + return false; + } + seekdir(_d, position); + return true; +} + + +String VFSFileImpl::getNextFileName() +{ + if (!_isDirectory || !_d) { + return ""; + } + struct dirent *file = readdir(_d); + if (file == NULL) { + return ""; + } + if (file->d_type != DT_REG && file->d_type != DT_DIR) { + return ""; + } + String fname = String(file->d_name); + String name = String(_path); + if (!fname.startsWith("/") && !name.endsWith("/")) { + name += "/"; + } + name += fname; + return name; +} + +String VFSFileImpl::getNextFileName(bool *isDir) +{ + if (!_isDirectory || !_d) { + return ""; + } + struct dirent *file = readdir(_d); + if (file == NULL) { + return ""; + } + if (file->d_type != DT_REG && file->d_type != DT_DIR) { + return ""; + } + String fname = String(file->d_name); + String name = String(_path); + if (!fname.startsWith("/") && !name.endsWith("/")) { + name += "/"; + } + name += fname; + + // check entry is a directory + if (isDir) { + *isDir = (file->d_type == DT_DIR); + } + return name; +} + +void VFSFileImpl::rewindDirectory(void) +{ + if(!_isDirectory || !_d) { + return; + } + rewinddir(_d); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/vfs_api.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/vfs_api.h new file mode 100644 index 0000000..ae2a4d0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/FS/src/vfs_api.h @@ -0,0 +1,82 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef vfs_api_h +#define vfs_api_h + +#include "FS.h" +#include "FSImpl.h" + +extern "C" { +#include +#include +#include +} + +using namespace fs; + +class VFSFileImpl; + +class VFSImpl : public FSImpl +{ + +protected: + friend class VFSFileImpl; + +public: + FileImplPtr open(const char* path, const char* mode, const bool create) override; + bool exists(const char* path) override; + bool rename(const char* pathFrom, const char* pathTo) override; + bool remove(const char* path) override; + bool mkdir(const char *path) override; + bool rmdir(const char *path) override; +}; + +class VFSFileImpl : public FileImpl +{ +protected: + VFSImpl* _fs; + FILE * _f; + DIR * _d; + char * _path; + bool _isDirectory; + mutable struct stat _stat; + mutable bool _written; + + void _getStat() const; + +public: + VFSFileImpl(VFSImpl* fs, const char* path, const char* mode); + ~VFSFileImpl() override; + size_t write(const uint8_t *buf, size_t size) override; + size_t read(uint8_t* buf, size_t size) override; + void flush() override; + bool seek(uint32_t pos, SeekMode mode) override; + size_t position() const override; + size_t size() const override; + bool setBufferSize(size_t size); + void close() override; + const char* path() const override; + const char* name() const override; + time_t getLastWrite() override; + boolean isDirectory(void) override; + boolean seekDir(long position) override; + String getNextFileName(void) override; + String getNextFileName(bool *isDir) override; + FileImplPtr openNextFile(const char* mode) override; + void rewindDirectory(void) override; + operator bool(); +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/Authorization/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/Authorization/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/Authorization/Authorization.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/Authorization/Authorization.ino new file mode 100644 index 0000000..400f93c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/Authorization/Authorization.ino @@ -0,0 +1,83 @@ +/** + * Authorization.ino + * + * Created on: 09.12.2015 + * + */ + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +WiFiMulti wifiMulti; + +void setup() { + + USE_SERIAL.begin(115200); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + wifiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if((wifiMulti.run() == WL_CONNECTED)) { + + HTTPClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url + + + http.begin("http://user:password@192.168.1.12/test.html"); + + /* + // or + http.begin("http://192.168.1.12/test.html"); + http.setAuthorization("user", "password"); + + // or + http.begin("http://192.168.1.12/test.html"); + http.setAuthorization("dXNlcjpwYXN3b3Jk"); + */ + + + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + + // httpCode will be negative on error + if(httpCode > 0) { + // HTTP header has been send and Server response header has been handled + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == HTTP_CODE_OK) { + String payload = http.getString(); + USE_SERIAL.println(payload); + } + } else { + USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } + + delay(10000); +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpClient/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpClient/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino new file mode 100644 index 0000000..9ee620a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpClient/BasicHttpClient.ino @@ -0,0 +1,101 @@ +/** + * BasicHTTPClient.ino + * + * Created on: 24.05.2015 + * + */ + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +WiFiMulti wifiMulti; + +/* +const char* ca = \ +"-----BEGIN CERTIFICATE-----\n" \ +"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \ +"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \ +"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \ +"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \ +"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" \ +"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" \ +"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" \ +"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" \ +"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" \ +"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" \ +"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" \ +"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" \ +"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" \ +"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" \ +"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" \ +"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" \ +"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" \ +"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" \ +"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" \ +"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" \ +"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" \ +"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" \ +"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" \ +"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" \ +"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \ +"-----END CERTIFICATE-----\n"; +*/ + +void setup() { + + USE_SERIAL.begin(115200); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + wifiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if((wifiMulti.run() == WL_CONNECTED)) { + + HTTPClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + // configure traged server and url + //http.begin("https://www.howsmyssl.com/a/check", ca); //HTTPS + http.begin("http://example.com/index.html"); //HTTP + + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + + // httpCode will be negative on error + if(httpCode > 0) { + // HTTP header has been send and Server response header has been handled + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == HTTP_CODE_OK) { + String payload = http.getString(); + USE_SERIAL.println(payload); + } + } else { + USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } + + delay(5000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpsClient/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpsClient/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino new file mode 100644 index 0000000..9b55d80 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino @@ -0,0 +1,147 @@ +/** + BasicHTTPSClient.ino + + Created on: 14.10.2018 + +*/ + +#include + +#include +#include + +#include + +#include + +// This is GandiStandardSSLCA2.pem, the root Certificate Authority that signed +// the server certifcate for the demo server https://jigsaw.w3.org in this +// example. This certificate is valid until Sep 11 23:59:59 2024 GMT +const char* rootCACertificate = \ +"-----BEGIN CERTIFICATE-----\n" \ +"MIIF6TCCA9GgAwIBAgIQBeTcO5Q4qzuFl8umoZhQ4zANBgkqhkiG9w0BAQwFADCB\n" \ +"iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" \ +"cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" \ +"BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQw\n" \ +"OTEyMDAwMDAwWhcNMjQwOTExMjM1OTU5WjBfMQswCQYDVQQGEwJGUjEOMAwGA1UE\n" \ +"CBMFUGFyaXMxDjAMBgNVBAcTBVBhcmlzMQ4wDAYDVQQKEwVHYW5kaTEgMB4GA1UE\n" \ +"AxMXR2FuZGkgU3RhbmRhcmQgU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" \ +"DwAwggEKAoIBAQCUBC2meZV0/9UAPPWu2JSxKXzAjwsLibmCg5duNyj1ohrP0pIL\n" \ +"m6jTh5RzhBCf3DXLwi2SrCG5yzv8QMHBgyHwv/j2nPqcghDA0I5O5Q1MsJFckLSk\n" \ +"QFEW2uSEEi0FXKEfFxkkUap66uEHG4aNAXLy59SDIzme4OFMH2sio7QQZrDtgpbX\n" \ +"bmq08j+1QvzdirWrui0dOnWbMdw+naxb00ENbLAb9Tr1eeohovj0M1JLJC0epJmx\n" \ +"bUi8uBL+cnB89/sCdfSN3tbawKAyGlLfOGsuRTg/PwSWAP2h9KK71RfWJ3wbWFmV\n" \ +"XooS/ZyrgT5SKEhRhWvzkbKGPym1bgNi7tYFAgMBAAGjggF1MIIBcTAfBgNVHSME\n" \ +"GDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUs5Cn2MmvTs1hPJ98\n" \ +"rV1/Qf1pMOowDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD\n" \ +"VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCIGA1UdIAQbMBkwDQYLKwYBBAGy\n" \ +"MQECAhowCAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl\n" \ +"cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy\n" \ +"bDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRy\n" \ +"dXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZ\n" \ +"aHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAWGf9\n" \ +"crJq13xhlhl+2UNG0SZ9yFP6ZrBrLafTqlb3OojQO3LJUP33WbKqaPWMcwO7lWUX\n" \ +"zi8c3ZgTopHJ7qFAbjyY1lzzsiI8Le4bpOHeICQW8owRc5E69vrOJAKHypPstLbI\n" \ +"FhfFcvwnQPYT/pOmnVHvPCvYd1ebjGU6NSU2t7WKY28HJ5OxYI2A25bUeo8tqxyI\n" \ +"yW5+1mUfr13KFj8oRtygNeX56eXVlogMT8a3d2dIhCe2H7Bo26y/d7CQuKLJHDJd\n" \ +"ArolQ4FCR7vY4Y8MDEZf7kYzawMUgtN+zY+vkNaOJH1AQrRqahfGlZfh8jjNp+20\n" \ +"J0CT33KpuMZmYzc4ZCIwojvxuch7yPspOqsactIGEk72gtQjbz7Dk+XYtsDe3CMW\n" \ +"1hMwt6CaDixVBgBwAc/qOR2A24j3pSC4W/0xJmmPLQphgzpHphNULB7j7UTKvGof\n" \ +"KA5R2d4On3XNDgOVyvnFqSot/kGkoUeuDcL5OWYzSlvhhChZbH2UF3bkRYKtcCD9\n" \ +"0m9jqNf6oDP6N8v3smWe2lBvP+Sn845dWDKXcCMu5/3EFZucJ48y7RetWIExKREa\n" \ +"m9T8bJUox04FB6b9HbwZ4ui3uRGKLXASUoWNjDNKD/yZkuBjcNqllEdjB+dYxzFf\n" \ +"BT02Vf6Dsuimrdfp5gJ0iHRc2jTbkNJtUQoj1iM=\n" \ +"-----END CERTIFICATE-----\n"; + +// Not sure if WiFiClientSecure checks the validity date of the certificate. +// Setting clock just to be sure... +void setClock() { + configTime(0, 0, "pool.ntp.org"); + + Serial.print(F("Waiting for NTP time sync: ")); + time_t nowSecs = time(nullptr); + while (nowSecs < 8 * 3600 * 2) { + delay(500); + Serial.print(F(".")); + yield(); + nowSecs = time(nullptr); + } + + Serial.println(); + struct tm timeinfo; + gmtime_r(&nowSecs, &timeinfo); + Serial.print(F("Current time: ")); + Serial.print(asctime(&timeinfo)); +} + + +WiFiMulti WiFiMulti; + +void setup() { + + Serial.begin(115200); + // Serial.setDebugOutput(true); + + Serial.println(); + Serial.println(); + Serial.println(); + + WiFi.mode(WIFI_STA); + WiFiMulti.addAP("SSID", "PASSWORD"); + + // wait for WiFi connection + Serial.print("Waiting for WiFi to connect..."); + while ((WiFiMulti.run() != WL_CONNECTED)) { + Serial.print("."); + } + Serial.println(" connected"); + + setClock(); +} + +void loop() { + WiFiClientSecure *client = new WiFiClientSecure; + if(client) { + client -> setCACert(rootCACertificate); + + { + // Add a scoping block for HTTPClient https to make sure it is destroyed before WiFiClientSecure *client is + HTTPClient https; + + Serial.print("[HTTPS] begin...\n"); + if (https.begin(*client, "https://jigsaw.w3.org/HTTP/connection.html")) { // HTTPS + Serial.print("[HTTPS] GET...\n"); + // start connection and send HTTP header + int httpCode = https.GET(); + + // httpCode will be negative on error + if (httpCode > 0) { + // HTTP header has been send and Server response header has been handled + Serial.printf("[HTTPS] GET... code: %d\n", httpCode); + + // file found at server + if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { + String payload = https.getString(); + Serial.println(payload); + } + } else { + Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str()); + } + + https.end(); + } else { + Serial.printf("[HTTPS] Unable to connect\n"); + } + + // End extra scoping block + } + + delete client; + } else { + Serial.println("Unable to create client"); + } + + Serial.println(); + Serial.println("Waiting 10s before the next round..."); + delay(10000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/HTTPClientEnterprise/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/HTTPClientEnterprise/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino new file mode 100644 index 0000000..c6b9e7d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/HTTPClientEnterprise/HTTPClientEnterprise.ino @@ -0,0 +1,108 @@ +/*|----------------------------------------------------------|*/ +/*|WORKING EXAMPLE FOR HTTP/HTTPS CONNECTION |*/ +/*|TESTED BOARDS: Devkit v1 DOIT, Devkitc v4 |*/ +/*|CORE: June 2018 |*/ +/*|----------------------------------------------------------|*/ +#include +#include +#if __has_include ("esp_eap_client.h") +#include "esp_eap_client.h" +#else +#include "esp_wpa2.h" +#endif +#include +#define EAP_IDENTITY "identity" //if connecting from another corporation, use identity@organisation.domain in Eduroam +#define EAP_PASSWORD "password" //your Eduroam password +const char* ssid = "eduroam"; // Eduroam SSID +int counter = 0; +const char* test_root_ca= \ +"-----BEGIN CERTIFICATE-----\n" \ +"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \ +"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \ +"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \ +"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \ +"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \ +"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \ +"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \ +"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \ +"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \ +"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \ +"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \ +"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \ +"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \ +"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \ +"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \ +"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \ +"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \ +"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \ +"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \ +"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" \ +"-----END CERTIFICATE-----\n"; +void setup() { + Serial.begin(115200); + delay(10); + Serial.println(); + Serial.print("Connecting to network: "); + Serial.println(ssid); + WiFi.disconnect(true); //disconnect form wifi to set new wifi connection + WiFi.mode(WIFI_STA); //init wifi mode +#if __has_include ("esp_eap_client.h") + esp_eap_client_set_identity((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide identity + esp_eap_client_set_username((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide username + esp_eap_client_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD)); //provide password + esp_wifi_sta_enterprise_enable(); +#else + esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide identity + esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide username --> identity and username is same + esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD)); //provide password + esp_wifi_sta_wpa2_ent_enable(); +#endif + WiFi.begin(ssid); //connect to wifi + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + counter++; + if(counter>=60){ //after 30 seconds timeout - reset board + ESP.restart(); + } + } + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address set: "); + Serial.println(WiFi.localIP()); //print LAN IP +} +void loop() { + if (WiFi.status() == WL_CONNECTED) { //if we are connected to Eduroam network + counter = 0; //reset counter + Serial.println("Wifi is still connected with IP: "); + Serial.println(WiFi.localIP()); //inform user about his IP address + }else if (WiFi.status() != WL_CONNECTED) { //if we lost connection, retry + WiFi.begin(ssid); + } + while (WiFi.status() != WL_CONNECTED) { //during lost connection, print dots + delay(500); + Serial.print("."); + counter++; + if(counter>=60){ //30 seconds timeout - reset board + ESP.restart(); + } + } + Serial.print("Connecting to website: "); + HTTPClient http; + http.begin("https://arduino.php5.sk/rele/rele1.txt", test_root_ca); //HTTPS example connection + //http.begin("http://www.arduino.php5.sk/rele/rele1.txt"); //HTTP example connection + //if uncomment HTTP example, you can comment root CA certificate too! + int httpCode = http.GET(); + if(httpCode > 0) { + Serial.printf("[HTTP] GET... code: %d\n", httpCode); + //file found at server --> on unsucessful connection code will be -1 + if(httpCode == HTTP_CODE_OK) { + String payload = http.getString(); + Serial.println(payload); + } + }else{ + Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + http.end(); + delay(2000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/ReuseConnection/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/ReuseConnection/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/ReuseConnection/ReuseConnection.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/ReuseConnection/ReuseConnection.ino new file mode 100644 index 0000000..d3bcefb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/ReuseConnection/ReuseConnection.ino @@ -0,0 +1,68 @@ +/** + * reuseConnection.ino + * + * Created on: 22.11.2015 + * + */ + + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +WiFiMulti wifiMulti; + +HTTPClient http; + +void setup() { + + USE_SERIAL.begin(115200); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + wifiMulti.addAP("SSID", "PASSWORD"); + + // allow reuse (if server supports it) + http.setReuse(true); +} + +void loop() { + // wait for WiFi connection + if((wifiMulti.run() == WL_CONNECTED)) { + + http.begin("http://192.168.1.12/test.html"); + //http.begin("192.168.1.12", 80, "/test.html"); + + int httpCode = http.GET(); + if(httpCode > 0) { + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == HTTP_CODE_OK) { + http.writeToStream(&USE_SERIAL); + } + } else { + USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } + + delay(1000); +} + + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/StreamHttpClient/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/StreamHttpClient/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/StreamHttpClient/StreamHttpClient.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/StreamHttpClient/StreamHttpClient.ino new file mode 100644 index 0000000..a0d681b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/examples/StreamHttpClient/StreamHttpClient.ino @@ -0,0 +1,100 @@ +/** + * StreamHTTPClient.ino + * + * Created on: 24.05.2015 + * + */ + +#include + +#include +#include + +#include + +#define USE_SERIAL Serial + +WiFiMulti wifiMulti; + +void setup() { + + USE_SERIAL.begin(115200); + + USE_SERIAL.println(); + USE_SERIAL.println(); + USE_SERIAL.println(); + + for(uint8_t t = 4; t > 0; t--) { + USE_SERIAL.printf("[SETUP] WAIT %d...\n", t); + USE_SERIAL.flush(); + delay(1000); + } + + wifiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if((wifiMulti.run() == WL_CONNECTED)) { + + HTTPClient http; + + USE_SERIAL.print("[HTTP] begin...\n"); + + // configure server and url + http.begin("http://192.168.1.12/test.html"); + //http.begin("192.168.1.12", 80, "/test.html"); + + USE_SERIAL.print("[HTTP] GET...\n"); + // start connection and send HTTP header + int httpCode = http.GET(); + if(httpCode > 0) { + // HTTP header has been send and Server response header has been handled + USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode); + + // file found at server + if(httpCode == HTTP_CODE_OK) { + + // get length of document (is -1 when Server sends no Content-Length header) + int len = http.getSize(); + + // create buffer for read + uint8_t buff[128] = { 0 }; + + // get tcp stream + WiFiClient * stream = http.getStreamPtr(); + + // read all data from server + while(http.connected() && (len > 0 || len == -1)) { + // get available data size + size_t size = stream->available(); + + if(size) { + // read up to 128 byte + int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); + + // write it to Serial + USE_SERIAL.write(buff, c); + + if(len > 0) { + len -= c; + } + } + delay(1); + } + + USE_SERIAL.println(); + USE_SERIAL.print("[HTTP] connection closed or file end.\n"); + + } + } else { + USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); + } + + http.end(); + } + + delay(10000); +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/library.properties new file mode 100644 index 0000000..56af94c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/library.properties @@ -0,0 +1,9 @@ +name=HTTPClient +version=2.0.0 +author=Markus Sattler +maintainer=Markus Sattler +sentence=HTTP Client for ESP32 +paragraph= +category=Communication +url=https://github.com/espressif/arduino-esp32/tree/master/libraries/HTTPClient +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/src/HTTPClient.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/src/HTTPClient.cpp new file mode 100644 index 0000000..62a9c44 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/src/HTTPClient.cpp @@ -0,0 +1,1711 @@ +#include +/** + * HTTPClient.cpp + * + * Created on: 02.11.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the HTTPClient for Arduino. + * Port to ESP32 by Evandro Luis Copercini (2017), + * changed fingerprints to CA verification. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Adapted in October 2018 + */ + +#include +#include + +#ifdef HTTPCLIENT_1_1_COMPATIBLE +#include +#include +#endif + +#include +#include + +#include "HTTPClient.h" + +/// Cookie jar support +#include + +#ifdef HTTPCLIENT_1_1_COMPATIBLE +class TransportTraits +{ +public: + virtual ~TransportTraits() + { + } + + virtual std::unique_ptr create() + { + return std::unique_ptr(new WiFiClient()); + } + + virtual bool verify(WiFiClient& client, const char* host) + { + return true; + } +}; + +class TLSTraits : public TransportTraits +{ +public: + TLSTraits(const char* CAcert, const char* clicert = nullptr, const char* clikey = nullptr) : + _cacert(CAcert), _clicert(clicert), _clikey(clikey) + { + } + + std::unique_ptr create() override + { + return std::unique_ptr(new WiFiClientSecure()); + } + + bool verify(WiFiClient& client, const char* host) override + { + WiFiClientSecure& wcs = static_cast(client); + if (_cacert == nullptr) { + wcs.setInsecure(); + } else { + wcs.setCACert(_cacert); + wcs.setCertificate(_clicert); + wcs.setPrivateKey(_clikey); + } + return true; + } + +protected: + const char* _cacert; + const char* _clicert; + const char* _clikey; +}; +#endif // HTTPCLIENT_1_1_COMPATIBLE + +/** + * constructor + */ +HTTPClient::HTTPClient() +{ +} + +/** + * destructor + */ +HTTPClient::~HTTPClient() +{ + if(_client) { + _client->stop(); + } + if(_currentHeaders) { + delete[] _currentHeaders; + } + if(_tcpDeprecated) { + _tcpDeprecated.reset(nullptr); + } + if(_transportTraits) { + _transportTraits.reset(nullptr); + } +} + +void HTTPClient::clear() +{ + _returnCode = 0; + _size = -1; + _headers = ""; +} + + +/** + * parsing the url for all needed parameters + * @param client Client& + * @param url String + * @param https bool + * @return success bool + */ +bool HTTPClient::begin(WiFiClient &client, String url) { +#ifdef HTTPCLIENT_1_1_COMPATIBLE + if(_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } +#endif + + _client = &client; + + // check for : (http: or https:) + int index = url.indexOf(':'); + if(index < 0) { + log_d("failed to parse protocol"); + return false; + } + + String protocol = url.substring(0, index); + if(protocol != "http" && protocol != "https") { + log_d("unknown protocol '%s'", protocol.c_str()); + return false; + } + + _port = (protocol == "https" ? 443 : 80); + _secure = (protocol == "https"); + return beginInternal(url, protocol.c_str()); +} + + +/** + * directly supply all needed parameters + * @param client Client& + * @param host String + * @param port uint16_t + * @param uri String + * @param https bool + * @return success bool + */ +bool HTTPClient::begin(WiFiClient &client, String host, uint16_t port, String uri, bool https) +{ +#ifdef HTTPCLIENT_1_1_COMPATIBLE + if(_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } +#endif + + _client = &client; + + clear(); + _host = host; + _port = port; + _uri = uri; + _protocol = (https ? "https" : "http"); + _secure = https; + return true; +} + + +#ifdef HTTPCLIENT_1_1_COMPATIBLE +bool HTTPClient::begin(String url, const char* CAcert) +{ + if(_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } + + clear(); + _port = 443; + if (!beginInternal(url, "https")) { + return false; + } + _secure = true; + _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); + if(!_transportTraits) { + log_e("could not create transport traits"); + return false; + } + + return true; +} + +/** + * parsing the url for all needed parameters + * @param url String + */ +bool HTTPClient::begin(String url) +{ + if(_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } + + clear(); + _port = 80; + if (!beginInternal(url, "http")) { + return begin(url, (const char*)NULL); + } + _transportTraits = TransportTraitsPtr(new TransportTraits()); + if(!_transportTraits) { + log_e("could not create transport traits"); + return false; + } + + return true; +} +#endif // HTTPCLIENT_1_1_COMPATIBLE + +bool HTTPClient::beginInternal(String url, const char* expectedProtocol) +{ + log_v("url: %s", url.c_str()); + + // check for : (http: or https: + int index = url.indexOf(':'); + if(index < 0) { + log_e("failed to parse protocol"); + return false; + } + + _protocol = url.substring(0, index); + if (_protocol != expectedProtocol) { + log_d("unexpected protocol: %s, expected %s", _protocol.c_str(), expectedProtocol); + return false; + } + + url.remove(0, (index + 3)); // remove http:// or https:// + + index = url.indexOf('/'); + if (index == -1) { + index = url.length(); + url += '/'; + } + String host = url.substring(0, index); + url.remove(0, index); // remove host part + + // get Authorization + index = host.indexOf('@'); + if(index >= 0) { + // auth info + String auth = host.substring(0, index); + host.remove(0, index + 1); // remove auth part including @ + _base64Authorization = base64::encode(auth); + } + + // get port + index = host.indexOf(':'); + String the_host; + if(index >= 0) { + the_host = host.substring(0, index); // hostname + host.remove(0, (index + 1)); // remove hostname + : + _port = host.toInt(); // get port + } else { + the_host = host; + } + if(_host != the_host && connected()){ + log_d("switching host from '%s' to '%s'. disconnecting first", _host.c_str(), the_host.c_str()); + _canReuse = false; + disconnect(true); + } + _host = the_host; + _uri = url; + log_d("protocol: %s, host: %s port: %d url: %s", _protocol.c_str(), _host.c_str(), _port, _uri.c_str()); + return true; +} + +#ifdef HTTPCLIENT_1_1_COMPATIBLE +bool HTTPClient::begin(String host, uint16_t port, String uri) +{ + if(_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } + + clear(); + _host = host; + _port = port; + _uri = uri; + _transportTraits = TransportTraitsPtr(new TransportTraits()); + log_d("host: %s port: %d uri: %s", host.c_str(), port, uri.c_str()); + return true; +} + +bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcert) +{ + if(_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } + + clear(); + _host = host; + _port = port; + _uri = uri; + + if (strlen(CAcert) == 0) { + return false; + } + _secure = true; + _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert)); + return true; +} + +bool HTTPClient::begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key) +{ + if(_client && !_tcpDeprecated) { + log_d("mix up of new and deprecated api"); + _canReuse = false; + end(); + } + + clear(); + _host = host; + _port = port; + _uri = uri; + + if (strlen(CAcert) == 0) { + return false; + } + _secure = true; + _transportTraits = TransportTraitsPtr(new TLSTraits(CAcert, cli_cert, cli_key)); + return true; +} +#endif // HTTPCLIENT_1_1_COMPATIBLE + +/** + * end + * called after the payload is handled + */ +void HTTPClient::end(void) +{ + disconnect(false); + clear(); +} + + + +/** + * disconnect + * close the TCP socket + */ +void HTTPClient::disconnect(bool preserveClient) +{ + if(connected()) { + if(_client->available() > 0) { + log_d("still data in buffer (%d), clean up.\n", _client->available()); + _client->flush(); + } + + if(_reuse && _canReuse) { + log_d("tcp keep open for reuse"); + } else { + log_d("tcp stop"); + _client->stop(); + if(!preserveClient) { + _client = nullptr; +#ifdef HTTPCLIENT_1_1_COMPATIBLE + if(_tcpDeprecated) { + _transportTraits.reset(nullptr); + _tcpDeprecated.reset(nullptr); + } +#endif + } + } + } else { + log_d("tcp is closed\n"); + } +} + + +/** + * connected + * @return connected status + */ +bool HTTPClient::connected() +{ + if(_client) { + return ((_client->available() > 0) || _client->connected()); + } + return false; +} + +/** + * try to reuse the connection to the server + * keep-alive + * @param reuse bool + */ +void HTTPClient::setReuse(bool reuse) +{ + _reuse = reuse; +} + +/** + * set User Agent + * @param userAgent const char * + */ +void HTTPClient::setUserAgent(const String& userAgent) +{ + _userAgent = userAgent; +} + +/** + * set the Authorizatio for the http request + * @param user const char * + * @param password const char * + */ +void HTTPClient::setAuthorization(const char * user, const char * password) +{ + if(user && password) { + String auth = user; + auth += ":"; + auth += password; + _base64Authorization = base64::encode(auth); + } +} + +/** + * set the Authorizatio for the http request + * @param auth const char * base64 + */ +void HTTPClient::setAuthorization(const char * auth) +{ + if(auth) { + _base64Authorization = auth; + } +} + +/** + * set the Authorization type for the http request + * @param authType const char * + */ +void HTTPClient::setAuthorizationType(const char * authType) +{ + if(authType) { + _authorizationType = authType; + } +} + +/** + * set the timeout (ms) for establishing a connection to the server + * @param connectTimeout int32_t + */ +void HTTPClient::setConnectTimeout(int32_t connectTimeout) +{ + _connectTimeout = connectTimeout; +} + +/** + * set the timeout for the TCP connection + * @param timeout unsigned int + */ +void HTTPClient::setTimeout(uint16_t timeout) +{ + _tcpTimeout = timeout; + if(connected()) { + _client->setTimeout((timeout + 500) / 1000); + } +} + +/** + * use HTTP1.0 + * @param use + */ +void HTTPClient::useHTTP10(bool useHTTP10) +{ + _useHTTP10 = useHTTP10; + _reuse = !useHTTP10; +} + +/** + * send a GET request + * @return http code + */ +int HTTPClient::GET() +{ + return sendRequest("GET"); +} + +/** + * sends a post request to the server + * @param payload uint8_t * + * @param size size_t + * @return http code + */ +int HTTPClient::POST(uint8_t * payload, size_t size) +{ + return sendRequest("POST", payload, size); +} + +int HTTPClient::POST(String payload) +{ + return POST((uint8_t *) payload.c_str(), payload.length()); +} + +/** + * sends a patch request to the server + * @param payload uint8_t * + * @param size size_t + * @return http code + */ +int HTTPClient::PATCH(uint8_t * payload, size_t size) +{ + return sendRequest("PATCH", payload, size); +} + +int HTTPClient::PATCH(String payload) +{ + return PATCH((uint8_t *) payload.c_str(), payload.length()); +} + +/** + * sends a put request to the server + * @param payload uint8_t * + * @param size size_t + * @return http code + */ +int HTTPClient::PUT(uint8_t * payload, size_t size) { + return sendRequest("PUT", payload, size); +} + +int HTTPClient::PUT(String payload) { + return PUT((uint8_t *) payload.c_str(), payload.length()); +} + +/** + * sendRequest + * @param type const char * "GET", "POST", .... + * @param payload String data for the message body + * @return + */ +int HTTPClient::sendRequest(const char * type, String payload) +{ + return sendRequest(type, (uint8_t *) payload.c_str(), payload.length()); +} + +/** + * sendRequest + * @param type const char * "GET", "POST", .... + * @param payload uint8_t * data for the message body if null not send + * @param size size_t size for the message body if 0 not send + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size) +{ + int code; + bool redirect = false; + uint16_t redirectCount = 0; + do { + // wipe out any existing headers from previous request + for(size_t i = 0; i < _headerKeysCount; i++) { + if (_currentHeaders[i].value.length() > 0) { + _currentHeaders[i].value.clear(); + } + } + + log_d("request type: '%s' redirCount: %d\n", type, redirectCount); + + // connect to server + if(!connect()) { + return returnError(HTTPC_ERROR_CONNECTION_REFUSED); + } + + if(payload && size > 0) { + addHeader(F("Content-Length"), String(size)); + } + + // add cookies to header, if present + String cookie_string; + if(generateCookieString(&cookie_string)) { + addHeader("Cookie", cookie_string); + } + + // send Header + if(!sendHeader(type)) { + return returnError(HTTPC_ERROR_SEND_HEADER_FAILED); + } + + // send Payload if needed + if(payload && size > 0) { + size_t sent_bytes = 0; + while(sent_bytes < size){ + size_t sent = _client->write(&payload[sent_bytes], size - sent_bytes); + if (sent == 0){ + log_w("Failed to send chunk! Lets wait a bit"); + delay(100); + sent = _client->write(&payload[sent_bytes], size - sent_bytes); + if (sent == 0){ + log_e("Failed to send chunk!"); + break; + } + } + sent_bytes += sent; + } + if(sent_bytes != size){ + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } + } + + code = handleHeaderResponse(); + log_d("sendRequest code=%d\n", code); + + // Handle redirections as stated in RFC document: + // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + // + // Implementing HTTP_CODE_FOUND as redirection with GET method, + // to follow most of existing user agent implementations. + // + redirect = false; + if ( + _followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS && + redirectCount < _redirectLimit && + _location.length() > 0 + ) { + switch (code) { + // redirecting using the same method + case HTTP_CODE_MOVED_PERMANENTLY: + case HTTP_CODE_TEMPORARY_REDIRECT: { + if ( + // allow to force redirections on other methods + // (the RFC require user to accept the redirection) + _followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS || + // allow GET and HEAD methods without force + !strcmp(type, "GET") || + !strcmp(type, "HEAD") + ) { + redirectCount += 1; + log_d("following redirect (the same method): '%s' redirCount: %d\n", _location.c_str(), redirectCount); + if (!setURL(_location)) { + log_d("failed setting URL for redirection\n"); + // no redirection + break; + } + // redirect using the same request method and payload, diffrent URL + redirect = true; + } + break; + } + // redirecting with method dropped to GET or HEAD + // note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method + case HTTP_CODE_FOUND: + case HTTP_CODE_SEE_OTHER: { + redirectCount += 1; + log_d("following redirect (dropped to GET/HEAD): '%s' redirCount: %d\n", _location.c_str(), redirectCount); + if (!setURL(_location)) { + log_d("failed setting URL for redirection\n"); + // no redirection + break; + } + // redirect after changing method to GET/HEAD and dropping payload + type = "GET"; + payload = nullptr; + size = 0; + redirect = true; + break; + } + + default: + break; + } + } + + } while (redirect); + // handle Server Response (Header) + return returnError(code); +} + +/** + * sendRequest + * @param type const char * "GET", "POST", .... + * @param stream Stream * data stream for the message body + * @param size size_t size for the message body if 0 not Content-Length is send + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int HTTPClient::sendRequest(const char * type, Stream * stream, size_t size) +{ + + if(!stream) { + return returnError(HTTPC_ERROR_NO_STREAM); + } + + // connect to server + if(!connect()) { + return returnError(HTTPC_ERROR_CONNECTION_REFUSED); + } + + if(size > 0) { + addHeader("Content-Length", String(size)); + } + + // add cookies to header, if present + String cookie_string; + if(generateCookieString(&cookie_string)) { + addHeader("Cookie", cookie_string); + } + + // send Header + if(!sendHeader(type)) { + return returnError(HTTPC_ERROR_SEND_HEADER_FAILED); + } + + int buff_size = HTTP_TCP_TX_BUFFER_SIZE; + + int len = size; + int bytesWritten = 0; + + if(len == 0) { + len = -1; + } + + // if possible create smaller buffer then HTTP_TCP_TX_BUFFER_SIZE + if((len > 0) && (len < buff_size)) { + buff_size = len; + } + + // create buffer for read + uint8_t * buff = (uint8_t *) malloc(buff_size); + + if(buff) { + // read all data from stream and send it to server + while(connected() && (stream->available() > -1) && (len > 0 || len == -1)) { + + // get available data size + int sizeAvailable = stream->available(); + + if(sizeAvailable) { + + int readBytes = sizeAvailable; + + // read only the asked bytes + if(len > 0 && readBytes > len) { + readBytes = len; + } + + // not read more the buffer can handle + if(readBytes > buff_size) { + readBytes = buff_size; + } + + // read data + int bytesRead = stream->readBytes(buff, readBytes); + + // write it to Stream + int bytesWrite = _client->write((const uint8_t *) buff, bytesRead); + bytesWritten += bytesWrite; + + // are all Bytes a writen to stream ? + if(bytesWrite != bytesRead) { + log_d("short write, asked for %d but got %d retry...", bytesRead, bytesWrite); + + // check for write error + if(_client->getWriteError()) { + log_d("stream write error %d", _client->getWriteError()); + + //reset write error for retry + _client->clearWriteError(); + } + + // some time for the stream + delay(1); + + int leftBytes = (readBytes - bytesWrite); + + // retry to send the missed bytes + bytesWrite = _client->write((const uint8_t *) (buff + bytesWrite), leftBytes); + bytesWritten += bytesWrite; + + if(bytesWrite != leftBytes) { + // failed again + log_d("short write, asked for %d but got %d failed.", leftBytes, bytesWrite); + free(buff); + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } + } + + // check for write error + if(_client->getWriteError()) { + log_d("stream write error %d", _client->getWriteError()); + free(buff); + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } + + // count bytes to read left + if(len > 0) { + len -= readBytes; + } + + delay(0); + } else { + delay(1); + } + } + + free(buff); + + if(size && (int) size != bytesWritten) { + log_d("Stream payload bytesWritten %d and size %d mismatch!.", bytesWritten, size); + log_d("ERROR SEND PAYLOAD FAILED!"); + return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED); + } else { + log_d("Stream payload written: %d", bytesWritten); + } + + } else { + log_d("too less ram! need %d", buff_size); + return returnError(HTTPC_ERROR_TOO_LESS_RAM); + } + + // handle Server Response (Header) + return returnError(handleHeaderResponse()); +} + +/** + * size of message body / payload + * @return -1 if no info or > 0 when Content-Length is set by server + */ +int HTTPClient::getSize(void) +{ + return _size; +} + +/** + * returns the stream of the tcp connection + * @return WiFiClient + */ +WiFiClient& HTTPClient::getStream(void) +{ + if (connected()) { + return *_client; + } + + log_w("getStream: not connected"); + static WiFiClient empty; + return empty; +} + +/** + * returns a pointer to the stream of the tcp connection + * @return WiFiClient* + */ +WiFiClient* HTTPClient::getStreamPtr(void) +{ + if(connected()) { + return _client; + } + + log_w("getStreamPtr: not connected"); + return nullptr; +} + +/** + * write all message body / payload to Stream + * @param stream Stream * + * @return bytes written ( negative values are error codes ) + */ +int HTTPClient::writeToStream(Stream * stream) +{ + + if(!stream) { + return returnError(HTTPC_ERROR_NO_STREAM); + } + + if(!connected()) { + return returnError(HTTPC_ERROR_NOT_CONNECTED); + } + + // get length of document (is -1 when Server sends no Content-Length header) + int len = _size; + int ret = 0; + + if(_transferEncoding == HTTPC_TE_IDENTITY) { + ret = writeToStreamDataBlock(stream, len); + + // have we an error? + if(ret < 0) { + return returnError(ret); + } + } else if(_transferEncoding == HTTPC_TE_CHUNKED) { + int size = 0; + while(1) { + if(!connected()) { + return returnError(HTTPC_ERROR_CONNECTION_LOST); + } + String chunkHeader = _client->readStringUntil('\n'); + + if(chunkHeader.length() <= 0) { + return returnError(HTTPC_ERROR_READ_TIMEOUT); + } + + chunkHeader.trim(); // remove \r + + // read size of chunk + len = (uint32_t) strtol((const char *) chunkHeader.c_str(), NULL, 16); + size += len; + log_v(" read chunk len: %d", len); + + // data left? + if(len > 0) { + int r = writeToStreamDataBlock(stream, len); + if(r < 0) { + // error in writeToStreamDataBlock + return returnError(r); + } + ret += r; + } else { + + // if no length Header use global chunk size + if(_size <= 0) { + _size = size; + } + + // check if we have write all data out + if(ret != _size) { + return returnError(HTTPC_ERROR_STREAM_WRITE); + } + break; + } + + // read trailing \r\n at the end of the chunk + char buf[2]; + auto trailing_seq_len = _client->readBytes((uint8_t*)buf, 2); + if (trailing_seq_len != 2 || buf[0] != '\r' || buf[1] != '\n') { + return returnError(HTTPC_ERROR_READ_TIMEOUT); + } + + delay(0); + } + } else { + return returnError(HTTPC_ERROR_ENCODING); + } + +// end(); + disconnect(true); + return ret; +} + +/** + * return all payload as String (may need lot of ram or trigger out of memory!) + * @return String + */ +String HTTPClient::getString(void) +{ + // _size can be -1 when Server sends no Content-Length header + if(_size > 0 || _size == -1) { + StreamString sstring; + // try to reserve needed memory (noop if _size == -1) + if(sstring.reserve((_size + 1))) { + writeToStream(&sstring); + return sstring; + } else { + log_d("not enough memory to reserve a string! need: %d", (_size + 1)); + } + } + + return ""; +} + +/** + * converts error code to String + * @param error int + * @return String + */ +String HTTPClient::errorToString(int error) +{ + switch(error) { + case HTTPC_ERROR_CONNECTION_REFUSED: + return F("connection refused"); + case HTTPC_ERROR_SEND_HEADER_FAILED: + return F("send header failed"); + case HTTPC_ERROR_SEND_PAYLOAD_FAILED: + return F("send payload failed"); + case HTTPC_ERROR_NOT_CONNECTED: + return F("not connected"); + case HTTPC_ERROR_CONNECTION_LOST: + return F("connection lost"); + case HTTPC_ERROR_NO_STREAM: + return F("no stream"); + case HTTPC_ERROR_NO_HTTP_SERVER: + return F("no HTTP server"); + case HTTPC_ERROR_TOO_LESS_RAM: + return F("too less ram"); + case HTTPC_ERROR_ENCODING: + return F("Transfer-Encoding not supported"); + case HTTPC_ERROR_STREAM_WRITE: + return F("Stream write error"); + case HTTPC_ERROR_READ_TIMEOUT: + return F("read Timeout"); + default: + return String(); + } +} + +/** + * adds Header to the request + * @param name + * @param value + * @param first + */ +void HTTPClient::addHeader(const String& name, const String& value, bool first, bool replace) +{ + // not allow set of Header handled by code + if(!name.equalsIgnoreCase(F("Connection")) && + !name.equalsIgnoreCase(F("User-Agent")) && + !name.equalsIgnoreCase(F("Host")) && + !(name.equalsIgnoreCase(F("Authorization")) && _base64Authorization.length())){ + + String headerLine = name; + headerLine += ": "; + + if (replace) { + int headerStart = _headers.indexOf(headerLine); + if (headerStart != -1 && (headerStart == 0 || _headers[headerStart - 1] == '\n')) { + int headerEnd = _headers.indexOf('\n', headerStart); + _headers = _headers.substring(0, headerStart) + _headers.substring(headerEnd + 1); + } + } + + headerLine += value; + headerLine += "\r\n"; + if(first) { + _headers = headerLine + _headers; + } else { + _headers += headerLine; + } + } +} + +void HTTPClient::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) +{ + _headerKeysCount = headerKeysCount; + if(_currentHeaders) { + delete[] _currentHeaders; + } + _currentHeaders = new RequestArgument[_headerKeysCount]; + for(size_t i = 0; i < _headerKeysCount; i++) { + _currentHeaders[i].key = headerKeys[i]; + } +} + +String HTTPClient::header(const char* name) +{ + for(size_t i = 0; i < _headerKeysCount; ++i) { + if(_currentHeaders[i].key.equalsIgnoreCase(name)) { + return _currentHeaders[i].value; + } + } + return String(); +} + +String HTTPClient::header(size_t i) +{ + if(i < _headerKeysCount) { + return _currentHeaders[i].value; + } + return String(); +} + +String HTTPClient::headerName(size_t i) +{ + if(i < _headerKeysCount) { + return _currentHeaders[i].key; + } + return String(); +} + +int HTTPClient::headers() +{ + return _headerKeysCount; +} + +bool HTTPClient::hasHeader(const char* name) +{ + for(size_t i = 0; i < _headerKeysCount; ++i) { + if((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) { + return true; + } + } + return false; +} + +/** + * init TCP connection and handle ssl verify if needed + * @return true if connection is ok + */ +bool HTTPClient::connect(void) +{ + if(connected()) { + if(_reuse) { + log_d("already connected, reusing connection"); + } else { + log_d("already connected, try reuse!"); + } + while(_client->available() > 0) { + _client->read(); + } + return true; + } + +#ifdef HTTPCLIENT_1_1_COMPATIBLE + if(_transportTraits && !_client) { + _tcpDeprecated = _transportTraits->create(); + if(!_tcpDeprecated) { + log_e("failed to create client"); + return false; + } + _client = _tcpDeprecated.get(); + } +#endif + + if (!_client) { + log_d("HTTPClient::begin was not called or returned error"); + return false; + } +#ifdef HTTPCLIENT_1_1_COMPATIBLE + if (_tcpDeprecated && !_transportTraits->verify(*_client, _host.c_str())) { + log_d("transport level verify failed"); + _client->stop(); + return false; + } +#endif + if(!_client->connect(_host.c_str(), _port, _connectTimeout)) { + log_d("failed connect to %s:%u", _host.c_str(), _port); + return false; + } + + // set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil() + _client->setTimeout((_tcpTimeout + 500) / 1000); + + log_d(" connected to %s:%u", _host.c_str(), _port); + + +/* +#ifdef ESP8266 + _client->setNoDelay(true); +#endif + */ + return connected(); +} + +/** + * sends HTTP request header + * @param type (GET, POST, ...) + * @return status + */ +bool HTTPClient::sendHeader(const char * type) +{ + if(!connected()) { + return false; + } + + String header = String(type) + " " + _uri + F(" HTTP/1."); + + if(_useHTTP10) { + header += "0"; + } else { + header += "1"; + } + + header += String(F("\r\nHost: ")) + _host; + if (_port != 80 && _port != 443) + { + header += ':'; + header += String(_port); + } + header += String(F("\r\nUser-Agent: ")) + _userAgent + + F("\r\nConnection: "); + + if(_reuse) { + header += F("keep-alive"); + } else { + header += F("close"); + } + header += "\r\n"; + + if(!_useHTTP10) { + header += F("Accept-Encoding: identity;q=1,chunked;q=0.1,*;q=0\r\n"); + } + + if(_base64Authorization.length()) { + _base64Authorization.replace("\n", ""); + header += F("Authorization: "); + header += _authorizationType; + header += " "; + header += _base64Authorization; + header += "\r\n"; + } + + header += _headers + "\r\n"; + + return (_client->write((const uint8_t *) header.c_str(), header.length()) == header.length()); +} + +/** + * reads the response from the server + * @return int http code + */ +int HTTPClient::handleHeaderResponse() +{ + + if(!connected()) { + return HTTPC_ERROR_NOT_CONNECTED; + } + + _returnCode = 0; + _size = -1; + _canReuse = _reuse; + + String transferEncoding; + + _transferEncoding = HTTPC_TE_IDENTITY; + unsigned long lastDataTime = millis(); + bool firstLine = true; + String date; + + while(connected()) { + size_t len = _client->available(); + if(len > 0) { + String headerLine = _client->readStringUntil('\n'); + headerLine.trim(); // remove \r + + lastDataTime = millis(); + + log_v("RX: '%s'", headerLine.c_str()); + + if(firstLine) { + firstLine = false; + if(_canReuse && headerLine.startsWith("HTTP/1.")) { + _canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0'); + } + int codePos = headerLine.indexOf(' ') + 1; + _returnCode = headerLine.substring(codePos, headerLine.indexOf(' ', codePos)).toInt(); + } else if(headerLine.indexOf(':')) { + String headerName = headerLine.substring(0, headerLine.indexOf(':')); + String headerValue = headerLine.substring(headerLine.indexOf(':') + 1); + headerValue.trim(); + + if(headerName.equalsIgnoreCase("Date")) { + date = headerValue; + } + + if(headerName.equalsIgnoreCase("Content-Length")) { + _size = headerValue.toInt(); + } + + if(_canReuse && headerName.equalsIgnoreCase("Connection")) { + if(headerValue.indexOf("close") >= 0 && headerValue.indexOf("keep-alive") < 0) { + _canReuse = false; + } + } + + if(headerName.equalsIgnoreCase("Transfer-Encoding")) { + transferEncoding = headerValue; + } + + if (headerName.equalsIgnoreCase("Location")) { + _location = headerValue; + } + + if (headerName.equalsIgnoreCase("Set-Cookie")) { + setCookie(date, headerValue); + } + + for (size_t i = 0; i < _headerKeysCount; i++) { + if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { + // Uncomment the following lines if you need to add support for multiple headers with the same key: + // if (!_currentHeaders[i].value.isEmpty()) { + // // Existing value, append this one with a comma + // _currentHeaders[i].value += ','; + // _currentHeaders[i].value += headerValue; + // } else { + _currentHeaders[i].value = headerValue; + // } + break; // We found a match, stop looking + } + } + + } + + if(headerLine == "") { + log_d("code: %d", _returnCode); + + if(_size > 0) { + log_d("size: %d", _size); + } + + if(transferEncoding.length() > 0) { + log_d("Transfer-Encoding: %s", transferEncoding.c_str()); + if(transferEncoding.equalsIgnoreCase("chunked")) { + _transferEncoding = HTTPC_TE_CHUNKED; + } else if(transferEncoding.equalsIgnoreCase("identity")) { + _transferEncoding = HTTPC_TE_IDENTITY; + } else { + return HTTPC_ERROR_ENCODING; + } + } else { + _transferEncoding = HTTPC_TE_IDENTITY; + } + + if(_returnCode) { + return _returnCode; + } else { + log_d("Remote host is not an HTTP Server!"); + return HTTPC_ERROR_NO_HTTP_SERVER; + } + } + + } else { + if((millis() - lastDataTime) > _tcpTimeout) { + return HTTPC_ERROR_READ_TIMEOUT; + } + delay(10); + } + } + + return HTTPC_ERROR_CONNECTION_LOST; +} + +/** + * write one Data Block to Stream + * @param stream Stream * + * @param size int + * @return < 0 = error >= 0 = size written + */ +int HTTPClient::writeToStreamDataBlock(Stream * stream, int size) +{ + int buff_size = HTTP_TCP_RX_BUFFER_SIZE; + int len = size; + int bytesWritten = 0; + + // if possible create smaller buffer then HTTP_TCP_RX_BUFFER_SIZE + if((len > 0) && (len < buff_size)) { + buff_size = len; + } + + // create buffer for read + uint8_t * buff = (uint8_t *) malloc(buff_size); + + if(buff) { + // read all data from server + while(connected() && (len > 0 || len == -1)) { + + // get available data size + size_t sizeAvailable = buff_size; + if(len < 0){ + sizeAvailable = _client->available(); + } + + if(sizeAvailable) { + + int readBytes = sizeAvailable; + + // read only the asked bytes + if(len > 0 && readBytes > len) { + readBytes = len; + } + + // not read more the buffer can handle + if(readBytes > buff_size) { + readBytes = buff_size; + } + + // stop if no more reading + if (readBytes == 0) + break; + + // read data + int bytesRead = _client->readBytes(buff, readBytes); + + // write it to Stream + int bytesWrite = stream->write(buff, bytesRead); + bytesWritten += bytesWrite; + + // are all Bytes a writen to stream ? + if(bytesWrite != bytesRead) { + log_d("short write asked for %d but got %d retry...", bytesRead, bytesWrite); + + // check for write error + if(stream->getWriteError()) { + log_d("stream write error %d", stream->getWriteError()); + + //reset write error for retry + stream->clearWriteError(); + } + + // some time for the stream + delay(1); + + int leftBytes = (readBytes - bytesWrite); + + // retry to send the missed bytes + bytesWrite = stream->write((buff + bytesWrite), leftBytes); + bytesWritten += bytesWrite; + + if(bytesWrite != leftBytes) { + // failed again + log_w("short write asked for %d but got %d failed.", leftBytes, bytesWrite); + free(buff); + return HTTPC_ERROR_STREAM_WRITE; + } + } + + // check for write error + if(stream->getWriteError()) { + log_w("stream write error %d", stream->getWriteError()); + free(buff); + return HTTPC_ERROR_STREAM_WRITE; + } + + // count bytes to read left + if(len > 0) { + len -= readBytes; + } + + delay(0); + } else { + delay(1); + } + } + + free(buff); + + log_v("connection closed or file end (written: %d).", bytesWritten); + + if((size > 0) && (size != bytesWritten)) { + log_d("bytesWritten %d and size %d mismatch!.", bytesWritten, size); + return HTTPC_ERROR_STREAM_WRITE; + } + + } else { + log_w("too less ram! need %d", buff_size); + return HTTPC_ERROR_TOO_LESS_RAM; + } + + return bytesWritten; +} + +/** + * called to handle error return, may disconnect the connection if still exists + * @param error + * @return error + */ +int HTTPClient::returnError(int error) +{ + if(error < 0) { + log_w("error(%d): %s", error, errorToString(error).c_str()); + if(connected()) { + log_d("tcp stop"); + _client->stop(); + } + } + return error; +} + +void HTTPClient::setFollowRedirects(followRedirects_t follow) +{ + _followRedirects = follow; +} + +void HTTPClient::setRedirectLimit(uint16_t limit) +{ + _redirectLimit = limit; +} + +/** + * set the URL to a new value. Handy for following redirects. + * @param url + */ +bool HTTPClient::setURL(const String& url) +{ + // if the new location is only a path then only update the URI + if (url && url[0] == '/') { + _uri = url; + clear(); + return true; + } + + if (!url.startsWith(_protocol + ':')) { + log_d("new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str()); + return false; + } + + // check if the port is specified + int indexPort = url.indexOf(':', 6); // find the first ':' excluding the one from the protocol + int indexURI = url.indexOf('/', 7); // find where the URI starts to make sure the ':' is not part of it + if (indexPort == -1 || indexPort > indexURI) { + // the port is not specified + _port = (_protocol == "https" ? 443 : 80); + } + + // disconnect but preserve _client. + // Also have to keep the connection otherwise it will free some of the memory used by _client + // and will blow up later when trying to do _client->available() or similar + _canReuse = true; + disconnect(true); + return beginInternal(url, _protocol.c_str()); +} + +const String &HTTPClient::getLocation(void) +{ + return _location; +} + +void HTTPClient::setCookieJar(CookieJar* cookieJar) +{ + _cookieJar = cookieJar; +} + +void HTTPClient::resetCookieJar() +{ + _cookieJar = nullptr; +} + +void HTTPClient::clearAllCookies() +{ + if (_cookieJar) _cookieJar->clear(); +} + +void HTTPClient::setCookie(String date, String headerValue) +{ + if (!_cookieJar) + { + return; + } + #define HTTP_TIME_PATTERN "%a, %d %b %Y %H:%M:%S" + + Cookie cookie; + String value; + int pos1, pos2; + + struct tm tm; + strptime(date.c_str(), HTTP_TIME_PATTERN, &tm); + cookie.date = mktime(&tm); + + pos1 = headerValue.indexOf('='); + pos2 = headerValue.indexOf(';'); + + if (pos1 >= 0 && pos2 > pos1){ + cookie.name = headerValue.substring(0, pos1); + cookie.value = headerValue.substring(pos1 + 1, pos2); + } else { + return; // invalid cookie header + } + + // only Cookie Attributes are case insensitive from this point on + headerValue.toLowerCase(); + + // expires + if (headerValue.indexOf("expires=") >= 0){ + pos1 = headerValue.indexOf("expires=") + strlen("expires="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) + value = headerValue.substring(pos1, pos2); + else + value = headerValue.substring(pos1); + + strptime(value.c_str(), HTTP_TIME_PATTERN, &tm); + cookie.expires.date = mktime(&tm); + cookie.expires.valid = true; + } + + // max-age + if (headerValue.indexOf("max-age=") >= 0){ + pos1 = headerValue.indexOf("max-age=") + strlen("max-age="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) + value = headerValue.substring(pos1, pos2); + else + value = headerValue.substring(pos1); + + cookie.max_age.duration = value.toInt(); + cookie.max_age.valid = true; + } + + // domain + if (headerValue.indexOf("domain=") >= 0){ + pos1 = headerValue.indexOf("domain=") + strlen("domain="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) + value = headerValue.substring(pos1, pos2); + else + value = headerValue.substring(pos1); + + if (value.startsWith(".")) value.remove(0, 1); + + if (_host.indexOf(value) >= 0) { + cookie.domain = value; + } else { + return; // server tries to set a cookie on a different domain; ignore it + } + } else { + pos1 = _host.lastIndexOf('.', _host.lastIndexOf('.') - 1); + if (pos1 >= 0) + cookie.domain = _host.substring(pos1 + 1); + else + cookie.domain = _host; + } + + // path + if (headerValue.indexOf("path=") >= 0){ + pos1 = headerValue.indexOf("path=") + strlen("path="); + pos2 = headerValue.indexOf(';', pos1); + + if (pos2 > pos1) + cookie.path = headerValue.substring(pos1, pos2); + else + cookie.path = headerValue.substring(pos1); + } + + // HttpOnly + cookie.http_only = (headerValue.indexOf("httponly") >= 0); + + // secure + cookie.secure = (headerValue.indexOf("secure") >= 0); + + // overwrite or delete cookie in/from cookie jar + time_t now_local = time(NULL); + time_t now_gmt = mktime(gmtime(&now_local)); + + bool found = false; + + for (auto c = _cookieJar->begin(); c != _cookieJar->end(); ++c) { + if (c->domain == cookie.domain && c->name == cookie.name) { + // when evaluating, max-age takes precedence over expires if both are defined + if ((cookie.max_age.valid && ((cookie.date + cookie.max_age.duration) < now_gmt)) || cookie.max_age.duration <= 0 + || (!cookie.max_age.valid && cookie.expires.valid && cookie.expires.date < now_gmt)) { + _cookieJar->erase(c); + c--; + } else { + *c = cookie; + } + found = true; + } + } + + // add cookie to jar + if (!found && !(cookie.max_age.valid && cookie.max_age.duration <= 0)) + _cookieJar->push_back(cookie); + +} + +bool HTTPClient::generateCookieString(String *cookieString) +{ + time_t now_local = time(NULL); + time_t now_gmt = mktime(gmtime(&now_local)); + + *cookieString = ""; + bool found = false; + + if (!_cookieJar) + { + return false; + } + for (auto c = _cookieJar->begin(); c != _cookieJar->end(); ++c) { + if ((c->max_age.valid && ((c->date + c->max_age.duration) < now_gmt)) || (!c->max_age.valid && c->expires.valid && c->expires.date < now_gmt)) { + _cookieJar->erase(c); + c--; + } else if (_host.indexOf(c->domain) >= 0 && (!c->secure || _secure) ) { + if (*cookieString == "") + *cookieString = c->name + "=" + c->value; + else + *cookieString += " ;" + c->name + "=" + c->value; + found = true; + } + } + + return found; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/src/HTTPClient.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/src/HTTPClient.h new file mode 100644 index 0000000..0058c1e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPClient/src/HTTPClient.h @@ -0,0 +1,312 @@ +/** + * HTTPClient.h + * + * Created on: 02.11.2015 + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the HTTPClient for Arduino. + * Port to ESP32 by Evandro Luis Copercini (2017), + * changed fingerprints to CA verification. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef HTTPClient_H_ +#define HTTPClient_H_ + +#ifndef HTTPCLIENT_1_1_COMPATIBLE +#define HTTPCLIENT_1_1_COMPATIBLE +#endif + +#include +#include +#include +#include + +/// Cookie jar support +#include + +#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000) + +/// HTTP client errors +#define HTTPC_ERROR_CONNECTION_REFUSED (-1) +#define HTTPC_ERROR_SEND_HEADER_FAILED (-2) +#define HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) +#define HTTPC_ERROR_NOT_CONNECTED (-4) +#define HTTPC_ERROR_CONNECTION_LOST (-5) +#define HTTPC_ERROR_NO_STREAM (-6) +#define HTTPC_ERROR_NO_HTTP_SERVER (-7) +#define HTTPC_ERROR_TOO_LESS_RAM (-8) +#define HTTPC_ERROR_ENCODING (-9) +#define HTTPC_ERROR_STREAM_WRITE (-10) +#define HTTPC_ERROR_READ_TIMEOUT (-11) + +/// size for the stream handling +#define HTTP_TCP_RX_BUFFER_SIZE (4096) +#define HTTP_TCP_TX_BUFFER_SIZE (1460) + +/// HTTP codes see RFC7231 +typedef enum { + HTTP_CODE_CONTINUE = 100, + HTTP_CODE_SWITCHING_PROTOCOLS = 101, + HTTP_CODE_PROCESSING = 102, + HTTP_CODE_OK = 200, + HTTP_CODE_CREATED = 201, + HTTP_CODE_ACCEPTED = 202, + HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203, + HTTP_CODE_NO_CONTENT = 204, + HTTP_CODE_RESET_CONTENT = 205, + HTTP_CODE_PARTIAL_CONTENT = 206, + HTTP_CODE_MULTI_STATUS = 207, + HTTP_CODE_ALREADY_REPORTED = 208, + HTTP_CODE_IM_USED = 226, + HTTP_CODE_MULTIPLE_CHOICES = 300, + HTTP_CODE_MOVED_PERMANENTLY = 301, + HTTP_CODE_FOUND = 302, + HTTP_CODE_SEE_OTHER = 303, + HTTP_CODE_NOT_MODIFIED = 304, + HTTP_CODE_USE_PROXY = 305, + HTTP_CODE_TEMPORARY_REDIRECT = 307, + HTTP_CODE_PERMANENT_REDIRECT = 308, + HTTP_CODE_BAD_REQUEST = 400, + HTTP_CODE_UNAUTHORIZED = 401, + HTTP_CODE_PAYMENT_REQUIRED = 402, + HTTP_CODE_FORBIDDEN = 403, + HTTP_CODE_NOT_FOUND = 404, + HTTP_CODE_METHOD_NOT_ALLOWED = 405, + HTTP_CODE_NOT_ACCEPTABLE = 406, + HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407, + HTTP_CODE_REQUEST_TIMEOUT = 408, + HTTP_CODE_CONFLICT = 409, + HTTP_CODE_GONE = 410, + HTTP_CODE_LENGTH_REQUIRED = 411, + HTTP_CODE_PRECONDITION_FAILED = 412, + HTTP_CODE_PAYLOAD_TOO_LARGE = 413, + HTTP_CODE_URI_TOO_LONG = 414, + HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_CODE_RANGE_NOT_SATISFIABLE = 416, + HTTP_CODE_EXPECTATION_FAILED = 417, + HTTP_CODE_MISDIRECTED_REQUEST = 421, + HTTP_CODE_UNPROCESSABLE_ENTITY = 422, + HTTP_CODE_LOCKED = 423, + HTTP_CODE_FAILED_DEPENDENCY = 424, + HTTP_CODE_UPGRADE_REQUIRED = 426, + HTTP_CODE_PRECONDITION_REQUIRED = 428, + HTTP_CODE_TOO_MANY_REQUESTS = 429, + HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HTTP_CODE_INTERNAL_SERVER_ERROR = 500, + HTTP_CODE_NOT_IMPLEMENTED = 501, + HTTP_CODE_BAD_GATEWAY = 502, + HTTP_CODE_SERVICE_UNAVAILABLE = 503, + HTTP_CODE_GATEWAY_TIMEOUT = 504, + HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506, + HTTP_CODE_INSUFFICIENT_STORAGE = 507, + HTTP_CODE_LOOP_DETECTED = 508, + HTTP_CODE_NOT_EXTENDED = 510, + HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511 +} t_http_codes; + +typedef enum { + HTTPC_TE_IDENTITY, + HTTPC_TE_CHUNKED +} transferEncoding_t; + +/** + * redirection follow mode. + * + `HTTPC_DISABLE_FOLLOW_REDIRECTS` - no redirection will be followed. + * + `HTTPC_STRICT_FOLLOW_REDIRECTS` - strict RFC2616, only requests using + * GET or HEAD methods will be redirected (using the same method), + * since the RFC requires end-user confirmation in other cases. + * + `HTTPC_FORCE_FOLLOW_REDIRECTS` - all redirections will be followed, + * regardless of a used method. New request will use the same method, + * and they will include the same body data and the same headers. + * In the sense of the RFC, it's just like every redirection is confirmed. + */ +typedef enum { + HTTPC_DISABLE_FOLLOW_REDIRECTS, + HTTPC_STRICT_FOLLOW_REDIRECTS, + HTTPC_FORCE_FOLLOW_REDIRECTS +} followRedirects_t; + + +#ifdef HTTPCLIENT_1_1_COMPATIBLE +class TransportTraits; +typedef std::unique_ptr TransportTraitsPtr; +#endif + +// cookie jar support +typedef struct { + String host; // host which tries to set the cookie + time_t date; // timestamp of the response that set the cookie + String name; + String value; + String domain; + String path = ""; + struct { + time_t date = 0; + bool valid = false; + } expires; + struct { + time_t duration = 0; + bool valid = false; + } max_age; + bool http_only = false; + bool secure = false; +} Cookie; +typedef std::vector CookieJar; + + +class HTTPClient +{ +public: + HTTPClient(); + ~HTTPClient(); + +/* + * Since both begin() functions take a reference to client as a parameter, you need to + * ensure the client object lives the entire time of the HTTPClient + */ + bool begin(WiFiClient &client, String url); + bool begin(WiFiClient &client, String host, uint16_t port, String uri = "/", bool https = false); + +#ifdef HTTPCLIENT_1_1_COMPATIBLE + bool begin(String url); + bool begin(String url, const char* CAcert); + bool begin(String host, uint16_t port, String uri = "/"); + bool begin(String host, uint16_t port, String uri, const char* CAcert); + bool begin(String host, uint16_t port, String uri, const char* CAcert, const char* cli_cert, const char* cli_key); +#endif + + void end(void); + + bool connected(void); + + void setReuse(bool reuse); /// keep-alive + void setUserAgent(const String& userAgent); + void setAuthorization(const char * user, const char * password); + void setAuthorization(const char * auth); + void setAuthorizationType(const char * authType); + void setConnectTimeout(int32_t connectTimeout); + void setTimeout(uint16_t timeout); + + // Redirections + void setFollowRedirects(followRedirects_t follow); + void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request + + bool setURL(const String &url); + void useHTTP10(bool usehttp10 = true); + + /// request handling + int GET(); + int PATCH(uint8_t * payload, size_t size); + int PATCH(String payload); + int POST(uint8_t * payload, size_t size); + int POST(String payload); + int PUT(uint8_t * payload, size_t size); + int PUT(String payload); + int sendRequest(const char * type, String payload); + int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0); + int sendRequest(const char * type, Stream * stream, size_t size = 0); + + void addHeader(const String& name, const String& value, bool first = false, bool replace = true); + + /// Response handling + void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); + String header(const char* name); // get request header value by name + String header(size_t i); // get request header value by number + String headerName(size_t i); // get request header name by number + int headers(); // get header count + bool hasHeader(const char* name); // check if header exists + + + int getSize(void); + const String &getLocation(void); + + WiFiClient& getStream(void); + WiFiClient* getStreamPtr(void); + int writeToStream(Stream* stream); + String getString(void); + + static String errorToString(int error); + + /// Cookie jar support + void setCookieJar(CookieJar* cookieJar); + void resetCookieJar(); + void clearAllCookies(); + +protected: + struct RequestArgument { + String key; + String value; + }; + + bool beginInternal(String url, const char* expectedProtocol); + void disconnect(bool preserveClient = false); + void clear(); + int returnError(int error); + bool connect(void); + bool sendHeader(const char * type); + int handleHeaderResponse(); + int writeToStreamDataBlock(Stream * stream, int len); + + /// Cookie jar support + void setCookie(String date, String headerValue); + bool generateCookieString(String *cookieString); + +#ifdef HTTPCLIENT_1_1_COMPATIBLE + TransportTraitsPtr _transportTraits; + std::unique_ptr _tcpDeprecated; +#endif + + WiFiClient* _client = nullptr; + + /// request handling + String _host; + uint16_t _port = 0; + int32_t _connectTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; + bool _reuse = true; + uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; + bool _useHTTP10 = false; + bool _secure = false; + + String _uri; + String _protocol; + String _headers; + String _userAgent = "ESP32HTTPClient"; + String _base64Authorization; + String _authorizationType = "Basic"; + + /// Response handling + RequestArgument* _currentHeaders = nullptr; + size_t _headerKeysCount = 0; + + int _returnCode = 0; + int _size = -1; + bool _canReuse = false; + followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS; + uint16_t _redirectLimit = 10; + String _location; + transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY; + + /// Cookie jar support + CookieJar* _cookieJar = nullptr; + +}; + + + +#endif /* HTTPClient_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdate/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdate/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdate/httpUpdate.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdate/httpUpdate.ino new file mode 100644 index 0000000..3a612da --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdate/httpUpdate.ino @@ -0,0 +1,93 @@ +/** + httpUpdate.ino + + Created on: 27.11.2015 + +*/ + +#include + +#include +#include + +#include +#include + +WiFiMulti WiFiMulti; + +void setup() { + + Serial.begin(115200); + // Serial.setDebugOutput(true); + + Serial.println(); + Serial.println(); + Serial.println(); + + for (uint8_t t = 4; t > 0; t--) { + Serial.printf("[SETUP] WAIT %d...\n", t); + Serial.flush(); + delay(1000); + } + + WiFi.mode(WIFI_STA); + WiFiMulti.addAP("SSID", "PASSWORD"); + + +} + +void update_started() { + Serial.println("CALLBACK: HTTP update process started"); +} + +void update_finished() { + Serial.println("CALLBACK: HTTP update process finished"); +} + +void update_progress(int cur, int total) { + Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total); +} + +void update_error(int err) { + Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err); +} + +void loop() { + // wait for WiFi connection + if ((WiFiMulti.run() == WL_CONNECTED)) { + + WiFiClient client; + + // The line below is optional. It can be used to blink the LED on the board during flashing + // The LED will be on during download of one buffer of data from the network. The LED will + // be off during writing that buffer to flash + // On a good connection the LED should flash regularly. On a bad connection the LED will be + // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second + // value is used to put the LED on. If the LED is on with HIGH, that value should be passed + // httpUpdate.setLedPin(LED_BUILTIN, LOW); + + httpUpdate.onStart(update_started); + httpUpdate.onEnd(update_finished); + httpUpdate.onProgress(update_progress); + httpUpdate.onError(update_error); + + t_httpUpdate_return ret = httpUpdate.update(client, "http://server/file.bin"); + // Or: + //t_httpUpdate_return ret = httpUpdate.update(client, "server", 80, "/file.bin"); + + switch (ret) { + case HTTP_UPDATE_FAILED: + Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); + break; + + case HTTP_UPDATE_NO_UPDATES: + Serial.println("HTTP_UPDATE_NO_UPDATES"); + break; + + case HTTP_UPDATE_OK: + Serial.println("HTTP_UPDATE_OK"); + break; + } + } +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/httpUpdateSPIFFS.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/httpUpdateSPIFFS.ino new file mode 100644 index 0000000..a07e6d2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSPIFFS/httpUpdateSPIFFS.ino @@ -0,0 +1,75 @@ +/** + httpUpdateSPIFFS.ino + + Created on: 05.12.2015 + +*/ + +#include + +#include +#include + +#include +#include + +WiFiMulti WiFiMulti; + +void setup() { + + Serial.begin(115200); + // Serial.setDebugOutput(true); + + Serial.println(); + Serial.println(); + Serial.println(); + + for (uint8_t t = 4; t > 0; t--) { + Serial.printf("[SETUP] WAIT %d...\n", t); + Serial.flush(); + delay(1000); + } + + WiFi.mode(WIFI_STA); + WiFiMulti.addAP("SSID", "PASSWORD"); + +} + +void loop() { + // wait for WiFi connection + if ((WiFiMulti.run() == WL_CONNECTED)) { + + Serial.println("Update SPIFFS..."); + + WiFiClient client; + + // The line below is optional. It can be used to blink the LED on the board during flashing + // The LED will be on during download of one buffer of data from the network. The LED will + // be off during writing that buffer to flash + // On a good connection the LED should flash regularly. On a bad connection the LED will be + // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second + // value is used to put the LED on. If the LED is on with HIGH, that value should be passed + // httpUpdate.setLedPin(LED_BUILTIN, LOW); + + t_httpUpdate_return ret = httpUpdate.updateSpiffs(client, "http://server/spiffs.bin"); + if (ret == HTTP_UPDATE_OK) { + Serial.println("Update sketch..."); + ret = httpUpdate.update(client, "http://server/file.bin"); + + switch (ret) { + case HTTP_UPDATE_FAILED: + Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); + break; + + case HTTP_UPDATE_NO_UPDATES: + Serial.println("HTTP_UPDATE_NO_UPDATES"); + break; + + case HTTP_UPDATE_OK: + Serial.println("HTTP_UPDATE_OK"); + break; + } + } + } +} + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSecure/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSecure/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSecure/httpUpdateSecure.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSecure/httpUpdateSecure.ino new file mode 100644 index 0000000..2028d19 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/examples/httpUpdateSecure/httpUpdateSecure.ino @@ -0,0 +1,130 @@ +/** + httpUpdateSecure.ino + + Created on: 16.10.2018 as an adaptation of the ESP8266 version of httpUpdate.ino + +*/ + +#include +#include + +#include +#include + +#include + +WiFiMulti WiFiMulti; + +// Set time via NTP, as required for x.509 validation +void setClock() { + configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC + + Serial.print(F("Waiting for NTP time sync: ")); + time_t now = time(nullptr); + while (now < 8 * 3600 * 2) { + yield(); + delay(500); + Serial.print(F(".")); + now = time(nullptr); + } + + Serial.println(F("")); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print(F("Current time: ")); + Serial.print(asctime(&timeinfo)); +} + +/** + * This is lets-encrypt-x3-cross-signed.pem + */ +const char* rootCACertificate = \ +"-----BEGIN CERTIFICATE-----\n" \ +"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \ +"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \ +"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \ +"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \ +"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\n" \ +"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\n" \ +"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\n" \ +"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\n" \ +"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\n" \ +"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\n" \ +"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\n" \ +"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\n" \ +"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\n" \ +"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\n" \ +"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\n" \ +"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\n" \ +"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\n" \ +"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\n" \ +"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\n" \ +"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\n" \ +"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\n" \ +"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\n" \ +"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\n" \ +"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\n" \ +"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \ +"-----END CERTIFICATE-----\n"; + +void setup() { + + Serial.begin(115200); + // Serial.setDebugOutput(true); + + Serial.println(); + Serial.println(); + Serial.println(); + + for (uint8_t t = 4; t > 0; t--) { + Serial.printf("[SETUP] WAIT %d...\n", t); + Serial.flush(); + delay(1000); + } + + WiFi.mode(WIFI_STA); + WiFiMulti.addAP("SSID", "PASSWORD"); +} + +void loop() { + // wait for WiFi connection + if ((WiFiMulti.run() == WL_CONNECTED)) { + + setClock(); + + WiFiClientSecure client; + client.setCACert(rootCACertificate); + + // Reading data over SSL may be slow, use an adequate timeout + client.setTimeout(12000 / 1000); // timeout argument is defined in seconds for setTimeout + + // The line below is optional. It can be used to blink the LED on the board during flashing + // The LED will be on during download of one buffer of data from the network. The LED will + // be off during writing that buffer to flash + // On a good connection the LED should flash regularly. On a bad connection the LED will be + // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second + // value is used to put the LED on. If the LED is on with HIGH, that value should be passed + // httpUpdate.setLedPin(LED_BUILTIN, HIGH); + + t_httpUpdate_return ret = httpUpdate.update(client, "https://server/file.bin", "", [](HTTPClient *client) { + client->setAuthorization("test", "password"); + }); + // Or: + //t_httpUpdate_return ret = httpUpdate.update(client, "server", 443, "/file.bin"); + + + switch (ret) { + case HTTP_UPDATE_FAILED: + Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); + break; + + case HTTP_UPDATE_NO_UPDATES: + Serial.println("HTTP_UPDATE_NO_UPDATES"); + break; + + case HTTP_UPDATE_OK: + Serial.println("HTTP_UPDATE_OK"); + break; + } + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/keywords.txt new file mode 100644 index 0000000..a882d8c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/keywords.txt @@ -0,0 +1,42 @@ +####################################### +# Syntax Coloring Map For HTTPUpdate +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +ESP32httpUpdate KEYWORD3 RESERVED_WORD + +####################################### +# Datatypes (KEYWORD1) +####################################### + +HTTPUpdateResult KEYWORD1 DATA_TYPE +httpUpdate KEYWORD1 DATA_TYPE + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +rebootOnUpdate KEYWORD2 +update KEYWORD2 +updateSpiffs KEYWORD2 +getLastError KEYWORD2 +getLastErrorString KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +HTTP_UE_TOO_LESS_SPACE LITERAL1 RESERVED_WORD_2 +HTTP_UE_SERVER_NOT_REPORT_SIZE LITERAL1 RESERVED_WORD_2 +HTTP_UE_SERVER_FILE_NOT_FOUND LITERAL1 RESERVED_WORD_2 +HTTP_UE_SERVER_FORBIDDEN LITERAL1 RESERVED_WORD_2 +HTTP_UE_SERVER_WRONG_HTTP_CODE LITERAL1 RESERVED_WORD_2 +HTTP_UE_SERVER_FAULTY_MD5 LITERAL1 RESERVED_WORD_2 +HTTP_UE_BIN_VERIFY_HEADER_FAILED LITERAL1 RESERVED_WORD_2 +HTTP_UE_BIN_FOR_WRONG_FLASH LITERAL1 RESERVED_WORD_2 +HTTP_UPDATE_FAILED LITERAL1 RESERVED_WORD_2 +HTTP_UPDATE_NO_UPDATES LITERAL1 RESERVED_WORD_2 +HTTP_UPDATE_OK LITERAL1 RESERVED_WORD_2 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/library.properties new file mode 100644 index 0000000..0423e70 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/library.properties @@ -0,0 +1,9 @@ +name=HTTPUpdate +version=2.0.0 +author=Markus Sattler +maintainer=Markus Sattler +sentence=Http Update for ESP32 +paragraph= +category=Data Processing +url=https://github.com/Links2004/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/ESP8266httpUpdate +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/src/HTTPUpdate.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/src/HTTPUpdate.cpp new file mode 100644 index 0000000..ceaf021 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/src/HTTPUpdate.cpp @@ -0,0 +1,454 @@ +/** + * + * @file HTTPUpdate.cpp based om ESP8266HTTPUpdate.cpp + * @date 16.10.2018 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP32 Http Updater. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "HTTPUpdate.h" +#include + +#include +#include // get running partition + +// To do extern "C" uint32_t _SPIFFS_start; +// To do extern "C" uint32_t _SPIFFS_end; + +HTTPUpdate::HTTPUpdate(void) + : _httpClientTimeout(8000), _ledPin(-1) +{ + _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS; +} + +HTTPUpdate::HTTPUpdate(int httpClientTimeout) + : _httpClientTimeout(httpClientTimeout), _ledPin(-1) +{ + _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS; +} + +HTTPUpdate::~HTTPUpdate(void) +{ +} + +HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& url, const String& currentVersion, HTTPUpdateRequestCB requestCB) +{ + HTTPClient http; + if(!http.begin(client, url)) + { + return HTTP_UPDATE_FAILED; + } + return handleUpdate(http, currentVersion, false, requestCB); +} + +HTTPUpdateResult HTTPUpdate::updateSpiffs(HTTPClient& httpClient, const String& currentVersion, HTTPUpdateRequestCB requestCB) +{ + return handleUpdate(httpClient, currentVersion, true, requestCB); +} + +HTTPUpdateResult HTTPUpdate::updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion, HTTPUpdateRequestCB requestCB) +{ + HTTPClient http; + if(!http.begin(client, url)) + { + return HTTP_UPDATE_FAILED; + } + return handleUpdate(http, currentVersion, true, requestCB); +} + +HTTPUpdateResult HTTPUpdate::update(HTTPClient& httpClient, + const String& currentVersion, HTTPUpdateRequestCB requestCB) +{ + return handleUpdate(httpClient, currentVersion, false, requestCB); +} + +HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& host, uint16_t port, const String& uri, + const String& currentVersion, HTTPUpdateRequestCB requestCB) +{ + HTTPClient http; + if(!http.begin(client, host, port, uri)) + { + return HTTP_UPDATE_FAILED; + } + return handleUpdate(http, currentVersion, false, requestCB); +} + +/** + * return error code as int + * @return int error code + */ +int HTTPUpdate::getLastError(void) +{ + return _lastError; +} + +/** + * return error code as String + * @return String error + */ +String HTTPUpdate::getLastErrorString(void) +{ + + if(_lastError == 0) { + return String(); // no error + } + + // error from Update class + if(_lastError > 0) { + StreamString error; + Update.printError(error); + error.trim(); // remove line ending + return String("Update error: ") + error; + } + + // error from http client + if(_lastError > -100) { + return String("HTTP error: ") + HTTPClient::errorToString(_lastError); + } + + switch(_lastError) { + case HTTP_UE_TOO_LESS_SPACE: + return "Not Enough space"; + case HTTP_UE_SERVER_NOT_REPORT_SIZE: + return "Server Did Not Report Size"; + case HTTP_UE_SERVER_FILE_NOT_FOUND: + return "File Not Found (404)"; + case HTTP_UE_SERVER_FORBIDDEN: + return "Forbidden (403)"; + case HTTP_UE_SERVER_WRONG_HTTP_CODE: + return "Wrong HTTP Code"; + case HTTP_UE_SERVER_FAULTY_MD5: + return "Wrong MD5"; + case HTTP_UE_BIN_VERIFY_HEADER_FAILED: + return "Verify Bin Header Failed"; + case HTTP_UE_BIN_FOR_WRONG_FLASH: + return "New Binary Does Not Fit Flash Size"; + case HTTP_UE_NO_PARTITION: + return "Partition Could Not be Found"; + } + + return String(); +} + + +String getSketchSHA256() { + const size_t HASH_LEN = 32; // SHA-256 digest length + + uint8_t sha_256[HASH_LEN] = { 0 }; + +// get sha256 digest for running partition + if(esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256) == 0) { + char buffer[2 * HASH_LEN + 1]; + + for(size_t index = 0; index < HASH_LEN; index++) { + uint8_t nibble = (sha_256[index] & 0xf0) >> 4; + buffer[2 * index] = nibble < 10 ? char(nibble + '0') : char(nibble - 10 + 'A'); + + nibble = sha_256[index] & 0x0f; + buffer[2 * index + 1] = nibble < 10 ? char(nibble + '0') : char(nibble - 10 + 'A'); + } + + buffer[2 * HASH_LEN] = '\0'; + + return String(buffer); + } else { + + return String(); + } +} + +/** + * + * @param http HTTPClient * + * @param currentVersion const char * + * @return HTTPUpdateResult + */ +HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs, HTTPUpdateRequestCB requestCB) +{ + + HTTPUpdateResult ret = HTTP_UPDATE_FAILED; + + // use HTTP/1.0 for update since the update handler not support any transfer Encoding + http.useHTTP10(true); + http.setTimeout(_httpClientTimeout); + http.setFollowRedirects(_followRedirects); + http.setUserAgent("ESP32-http-Update"); + http.addHeader("Cache-Control", "no-cache"); + http.addHeader("x-ESP32-STA-MAC", WiFi.macAddress()); + http.addHeader("x-ESP32-AP-MAC", WiFi.softAPmacAddress()); + http.addHeader("x-ESP32-free-space", String(ESP.getFreeSketchSpace())); + http.addHeader("x-ESP32-sketch-size", String(ESP.getSketchSize())); + String sketchMD5 = ESP.getSketchMD5(); + if(sketchMD5.length() != 0) { + http.addHeader("x-ESP32-sketch-md5", sketchMD5); + } + // Add also a SHA256 + String sketchSHA256 = getSketchSHA256(); + if(sketchSHA256.length() != 0) { + http.addHeader("x-ESP32-sketch-sha256", sketchSHA256); + } + http.addHeader("x-ESP32-chip-size", String(ESP.getFlashChipSize())); + http.addHeader("x-ESP32-sdk-version", ESP.getSdkVersion()); + + if(spiffs) { + http.addHeader("x-ESP32-mode", "spiffs"); + } else { + http.addHeader("x-ESP32-mode", "sketch"); + } + + if(currentVersion && currentVersion[0] != 0x00) { + http.addHeader("x-ESP32-version", currentVersion); + } + if (requestCB) { + requestCB(&http); + } + + const char * headerkeys[] = { "x-MD5" }; + size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*); + + // track these headers + http.collectHeaders(headerkeys, headerkeyssize); + + + int code = http.GET(); + int len = http.getSize(); + + if(code <= 0) { + log_e("HTTP error: %s\n", http.errorToString(code).c_str()); + _lastError = code; + http.end(); + return HTTP_UPDATE_FAILED; + } + + + log_d("Header read fin.\n"); + log_d("Server header:\n"); + log_d(" - code: %d\n", code); + log_d(" - len: %d\n", len); + + if(http.hasHeader("x-MD5")) { + log_d(" - MD5: %s\n", http.header("x-MD5").c_str()); + } + + log_d("ESP32 info:\n"); + log_d(" - free Space: %d\n", ESP.getFreeSketchSpace()); + log_d(" - current Sketch Size: %d\n", ESP.getSketchSize()); + + if(currentVersion && currentVersion[0] != 0x00) { + log_d(" - current version: %s\n", currentVersion.c_str() ); + } + + switch(code) { + case HTTP_CODE_OK: ///< OK (Start Update) + if(len > 0) { + bool startUpdate = true; + if(spiffs) { + const esp_partition_t* _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); + if(!_partition){ + _lastError = HTTP_UE_NO_PARTITION; + return HTTP_UPDATE_FAILED; + } + + if(len > _partition->size) { + log_e("spiffsSize to low (%d) needed: %d\n", _partition->size, len); + startUpdate = false; + } + } else { + int sketchFreeSpace = ESP.getFreeSketchSpace(); + if(!sketchFreeSpace){ + _lastError = HTTP_UE_NO_PARTITION; + return HTTP_UPDATE_FAILED; + } + + if(len > sketchFreeSpace) { + log_e("FreeSketchSpace to low (%d) needed: %d\n", sketchFreeSpace, len); + startUpdate = false; + } + } + + if(!startUpdate) { + _lastError = HTTP_UE_TOO_LESS_SPACE; + ret = HTTP_UPDATE_FAILED; + } else { + // Warn main app we're starting up... + if (_cbStart) { + _cbStart(); + } + + WiFiClient * tcp = http.getStreamPtr(); + +// To do? WiFiUDP::stopAll(); +// To do? WiFiClient::stopAllExcept(tcp); + + delay(100); + + int command; + + if(spiffs) { + command = U_SPIFFS; + log_d("runUpdate spiffs...\n"); + } else { + command = U_FLASH; + log_d("runUpdate flash...\n"); + } + + if(!spiffs) { +/* To do + uint8_t buf[4]; + if(tcp->peekBytes(&buf[0], 4) != 4) { + log_e("peekBytes magic header failed\n"); + _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + http.end(); + return HTTP_UPDATE_FAILED; + } +*/ + + // check for valid first magic byte +// if(buf[0] != 0xE9) { + if(tcp->peek() != 0xE9) { + log_e("Magic header does not start with 0xE9\n"); + _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + http.end(); + return HTTP_UPDATE_FAILED; + + } +/* To do + uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4); + + // check if new bin fits to SPI flash + if(bin_flash_size > ESP.getFlashChipRealSize()) { + log_e("New binary does not fit SPI Flash size\n"); + _lastError = HTTP_UE_BIN_FOR_WRONG_FLASH; + http.end(); + return HTTP_UPDATE_FAILED; + } +*/ + } + if(runUpdate(*tcp, len, http.header("x-MD5"), command)) { + ret = HTTP_UPDATE_OK; + log_d("Update ok\n"); + http.end(); + // Warn main app we're all done + if (_cbEnd) { + _cbEnd(); + } + + if(_rebootOnUpdate && !spiffs) { + ESP.restart(); + } + + } else { + ret = HTTP_UPDATE_FAILED; + log_e("Update failed\n"); + } + } + } else { + _lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE; + ret = HTTP_UPDATE_FAILED; + log_e("Content-Length was 0 or wasn't set by Server?!\n"); + } + break; + case HTTP_CODE_NOT_MODIFIED: + ///< Not Modified (No updates) + ret = HTTP_UPDATE_NO_UPDATES; + break; + case HTTP_CODE_NOT_FOUND: + _lastError = HTTP_UE_SERVER_FILE_NOT_FOUND; + ret = HTTP_UPDATE_FAILED; + break; + case HTTP_CODE_FORBIDDEN: + _lastError = HTTP_UE_SERVER_FORBIDDEN; + ret = HTTP_UPDATE_FAILED; + break; + default: + _lastError = HTTP_UE_SERVER_WRONG_HTTP_CODE; + ret = HTTP_UPDATE_FAILED; + log_e("HTTP Code is (%d)\n", code); + break; + } + + http.end(); + return ret; +} + +/** + * write Update to flash + * @param in Stream& + * @param size uint32_t + * @param md5 String + * @return true if Update ok + */ +bool HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int command) +{ + + StreamString error; + + if (_cbProgress) { + Update.onProgress(_cbProgress); + } + + if(!Update.begin(size, command, _ledPin, _ledOn)) { + _lastError = Update.getError(); + Update.printError(error); + error.trim(); // remove line ending + log_e("Update.begin failed! (%s)\n", error.c_str()); + return false; + } + + if (_cbProgress) { + _cbProgress(0, size); + } + + if(md5.length()) { + if(!Update.setMD5(md5.c_str())) { + _lastError = HTTP_UE_SERVER_FAULTY_MD5; + log_e("Update.setMD5 failed! (%s)\n", md5.c_str()); + return false; + } + } + +// To do: the SHA256 could be checked if the server sends it + + if(Update.writeStream(in) != size) { + _lastError = Update.getError(); + Update.printError(error); + error.trim(); // remove line ending + log_e("Update.writeStream failed! (%s)\n", error.c_str()); + return false; + } + + if (_cbProgress) { + _cbProgress(size, size); + } + + if(!Update.end()) { + _lastError = Update.getError(); + Update.printError(error); + error.trim(); // remove line ending + log_e("Update.end failed! (%s)\n", error.c_str()); + return false; + } + + return true; +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE) +HTTPUpdate httpUpdate; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/src/HTTPUpdate.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/src/HTTPUpdate.h new file mode 100644 index 0000000..0847deb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdate/src/HTTPUpdate.h @@ -0,0 +1,141 @@ +/** + * + * @file HTTPUpdate.h based on ESP8266HTTPUpdate.h + * @date 16.10.2018 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP32 Http Updater. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef ___HTTP_UPDATE_H___ +#define ___HTTP_UPDATE_H___ + +#include +#include +#include +#include +#include +#include + +/// note we use HTTP client errors too so we start at 100 +#define HTTP_UE_TOO_LESS_SPACE (-100) +#define HTTP_UE_SERVER_NOT_REPORT_SIZE (-101) +#define HTTP_UE_SERVER_FILE_NOT_FOUND (-102) +#define HTTP_UE_SERVER_FORBIDDEN (-103) +#define HTTP_UE_SERVER_WRONG_HTTP_CODE (-104) +#define HTTP_UE_SERVER_FAULTY_MD5 (-105) +#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106) +#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107) +#define HTTP_UE_NO_PARTITION (-108) + +enum HTTPUpdateResult { + HTTP_UPDATE_FAILED, + HTTP_UPDATE_NO_UPDATES, + HTTP_UPDATE_OK +}; + +typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility + +using HTTPUpdateStartCB = std::function; +using HTTPUpdateRequestCB = std::function; +using HTTPUpdateEndCB = std::function; +using HTTPUpdateErrorCB = std::function; +using HTTPUpdateProgressCB = std::function; + +class HTTPUpdate +{ +public: + HTTPUpdate(void); + HTTPUpdate(int httpClientTimeout); + ~HTTPUpdate(void); + + void rebootOnUpdate(bool reboot) + { + _rebootOnUpdate = reboot; + } + + /** + * set redirect follow mode. See `followRedirects_t` enum for avaliable modes. + * @param follow + */ + void setFollowRedirects(followRedirects_t follow) + { + _followRedirects = follow; + } + + void setLedPin(int ledPin = -1, uint8_t ledOn = HIGH) + { + _ledPin = ledPin; + _ledOn = ledOn; + } + + t_httpUpdate_return update(WiFiClient& client, const String& url, const String& currentVersion = "", HTTPUpdateRequestCB requestCB = NULL); + + t_httpUpdate_return update(WiFiClient& client, const String& host, uint16_t port, const String& uri = "/", + const String& currentVersion = "", HTTPUpdateRequestCB requestCB = NULL); + + t_httpUpdate_return updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion = "", HTTPUpdateRequestCB requestCB = NULL); + + t_httpUpdate_return update(HTTPClient& httpClient, + const String& currentVersion = "", + HTTPUpdateRequestCB requestCB = NULL); + + t_httpUpdate_return updateSpiffs(HTTPClient &httpClient, const String ¤tVersion = "", HTTPUpdateRequestCB requestCB = NULL); + + // Notification callbacks + void onStart(HTTPUpdateStartCB cbOnStart) { _cbStart = cbOnStart; } + void onEnd(HTTPUpdateEndCB cbOnEnd) { _cbEnd = cbOnEnd; } + void onError(HTTPUpdateErrorCB cbOnError) { _cbError = cbOnError; } + void onProgress(HTTPUpdateProgressCB cbOnProgress) { _cbProgress = cbOnProgress; } + + int getLastError(void); + String getLastErrorString(void); + +protected: + t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false, HTTPUpdateRequestCB requestCB = NULL); + bool runUpdate(Stream& in, uint32_t size, String md5, int command = U_FLASH); + + // Set the error and potentially use a CB to notify the application + void _setLastError(int err) { + _lastError = err; + if (_cbError) { + _cbError(err); + } + } + int _lastError; + bool _rebootOnUpdate = true; +private: + int _httpClientTimeout; + followRedirects_t _followRedirects; + + // Callbacks + HTTPUpdateStartCB _cbStart; + HTTPUpdateEndCB _cbEnd; + HTTPUpdateErrorCB _cbError; + HTTPUpdateProgressCB _cbProgress; + + int _ledPin; + uint8_t _ledOn; +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE) +extern HTTPUpdate httpUpdate; +#endif + +#endif /* ___HTTP_UPDATE_H___ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/examples/WebUpdater/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/examples/WebUpdater/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino new file mode 100644 index 0000000..21688c3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino @@ -0,0 +1,50 @@ +/* + To upload through terminal you can use: curl -F "image=@firmware.bin" esp32-webupdate.local/update +*/ + +#include +#include +#include +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* host = "esp32-webupdate"; +const char* ssid = STASSID; +const char* password = STAPSK; + +WebServer httpServer(80); +HTTPUpdateServer httpUpdater; + +void setup(void) { + + Serial.begin(115200); + Serial.println(); + Serial.println("Booting Sketch..."); + WiFi.mode(WIFI_AP_STA); + WiFi.begin(ssid, password); + + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + WiFi.begin(ssid, password); + Serial.println("WiFi failed, retrying."); + } + + if (MDNS.begin(host)) { + Serial.println("mDNS responder started"); + } + + + httpUpdater.setup(&httpServer); + httpServer.begin(); + + MDNS.addService("http", "tcp", 80); + Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host); +} + +void loop(void) { + httpServer.handleClient(); +} \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/keywords.txt new file mode 100644 index 0000000..a6f8a0c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/keywords.txt @@ -0,0 +1,20 @@ +####################################### +# Syntax Coloring Map For HTTPUpdateServer +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ESP32HTTPUpdateServer KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setup KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/library.properties new file mode 100644 index 0000000..a1e448c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/library.properties @@ -0,0 +1,9 @@ +name=HTTPUpdateServer +version=2.0.0 +author=Hristo Kapanakov +maintainer= +sentence=Simple HTTP Update server based on the WebServer +paragraph=The library accepts HTTP post requests to the /update url, and updates the ESP32 firmware. +category=Communication +url= +architectures=esp32 \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/src/HTTPUpdateServer.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/src/HTTPUpdateServer.h new file mode 100644 index 0000000..aa53ce6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/HTTPUpdateServer/src/HTTPUpdateServer.h @@ -0,0 +1,166 @@ +#ifndef __HTTP_UPDATE_SERVER_H +#define __HTTP_UPDATE_SERVER_H + +#include +#include +#include +#include + + +static const char serverIndex[] PROGMEM = +R"( + + + + + + +
+ Firmware:
+ + +
+
+ FileSystem:
+ + +
+ + )"; +static const char successResponse[] PROGMEM = +"Update Success! Rebooting..."; + +class HTTPUpdateServer +{ +public: + HTTPUpdateServer(bool serial_debug=false) { + _serial_output = serial_debug; + _server = NULL; + _username = emptyString; + _password = emptyString; + _authenticated = false; + } + + void setup(WebServer *server) + { + setup(server, emptyString, emptyString); + } + + void setup(WebServer *server, const String& path) + { + setup(server, path, emptyString, emptyString); + } + + void setup(WebServer *server, const String& username, const String& password) + { + setup(server, "/update", username, password); + } + + void setup(WebServer *server, const String& path, const String& username, const String& password) + { + + _server = server; + _username = username; + _password = password; + + // handler for the /update form page + _server->on(path.c_str(), HTTP_GET, [&]() { + if (_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str())) + return _server->requestAuthentication(); + _server->send_P(200, PSTR("text/html"), serverIndex); + }); + + // handler for the /update form POST (once file upload finishes) + _server->on(path.c_str(), HTTP_POST, [&]() { + if (!_authenticated) + return _server->requestAuthentication(); + if (Update.hasError()) { + _server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError); + } + else { + _server->client().setNoDelay(true); + _server->send_P(200, PSTR("text/html"), successResponse); + delay(100); + _server->client().stop(); + ESP.restart(); + } + }, [&]() { + // handler for the file upload, get's the sketch bytes, and writes + // them through the Update object + HTTPUpload& upload = _server->upload(); + + if (upload.status == UPLOAD_FILE_START) { + _updaterError.clear(); + if (_serial_output) + Serial.setDebugOutput(true); + + _authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str())); + if (!_authenticated) { + if (_serial_output) + Serial.printf("Unauthenticated Update\n"); + return; + } + + if (_serial_output) + Serial.printf("Update: %s\n", upload.filename.c_str()); + if (upload.name == "filesystem") { + if (!Update.begin(SPIFFS.totalBytes(), U_SPIFFS)) {//start with max available size + if (_serial_output) Update.printError(Serial); + } + } + else { + uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; + if (!Update.begin(maxSketchSpace, U_FLASH)) {//start with max available size + _setUpdaterError(); + } + } + } + else if (_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()) { + if (_serial_output) Serial.printf("."); + if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { + _setUpdaterError(); + } + } + else if (_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()) { + if (Update.end(true)) { //true to set the size to the current progress + if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } + else { + _setUpdaterError(); + } + if (_serial_output) Serial.setDebugOutput(false); + } + else if (_authenticated && upload.status == UPLOAD_FILE_ABORTED) { + Update.end(); + if (_serial_output) Serial.println("Update was aborted"); + } + delay(0); + }); + } + + void updateCredentials(const String& username, const String& password) + { + _username = username; + _password = password; + } + +protected: + void _setUpdaterError() + { + if (_serial_output) Update.printError(Serial); + StreamString str; + Update.printError(str); + _updaterError = str.c_str(); + } + +private: + bool _serial_output; + WebServer *_server; + String _username; + String _password; + bool _authenticated; + String _updaterError; +}; + + +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/ADCPlotter.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/ADCPlotter.ino new file mode 100644 index 0000000..5f3bd93 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/ADCPlotter/ADCPlotter.ino @@ -0,0 +1,86 @@ +/* + This example is only for ESP devices. + + This example demonstrates usage of integrated Digital to Analog Converter (DAC) + You can display sound wave from audio device, or just measure voltage. + + To display audio prepare circuit found in following link or drafted as ASCII art + https://forum.arduino.cc/index.php?topic=567581.0 + (!) Note that unlike in the link we are connecting the supply line to 3.3V (not 5V) + because ADC can measure only up to around 3V. Anything above 3V will be very inaccurate. + + ^ +3.3V + | + _ + | |10k + |_| + | | |10uF + GPIO34-------------*------------| |----------- line in +(Default ADC pin) | +| | + | + _ + | |10k + |_| + | + | + V GND + +Connect hot wire of your audio to Line in and GNd wire of audio cable to common ground (GND) + +Second option to measure voltage on trimmer / potentiometer has following connection + ^ +3.3V + | + _ + | | + GPIO34----------->| | +(Default ADC pin) |_| + | + | + _ + | | optional resistor + |_| + | + | + V GND + Optional resistor will decrease read value. + + Steps to run: + 1. Select target board: + Tools -> Board -> ESP32 Arduino -> your board + 2. Upload sketch + Press upload button (arrow in top left corner) + When you see in console line like this: "Connecting........_____.....__" + On your board press and hold Boot button and press EN button shortly. Now you can release both buttons. + You should see lines like this: "Writing at 0x00010000... (12 %)" with rising percentage on each line. + If this fails, try the board buttons right after pressing upload button, or reconnect the USB cable. + 3. Open plotter + Tools -> Serial Plotter + Enjoy + +Created by Tomas Pilny +on 17th June 2021 +*/ + +#include + +void setup() { + // Open serial communications and wait for port to open: + // A baud rate of 115200 is used instead of 9600 for a faster data rate + // on non-native USB ports + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start I2S at 8 kHz with 32-bits per sample + if (!I2S.begin(ADC_DAC_MODE, 8000, 16)) { + Serial.println("Failed to initialize I2S!"); + while (1); // do nothing + } +} + +void loop() { + // read a sample + int sample = I2S.read(); + Serial.println(sample); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/FullDuplex.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/FullDuplex.ino new file mode 100644 index 0000000..9b3625f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/FullDuplex/FullDuplex.ino @@ -0,0 +1,59 @@ +/* + This example is only for ESP + This example demonstrates simultaneous usage of microphone and speaker using single I2S module. + The application transfers data from input to output + + Circuit: + * ESP32 + * GND connected GND + * VIN connected 5V + * SCK 5 + * FS 25 + * DIN 35 + * DOUT 26 + * I2S microphone + * I2S decoder + headphones / speaker + + created 8 October 2021 + by Tomas Pilny + */ + +#include +const long sampleRate = 16000; +const int bitsPerSample = 32; +uint8_t *buffer; + +void setup() { + Serial.begin(115200); + //I2S.setAllPins(5, 25, 35, 26); // you can change default pins; order of pins = (CLK, WS, IN, OUT) + if(!I2S.setDuplex()){ + Serial.println("ERROR - could not set duplex"); + while(true){ + vTaskDelay(10); // Cannot continue + } + } + if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, bitsPerSample)) { + Serial.println("Failed to initialize I2S!"); + while(true){ + vTaskDelay(10); // Cannot continue + } + } + buffer = (uint8_t*) malloc(I2S.getBufferSize() * (bitsPerSample / 8)); + if(buffer == NULL){ + Serial.println("Failed to allocate buffer!"); + while(true){ + vTaskDelay(10); // Cannot continue + } + } + Serial.println("Setup done"); +} + +void loop() { + //I2S.write(I2S.read()); // primitive implementation sample-by-sample + + // Buffer based implementation + I2S.read(buffer, I2S.getBufferSize() * (bitsPerSample / 8)); + I2S.write(buffer, I2S.getBufferSize() * (bitsPerSample / 8)); + + //optimistic_yield(1000); // yield if last yield occurred before CPU clock cycles ago +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/InputSerialPlotter.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/InputSerialPlotter.ino new file mode 100644 index 0000000..db9f7d0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/InputSerialPlotter/InputSerialPlotter.ino @@ -0,0 +1,44 @@ +/* + This example reads audio data from an Invensense's ICS43432 I2S microphone + breakout board, and prints out the samples to the Serial console. The + Serial Plotter built into the Arduino IDE can be used to plot the audio + data (Tools -> Serial Plotter) + + Circuit: + * Arduino/Genuino Zero, MKR family and Nano 33 IoT + * ICS43432: + * GND connected GND + * 3.3V connected to 3.3V (Zero, Nano, ESP32), VCC (MKR) + * WS connected to pin 0 (Zero) or 3 (MKR), A2 (Nano) or 25 (ESP32) + * CLK connected to pin 1 (Zero) or 2 (MKR), A3 (Nano) or 5 (ESP32) + * SD connected to pin 9 (Zero) or A6 (MKR), 4 (Nano) or 26 (ESP32) + created 17 November 2016 + by Sandeep Mistry + */ + +#include + +void setup() { + // Open serial communications and wait for port to open: + // A baud rate of 115200 is used instead of 9600 for a faster data rate + // on non-native USB ports + Serial.begin(115200); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // start I2S at 8 kHz with 32-bits per sample + if (!I2S.begin(I2S_PHILIPS_MODE, 8000, 32)) { + Serial.println("Failed to initialize I2S!"); + while (1); // do nothing + } +} + +void loop() { + // read a sample + int sample = I2S.read(); + + if (sample && sample != -1 && sample != 1) { + Serial.println(sample); + } +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/SimpleTone.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/SimpleTone.ino new file mode 100644 index 0000000..49cae77 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/examples/SimpleTone/SimpleTone.ino @@ -0,0 +1,79 @@ +/* + This example generates a square wave based tone at a specified frequency + and sample rate. Then outputs the data using the I2S interface to a + MAX08357 I2S Amp Breakout board. + + I2S Circuit: + * Arduino/Genuino Zero, MKR family and Nano 33 IoT + * MAX08357: + * GND connected GND + * VIN connected 5V + * LRC connected to pin 0 (Zero) or 3 (MKR), A2 (Nano) or 25 (ESP32) + * BCLK connected to pin 1 (Zero) or 2 (MKR), A3 (Nano) or 5 (ESP32) + * DIN connected to pin 9 (Zero) or A6 (MKR), 4 (Nano) or 26 (ESP32) + + DAC Circuit: + * ESP32 or ESP32-S2 + * Audio amplifier + - Note: + - ESP32 has DAC on GPIO pins 25 and 26. + - ESP32-S2 has DAC on GPIO pins 17 and 18. + - Connect speaker(s) or headphones. + + created 17 November 2016 + by Sandeep Mistry + For ESP extended + Tomas Pilny + 2nd September 2021 + */ + +#include +const int frequency = 440; // frequency of square wave in Hz +const int amplitude = 500; // amplitude of square wave +const int sampleRate = 8000; // sample rate in Hz +const int bps = 16; + +const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave + +int32_t sample = amplitude; // current sample value +int count = 0; + +i2s_mode_t mode = I2S_PHILIPS_MODE; // I2S decoder is needed +// i2s_mode_t mode = ADC_DAC_MODE; // Audio amplifier is needed + +// Mono channel input +// This is ESP specific implementation - +// samples will be automatically copied to both channels inside I2S driver +// If you want to have true mono output use I2S_PHILIPS_MODE and interlay +// second channel with 0-value samples. +// The order of channels is RIGH followed by LEFT +//i2s_mode_t mode = I2S_RIGHT_JUSTIFIED_MODE; // I2S decoder is needed + +void setup() { + Serial.begin(115200); + Serial.println("I2S simple tone"); + + // start I2S at the sample rate with 16-bits per sample + if (!I2S.begin(mode, sampleRate, bps)) { + Serial.println("Failed to initialize I2S!"); + while (1); // do nothing + } +} + +void loop() { + if (count % halfWavelength == 0 ) { + // invert the sample every half wavelength count multiple to generate square wave + sample = -1 * sample; + } + + if(mode == I2S_PHILIPS_MODE || mode == ADC_DAC_MODE){ // write the same sample twice, once for Right and once for Left channel + I2S.write(sample); // Right channel + I2S.write(sample); // Left channel + }else if(mode == I2S_RIGHT_JUSTIFIED_MODE || mode == I2S_LEFT_JUSTIFIED_MODE){ + // write the same only once - it will be automatically copied to the other channel + I2S.write(sample); + } + + // increment the counter for the next sample + count++; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/keywords.txt new file mode 100644 index 0000000..ad1b802 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/keywords.txt @@ -0,0 +1,61 @@ +####################################### +# Syntax Coloring Map I2S +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +I2S KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +I2SClass KEYWORD2 +begin KEYWORD2 +end KEYWORD2 + +onReceive KEYWORD2 +onTransmit KEYWORD2 + +setSckPin KEYWORD2 +setFsPin KEYWORD2 +setDataInPin KEYWORD2 +setDataOutPin KEYWORD2 +setAllPins KEYWORD2 + +getSckPin KEYWORD2 +getFsPin KEYWORD2 +getDataPin KEYWORD2 +getDataInPin KEYWORD2 +getDataOutPin KEYWORD2 + +setDuplex KEYWORD2 +setSimplex KEYWORD2 +isDuplex KEYWORD2 + +setBufferSize KEYWORD2 +getBufferSize KEYWORD2 + +write KEYWORD2 +availableForWrite KEYWORD2 + +read KEYWORD2 +available KEYWORD2 + +gpioToAdcUnit KEYWORD2 +gpioToAdcChannel KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +I2S_PHILIPS_MODE LITERAL1 +I2S_RIGHT_JUSTIFIED_MODE LITERAL1 +I2S_LEFT_JUSTIFIED_MODE LITERAL1 +I2S_ADC_DAC LITERAL1 +I2S_PDM LITERAL1 + +PIN_I2S_SCK LITERAL1 +PIN_I2S_FS LITERAL1 +PIN_I2S_SD LITERAL1 +PIN_I2S_SD_OUT LITERAL1 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/library.properties new file mode 100644 index 0000000..bb77e30 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/library.properties @@ -0,0 +1,9 @@ +name=I2S +version=1.0 +author=Tomas Pilny +maintainer=Tomas Pilny +sentence=Enables the communication with devices that use the Inter-IC Sound (I2S) Bus. Specific implementation for ESP. +paragraph= +category=Communication +url=http://www.arduino.cc/en/Reference/I2S +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/src/I2S.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/src/I2S.cpp new file mode 100644 index 0000000..7414067 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/src/I2S.cpp @@ -0,0 +1,1222 @@ +/* + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "I2S.h" +#include "freertos/semphr.h" + +#define _I2S_EVENT_QUEUE_LENGTH 16 +#define _I2S_DMA_BUFFER_COUNT 2 // BUFFER COUNT must be between 2 and 128 +#define I2S_INTERFACES_COUNT SOC_I2S_NUM + +#ifndef I2S_DEVICE + #define I2S_DEVICE 0 +#endif + +#ifndef I2S_CLOCK_GENERATOR + #define I2S_CLOCK_GENERATOR 0 // does nothing for ESP +#endif + +I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin) : + _deviceIndex(deviceIndex), + _sdPin(sdPin), // shared data pin + _inSdPin(PIN_I2S_SD_IN), // input data pin + _outSdPin(PIN_I2S_SD), // output data pin + _sckPin(sckPin), // clock pin + _fsPin(fsPin), // frame (word) select pin + + _state(I2S_STATE_IDLE), + _bitsPerSample(0), + _sampleRate(0), + _mode(I2S_PHILIPS_MODE), + + _buffer_byte_size(0), + + _driverInstalled(false), + _initialized(false), + _callbackTaskHandle(NULL), + _i2sEventQueue(NULL), + _i2s_general_mutex(NULL), + _input_ring_buffer(NULL), + _output_ring_buffer(NULL), + _i2s_dma_buffer_size(128), // Number of frames in each DMA buffer. Frame size = number of channels * Bytes per sample; Must be between 8 and 1024 + _driveClock(true), + _peek_buff(0), + _peek_buff_valid(false), + _nesting_counter(0), + + _onTransmit(NULL), + _onReceive(NULL) +{ + _i2s_general_mutex = xSemaphoreCreateMutex(); + if(_i2s_general_mutex == NULL){ + log_e("I2S could not create internal mutex!"); + } +} + +int I2SClass::_createCallbackTask(){ + int stack_size = 20000; + if(_callbackTaskHandle != NULL){ + log_e("Callback task already exists!"); + return 0; // ERR + } + + xTaskCreate( + onDmaTransferComplete, // Function to implement the task + "onDmaTransferComplete", // Name of the task + stack_size, // Stack size in words + NULL, // Task input parameter + 2, // Priority of the task + &_callbackTaskHandle // Task handle. + ); + if(_callbackTaskHandle == NULL){ + log_e("Could not create callback task"); + return 0; // ERR + } + return 1; // OK +} + +int I2SClass::_installDriver(){ + if(_driverInstalled){ + log_e("I2S driver is already installed"); + return 0; // ERR + } + + esp_i2s::i2s_mode_t i2s_mode = (esp_i2s::i2s_mode_t)(esp_i2s::I2S_MODE_RX | esp_i2s::I2S_MODE_TX); + + if(_driveClock){ + i2s_mode = (esp_i2s::i2s_mode_t)(i2s_mode | esp_i2s::I2S_MODE_MASTER); + }else{ + i2s_mode = (esp_i2s::i2s_mode_t)(i2s_mode | esp_i2s::I2S_MODE_SLAVE); + } + + if(_mode == ADC_DAC_MODE){ + #if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) + if(_bitsPerSample != 16){ // ADC/DAC can only work in 16-bit sample mode + log_e("ERROR invalid bps for ADC/DAC. Allowed only 16, requested %d", _bitsPerSample); + return 0; // ERR + } + i2s_mode = (esp_i2s::i2s_mode_t)(i2s_mode | esp_i2s::I2S_MODE_DAC_BUILT_IN | esp_i2s::I2S_MODE_ADC_BUILT_IN); + #else + log_e("This chip does not support ADC / DAC mode"); + return 0; // ERR + #endif + }else if(_mode == I2S_PHILIPS_MODE || + _mode == I2S_RIGHT_JUSTIFIED_MODE || + _mode == I2S_LEFT_JUSTIFIED_MODE){ // End of ADC/DAC mode; start of Normal Philips mode + if(_bitsPerSample != 8 && _bitsPerSample != 16 && _bitsPerSample != 24 && _bitsPerSample != 32){ + log_e("Invalid bits per sample for normal mode (requested %d)\nAllowed bps = 8 | 16 | 24 | 32", _bitsPerSample); + return 0; // ERR + } + if(_bitsPerSample == 24){ + log_w("Original Arduino library does not support 24 bits per sample.\nKeep that in mind if you should switch back to Arduino"); + } + }else if(_mode == PDM_STEREO_MODE || _mode == PDM_MONO_MODE){ // end of Normal Philips mode; start of PDM mode + #if (SOC_I2S_SUPPORTS_PDM_TX && SOC_I2S_SUPPORTS_PDM_RX) + i2s_mode = (esp_i2s::i2s_mode_t)(i2s_mode | esp_i2s::I2S_MODE_PDM); + #else + log_e("This chip does not support PDM"); + return 0; // ERR + #endif + } // Mode + esp_i2s::i2s_config_t i2s_config = { + .mode = i2s_mode, + .sample_rate = _sampleRate, + .bits_per_sample = (esp_i2s::i2s_bits_per_sample_t)_bitsPerSample, + .channel_format = esp_i2s::I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = (esp_i2s::i2s_comm_format_t)(esp_i2s::I2S_COMM_FORMAT_STAND_I2S), + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL2, + .dma_buf_count = _I2S_DMA_BUFFER_COUNT, + .dma_buf_len = _i2s_dma_buffer_size, + .use_apll = false, + #warning The following values are new and need to be checked + .tx_desc_auto_clear = true, + .fixed_mclk = 0, + .mclk_multiple = esp_i2s::I2S_MCLK_MULTIPLE_128, + .bits_per_chan = esp_i2s::I2S_BITS_PER_CHAN_DEFAULT +#if SOC_I2S_SUPPORTS_TDM + ,.chan_mask = esp_i2s::I2S_CHANNEL_STEREO, + .total_chan = 2, + .left_align = false, + .big_edin = false, + .bit_order_msb = false, + .skip_msk = false +#endif // SOC_I2S_SUPPORTS_TDM + }; + + if(_driveClock == false){ + i2s_config.use_apll = true; + i2s_config.fixed_mclk = 512*_sampleRate; + } + + // Install and start i2s driver + while(ESP_OK != esp_i2s::i2s_driver_install((esp_i2s::i2s_port_t) _deviceIndex, &i2s_config, _I2S_EVENT_QUEUE_LENGTH, &_i2sEventQueue)){ + // increase buffer size + if(2*_i2s_dma_buffer_size <= 1024){ + log_w("WARNING i2s driver install failed.\nTrying to increase I2S DMA buffer size from %d to %d\n", _i2s_dma_buffer_size, 2*_i2s_dma_buffer_size); + setBufferSize(2*_i2s_dma_buffer_size); + }else if(_i2s_dma_buffer_size < 1024){ + log_w("WARNING i2s driver install failed.\nTrying to decrease I2S DMA buffer size from %d to 1024\n", _i2s_dma_buffer_size); + setBufferSize(1024); + }else{ // install failed with max buffer size + log_e("ERROR i2s driver install failed"); + return 0; // ERR + } + } //try installing with increasing size + + if(_mode == I2S_RIGHT_JUSTIFIED_MODE || _mode == I2S_LEFT_JUSTIFIED_MODE || _mode == PDM_MONO_MODE){ // mono/single channel + // Set the clock for MONO. Stereo is not supported yet. + if(ESP_OK != esp_i2s::i2s_set_clk((esp_i2s::i2s_port_t) _deviceIndex, _sampleRate, (esp_i2s::i2s_bits_per_sample_t)_bitsPerSample, esp_i2s::I2S_CHANNEL_MONO)){ + log_e("Setting the I2S Clock has failed!\n"); + return 0; // ERR + } + } // mono channel mode + +#if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) + if(_mode == ADC_DAC_MODE){ + esp_i2s::i2s_set_dac_mode(esp_i2s::I2S_DAC_CHANNEL_BOTH_EN); + esp_i2s::adc_unit_t adc_unit; + if(!_gpioToAdcUnit((gpio_num_t)_inSdPin, &adc_unit)){ + log_e("pin to adc unit conversion failed"); + return 0; // ERR + } + esp_i2s::adc_channel_t adc_channel; + if(!_gpioToAdcChannel((gpio_num_t)_inSdPin, &adc_channel)){ + log_e("pin to adc channel conversion failed"); + return 0; // ERR + } + if(ESP_OK != esp_i2s::i2s_set_adc_mode(adc_unit, (esp_i2s::adc1_channel_t)adc_channel)){ + log_e("i2s_set_adc_mode failed"); + return 0; // ERR + } + if(ESP_OK != esp_i2s::i2s_set_pin((esp_i2s::i2s_port_t) _deviceIndex, NULL)){ + log_e("i2s_set_pin failed"); + return 0; // ERR + } + + if(adc_unit == esp_i2s::ADC_UNIT_1){ + esp_i2s::adc1_config_width(esp_i2s::ADC_WIDTH_BIT_12); + esp_i2s::adc1_config_channel_atten((esp_i2s::adc1_channel_t)adc_channel, esp_i2s::ADC_ATTEN_DB_11); + }else if(adc_unit == esp_i2s::ADC_UNIT_2){ + esp_i2s::adc2_config_channel_atten((esp_i2s::adc2_channel_t)adc_channel, esp_i2s::ADC_ATTEN_DB_11); + } + + esp_i2s::i2s_adc_enable((esp_i2s::i2s_port_t) _deviceIndex); + _driverInstalled = true; + }else // End of ADC/DAC mode +#endif // SOC_I2S_SUPPORTS_ADC_DAC + if(_mode == I2S_PHILIPS_MODE || _mode == I2S_RIGHT_JUSTIFIED_MODE || _mode == I2S_LEFT_JUSTIFIED_MODE || _mode == PDM_STEREO_MODE || _mode == PDM_MONO_MODE){ // if I2S mode + _driverInstalled = true; // IDF I2S driver must be installed before calling _applyPinSetting + if(!_applyPinSetting()){ + log_e("could not apply pin setting during driver install"); + _uninstallDriver(); + return 0; // ERR + } + } // if I2S _mode + return 1; // OK +} + +// Init in MASTER mode: the SCK and FS pins are driven as outputs using the sample rate +int I2SClass::begin(int mode, int sampleRate, int bitsPerSample){ + _take_if_not_holding(); + // master mode (driving clock and frame select pins - output) + int ret = begin(mode, sampleRate, bitsPerSample, true); + _give_if_top_call(); + return ret; +} + +// Init in SLAVE mode: the SCK and FS pins are inputs, other side controls sample rate +int I2SClass::begin(int mode, int bitsPerSample){ + _take_if_not_holding(); + // slave mode (not driving clock and frame select pin - input) + int ret = begin(mode, 96000, bitsPerSample, false); + _give_if_top_call(); + return ret; +} + + +// Core function +int I2SClass::begin(int mode, int sampleRate, int bitsPerSample, bool driveClock){ + _take_if_not_holding(); + if(_initialized){ + log_e("ERROR: Object already initialized! Call I2S.end() to disable"); + _give_if_top_call(); + return 0; // ERR + } + _driveClock = driveClock; + _mode = mode; + _sampleRate = (uint32_t)sampleRate; + _bitsPerSample = bitsPerSample; + + // There is work in progress on this library. + if(_bitsPerSample == 16 && _sampleRate > 16000 && driveClock){ + log_w("This sample rate is not officially supported - audio might be noisy.\nTry using sample rate below or equal to 16000"); + } + if(_bitsPerSample != 16){ + log_w("This bit-per-sample is not officially supported - audio quality might suffer.\nTry using 16bps, with sample rate below or equal 16000"); + } + if(_mode != I2S_PHILIPS_MODE){ + log_w("This mode is not officially supported - audio quality might suffer.\nAt the moment the only supported mode is I2S_PHILIPS_MODE"); + } + + if (_state != I2S_STATE_IDLE && _state != I2S_STATE_DUPLEX) { + log_e("Error: unexpected _state (%d)", _state); + _give_if_top_call(); + return 0; // ERR + } + + switch (mode) { + case I2S_PHILIPS_MODE: + case I2S_RIGHT_JUSTIFIED_MODE: + case I2S_LEFT_JUSTIFIED_MODE: + + #if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) + case ADC_DAC_MODE: + #endif + + case PDM_STEREO_MODE: + case PDM_MONO_MODE: + break; + + default: // invalid mode + log_e("ERROR: unknown mode"); + _give_if_top_call(); + return 0; // ERR + } + + if(!_installDriver()){ + log_e("ERROR: failed to install driver"); + end(); + _give_if_top_call(); + return 0; // ERR + } + + _buffer_byte_size = _i2s_dma_buffer_size * (_bitsPerSample / 8) * _I2S_DMA_BUFFER_COUNT * 2; + _input_ring_buffer = xRingbufferCreate(_buffer_byte_size, RINGBUF_TYPE_BYTEBUF); + _output_ring_buffer = xRingbufferCreate(_buffer_byte_size, RINGBUF_TYPE_BYTEBUF); + if(_input_ring_buffer == NULL || _output_ring_buffer == NULL){ + log_e("ERROR: could not create one or both internal buffers. Requested size = %d\n", _buffer_byte_size); + _give_if_top_call(); + return 0; // ERR + } + + if(!_createCallbackTask()){ + log_e("ERROR: failed to create callback task"); + end(); + _give_if_top_call(); + return 0; // ERR + } + _initialized = true; + _give_if_top_call(); + return 1; // OK +} + +int I2SClass::_applyPinSetting(){ + if(_driverInstalled){ + esp_i2s::i2s_pin_config_t pin_config = { + .mck_io_num = I2S_PIN_NO_CHANGE, + .bck_io_num = _sckPin, + .ws_io_num = _fsPin, + .data_out_num = I2S_PIN_NO_CHANGE, + .data_in_num = I2S_PIN_NO_CHANGE + }; + if (_state == I2S_STATE_DUPLEX){ // duplex + pin_config.data_out_num = _outSdPin; + pin_config.data_in_num = _inSdPin; + }else{ // simplex + if(_state == I2S_STATE_RECEIVER){ + pin_config.data_out_num = I2S_PIN_NO_CHANGE; + pin_config.data_in_num = _sdPin; + }else if(_state == I2S_STATE_TRANSMITTER){ + pin_config.data_out_num = _sdPin; + pin_config.data_in_num = I2S_PIN_NO_CHANGE; + }else{ + pin_config.data_out_num = I2S_PIN_NO_CHANGE; + pin_config.data_in_num = _sdPin; + } + } + if(ESP_OK != esp_i2s::i2s_set_pin((esp_i2s::i2s_port_t) _deviceIndex, &pin_config)){ + log_e("i2s_set_pin failed; attempted settings: SCK=%d; FS=%d; DIN=%d; DOUT=%d", pin_config.bck_io_num, pin_config.ws_io_num, pin_config.data_in_num, pin_config.data_out_num); + return 0; // ERR + }else{ + return 1; // OK + } + } // if(_driverInstalled) + return 1; // OK +} + +void I2SClass::_setSckPin(int sckPin){ + _take_if_not_holding(); + if(sckPin >= 0){ + _sckPin = sckPin; + }else{ + _sckPin = PIN_I2S_SCK; + } + _give_if_top_call(); +} + +int I2SClass::setSckPin(int sckPin){ + _take_if_not_holding(); + _setSckPin(sckPin); + int ret = _applyPinSetting(); + _applyPinSetting(); + _give_if_top_call(); + return ret; +} + +void I2SClass::_setFsPin(int fsPin){ + if(fsPin >= 0){ + _fsPin = fsPin; + }else{ + _fsPin = PIN_I2S_FS; + } +} + +int I2SClass::setFsPin(int fsPin){ + _take_if_not_holding(); + _setFsPin(fsPin); + int ret = _applyPinSetting(); + _give_if_top_call(); + return ret; +} + +// shared data pin for simplex +void I2SClass::_setDataPin(int sdPin){ + if(sdPin >= 0){ + _sdPin = sdPin; + }else{ + _sdPin = PIN_I2S_SD; + } +} + +// shared data pin for simplex +int I2SClass::setDataPin(int sdPin){ + _take_if_not_holding(); + _setDataPin(sdPin); + int ret = _applyPinSetting(); + _give_if_top_call(); + return ret; +} + +void I2SClass::_setDataInPin(int inSdPin){ + if(inSdPin >= 0){ + _inSdPin = inSdPin; + }else{ + _inSdPin = PIN_I2S_SD_IN; + } +} + +int I2SClass::setDataInPin(int inSdPin){ + _take_if_not_holding(); + _setDataInPin(inSdPin); + int ret = _applyPinSetting(); + _give_if_top_call(); + return ret; +} + +void I2SClass::_setDataOutPin(int outSdPin){ + if(outSdPin >= 0){ + _outSdPin = outSdPin; + }else{ + _outSdPin = PIN_I2S_SD; + } +} + +int I2SClass::setDataOutPin(int outSdPin){ + _take_if_not_holding(); + _setDataOutPin(outSdPin); + int ret = _applyPinSetting(); + _give_if_top_call(); + return ret; +} + +int I2SClass::setAllPins(){ + _take_if_not_holding(); + int ret = setAllPins(PIN_I2S_SCK, PIN_I2S_FS, PIN_I2S_SD, PIN_I2S_SD_OUT, PIN_I2S_SD_IN); + _give_if_top_call(); + return ret; +} + +int I2SClass::setAllPins(int sckPin, int fsPin, int sdPin, int outSdPin, int inSdPin){ + _take_if_not_holding(); + _setSckPin(sckPin); + _setFsPin(fsPin); + _setDataPin(sdPin); + _setDataOutPin(outSdPin); + _setDataInPin(inSdPin); + int ret = _applyPinSetting(); + _give_if_top_call(); + return ret; +} + +int I2SClass::setDuplex(){ + _take_if_not_holding(); + _state = I2S_STATE_DUPLEX; + _give_if_top_call(); + return 1; +} + +int I2SClass::setSimplex(){ + _take_if_not_holding(); + _state = I2S_STATE_IDLE; + _give_if_top_call(); + return 1; +} + +int I2SClass::isDuplex(){ + _take_if_not_holding(); + int ret = (int)(_state == I2S_STATE_DUPLEX); + _give_if_top_call(); + return ret; +} + +int I2SClass::getSckPin(){ + _take_if_not_holding(); + int ret = _sckPin; + _give_if_top_call(); + return ret; +} + +int I2SClass::getFsPin(){ + _take_if_not_holding(); + int ret = _fsPin; + _give_if_top_call(); + return ret; +} + +int I2SClass::getDataPin(){ + _take_if_not_holding(); + int ret = _sdPin; + _give_if_top_call(); + return ret; +} + +int I2SClass::getDataInPin(){ + _take_if_not_holding(); + int ret = _inSdPin; + _give_if_top_call(); + return ret; +} + +int I2SClass::getDataOutPin(){ + _take_if_not_holding(); + int ret = _outSdPin; + _give_if_top_call(); + return ret; +} + +void I2SClass::_uninstallDriver(){ + if(_driverInstalled){ + #if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) + if(_mode == ADC_DAC_MODE){ + esp_i2s::i2s_adc_disable((esp_i2s::i2s_port_t) _deviceIndex); + } + #endif + esp_i2s::i2s_driver_uninstall((esp_i2s::i2s_port_t) _deviceIndex); + + if(_state != I2S_STATE_DUPLEX){ + _state = I2S_STATE_IDLE; + } + _driverInstalled = false; + } // if(_driverInstalled) +} + +void I2SClass::end(){ + _take_if_not_holding(); + if(xTaskGetCurrentTaskHandle() != _callbackTaskHandle){ + if(_callbackTaskHandle){ + vTaskDelete(_callbackTaskHandle); + _callbackTaskHandle = NULL; // prevent secondary termination to non-existing task + } + _uninstallDriver(); + _onTransmit = NULL; + _onReceive = NULL; + if(_input_ring_buffer != NULL){ + vRingbufferDelete(_input_ring_buffer); + _input_ring_buffer = NULL; + } + if(_output_ring_buffer != NULL){ + vRingbufferDelete(_output_ring_buffer); + _output_ring_buffer = NULL; + } + _initialized = false; + }else{ + log_w("WARNING: ending I2SClass from callback task not permitted, but attempted!"); + } + _give_if_top_call(); +} + +// Bytes available to read +int I2SClass::available(){ + _take_if_not_holding(); + int ret = 0; + if(_input_ring_buffer != NULL){ + ret = _buffer_byte_size - (int)xRingbufferGetCurFreeSize(_input_ring_buffer); + } + _give_if_top_call(); + return ret; +} + +union i2s_sample_t { + uint8_t b8; + int16_t b16; + int32_t b32; +}; + +int I2SClass::read(){ + _take_if_not_holding(); + i2s_sample_t sample; + sample.b32 = 0; + if(_initialized){ + read(&sample, _bitsPerSample / 8); + + if (_bitsPerSample == 32) { + _give_if_top_call(); + return sample.b32; + } else if (_bitsPerSample == 16) { + _give_if_top_call(); + return sample.b16; + } else if (_bitsPerSample == 8) { + _give_if_top_call(); + return sample.b8; + } else { + _give_if_top_call(); + return 0; // sample value + } + } // if(_initialized) + _give_if_top_call(); + return 0; // sample value +} + +int I2SClass::read(void* buffer, size_t size){ + _take_if_not_holding(); + size_t requested_size = size; + if(_initialized){ + if(!_enableReceiver()){ + _give_if_top_call(); + return 0; // There was an error switching to receiver + } // _enableReceiver succeeded ? + + size_t item_size = 0; + void *tmp_buffer; + if(_input_ring_buffer != NULL){ + if(_peek_buff_valid){ + memcpy(buffer, &_peek_buff, _bitsPerSample/8); + _peek_buff_valid = false; + requested_size -= _bitsPerSample/8; + } + tmp_buffer = xRingbufferReceiveUpTo(_input_ring_buffer, &item_size, pdMS_TO_TICKS(1000), requested_size); + if(tmp_buffer != NULL){ + memcpy(buffer, tmp_buffer, item_size); + #if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) + if(_mode == ADC_DAC_MODE){ + for(size_t i = 0; i < item_size / 2; ++i){ + ((uint16_t*)buffer)[i] = ((uint16_t*)buffer)[i] & 0x0FFF; + } + } // ADC/DAC mode + #endif + vRingbufferReturnItem(_input_ring_buffer, tmp_buffer); + _give_if_top_call(); + return item_size; + }else{ + log_w("input buffer is empty - timed out"); + _give_if_top_call(); + return 0; // 0 Bytes read / ERR + } // tmp buffer not NULL ? + } // ring buffer not NULL ? + } // if(_initialized) + _give_if_top_call(); + return 0; // 0 Bytes read / ERR +} + +size_t I2SClass::write(uint8_t data){ + _take_if_not_holding(); + size_t ret = 0; + if(_initialized){ + ret = write_blocking((int32_t*)&data, 1); + } + _give_if_top_call(); + return ret; +} + +size_t I2SClass::write(int32_t sample){ + _take_if_not_holding(); + size_t ret = 0; + if(_initialized){ + ret = write_blocking(&sample, _bitsPerSample/8); + } + _give_if_top_call(); + return ret; +} + +size_t I2SClass::write(const uint8_t *buffer, size_t size){ + _take_if_not_holding(); + size_t ret = 0; + if(_initialized){ + ret = write((const void*)buffer, size); + } + _give_if_top_call(); + return ret; +} + +size_t I2SClass::write(const void *buffer, size_t size){ + _take_if_not_holding(); + size_t ret = 0; + if(_initialized){ + //size_t ret = write_blocking(buffer, size); + ret = write_nonblocking(buffer, size); + } // if(_initialized) + _give_if_top_call(); + return ret; +} + +// blocking version of write +// This version of write will wait indefinitely to write requested samples +// into output buffer +size_t I2SClass::write_blocking(const void *buffer, size_t size){ + _take_if_not_holding(); + if(_initialized){ + if(!_enableTransmitter()){ + _give_if_top_call(); + return 0; // There was an error switching to transmitter + } // _enableTransmitter succeeded ? + + if(_output_ring_buffer != NULL){ + int ret = xRingbufferSend(_output_ring_buffer, buffer, size, portMAX_DELAY); + if(pdTRUE == ret){ + _give_if_top_call(); + return size; + }else{ + log_e("xRingbufferSend() with infinite wait returned with error"); + _give_if_top_call(); + return 0; + } // ring buffer send ok ? + } // ring buffer not NULL ? + } // if(_initialized) + return 0; + log_w("I2S not initialized"); + _give_if_top_call(); + return 0; +} + +// non-blocking version of write +// In case there is not enough space in buffer to write requested size +// this function will try to flush the buffer and write requested data with 0 time-out +size_t I2SClass::write_nonblocking(const void *buffer, size_t size){ + _take_if_not_holding(); + if(_initialized){ + if(_state != I2S_STATE_TRANSMITTER && _state != I2S_STATE_DUPLEX){ + if(!_enableTransmitter()){ + _give_if_top_call(); + return 0; // There was an error switching to transmitter + } + } + if(availableForWrite() < size){ + flush(); + } + if(_output_ring_buffer != NULL){ + if(pdTRUE == xRingbufferSend(_output_ring_buffer, buffer, size, 0)){ + _give_if_top_call(); + return size; + }else{ + log_w("I2S could not write all data into ring buffer!"); + _give_if_top_call(); + return 0; + } + } + } // if(_initialized) + return 0; + _give_if_top_call(); // this should not be needed +} + +/* + Read 1 sample from internal buffer and return it. + Repeated peeks will return the same sample until read is called. +*/ +int I2SClass::peek(){ + _take_if_not_holding(); + int ret = 0; + if(_initialized && _input_ring_buffer != NULL && !_peek_buff_valid){ + size_t item_size = 0; + void *item = NULL; + + item = xRingbufferReceiveUpTo(_input_ring_buffer, &item_size, 0, _bitsPerSample/8); // fetch 1 sample + if (item != NULL && item_size == _bitsPerSample/8){ + _peek_buff = *((int*)item); + vRingbufferReturnItem(_input_ring_buffer, item); + _peek_buff_valid = true; + } + + } // if(_initialized) + if(_peek_buff_valid){ + ret = _peek_buff; + } + _give_if_top_call(); + return ret; +} + +void I2SClass::flush(){ + _take_if_not_holding(); + if(_initialized){ + const size_t single_dma_buf = _i2s_dma_buffer_size*(_bitsPerSample/8)*2; + size_t item_size = 0; + void *item = NULL; + if(_output_ring_buffer != NULL){ + item = xRingbufferReceiveUpTo(_output_ring_buffer, &item_size, 0, single_dma_buf); + if (item != NULL){ + _fix_and_write(item, item_size); + vRingbufferReturnItem(_output_ring_buffer, item); + } + } + } // if(_initialized) + _give_if_top_call(); +} + +// Bytes available to write +int I2SClass::availableForWrite(){ + _take_if_not_holding(); + int ret = 0; + if(_initialized){ + if(_output_ring_buffer != NULL){ + ret = (int)xRingbufferGetCurFreeSize(_output_ring_buffer); + } + } // if(_initialized) + _give_if_top_call(); + return ret; +} + +void I2SClass::onTransmit(void(*function)(void)){ + _take_if_not_holding(); + _onTransmit = function; + _give_if_top_call(); +} + +void I2SClass::onReceive(void(*function)(void)){ + _take_if_not_holding(); + _onReceive = function; + _give_if_top_call(); +} + +int I2SClass::setBufferSize(int bufferSize){ + _take_if_not_holding(); + int ret = 0; + if(bufferSize >= 8 && bufferSize <= 1024){ + _i2s_dma_buffer_size = bufferSize; + }else{ + log_e("setBufferSize: wrong input! Buffer size must be between 8 and 1024. Requested %d", bufferSize); + _give_if_top_call(); + return 0; // ERR + } // check requested buffer size + + if(_initialized){ + _uninstallDriver(); + ret = _installDriver(); + _give_if_top_call(); + return ret; + }else{ // check requested buffer size + _give_if_top_call(); + return 1; // It's ok to change buffer size for uninitialized driver - new size will be used on begin() + } // if(_initialized) + _give_if_top_call(); + return 0; // ERR +} + +int I2SClass::getBufferSize(){ + _take_if_not_holding(); + int ret = _i2s_dma_buffer_size; + _give_if_top_call(); + return ret; +} + +int I2SClass::_enableTransmitter(){ + if(_state != I2S_STATE_DUPLEX && _state != I2S_STATE_TRANSMITTER){ + _state = I2S_STATE_TRANSMITTER; + return _applyPinSetting(); + } + return 1; // Ok +} + +int I2SClass::_enableReceiver(){ + if(_state != I2S_STATE_DUPLEX && _state != I2S_STATE_RECEIVER){ + _state = I2S_STATE_RECEIVER; + return _applyPinSetting(); + } + return 1; // Ok +} + +void I2SClass::_tx_done_routine(uint8_t* prev_item){ + static bool prev_item_valid = false; + const size_t single_dma_buf = _i2s_dma_buffer_size*(_bitsPerSample/8)*2; // *2 for stereo - it has double number of samples for 2 channels + static size_t item_size = 0; + static size_t prev_item_size = 0; + static void *item = NULL; + static int prev_item_offset = 0; + static size_t bytes_written = 0; + + if(prev_item_valid){ // use item from previous round + _fix_and_write(prev_item+prev_item_offset, prev_item_size, &bytes_written); + if(prev_item_size == bytes_written){ + prev_item_valid = false; + } // write size check + prev_item_offset = bytes_written; + prev_item_size -= bytes_written; + } // prev_item_valid + + if(_output_ring_buffer != NULL && (_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= single_dma_buf)){ // fill up the I2S DMA buffer + bytes_written = 0; + item_size = 0; + if(_buffer_byte_size - xRingbufferGetCurFreeSize(_output_ring_buffer) >= _i2s_dma_buffer_size*(_bitsPerSample/8)){ // don't read from almost empty buffer + item = xRingbufferReceiveUpTo(_output_ring_buffer, &item_size, pdMS_TO_TICKS(0), single_dma_buf); + if (item != NULL){ + _fix_and_write(item, item_size, &bytes_written); + if(item_size != bytes_written){ // save item that was not written correctly for later + memcpy(prev_item, (void*)&((uint8_t*)item)[bytes_written], item_size-bytes_written); + prev_item_size = item_size - bytes_written; + prev_item_offset = 0; + prev_item_valid = true; + } // save item that was not written correctly for later + vRingbufferReturnItem(_output_ring_buffer, item); + } // Check received item + } // don't read from almost empty buffer + } // fill up the I2S DMA buffer + if(_onTransmit){ + _onTransmit(); + } // user callback +} + +void I2SClass::_rx_done_routine(){ + size_t bytes_read = 0; + const size_t single_dma_buf = _i2s_dma_buffer_size*(_bitsPerSample/8); + + if(_input_ring_buffer != NULL){ + uint8_t *_inputBuffer = (uint8_t*)malloc(_i2s_dma_buffer_size*4); + size_t avail = xRingbufferGetCurFreeSize(_input_ring_buffer); + if(avail > 0){ + esp_err_t ret = esp_i2s::i2s_read((esp_i2s::i2s_port_t) _deviceIndex, _inputBuffer, avail <= single_dma_buf ? avail : single_dma_buf, (size_t*) &bytes_read, 0); + if(ret != ESP_OK){ + log_w("i2s_read returned with error %d", ret); + } + _post_read_data_fix(_inputBuffer, &bytes_read); + } + + if(bytes_read > 0){ // when read more than 0, then send to ring buffer + if(pdTRUE != xRingbufferSend(_input_ring_buffer, _inputBuffer, bytes_read, 0)){ + log_w("I2S failed to send item from DMA to internal buffer\n"); + } // xRingbufferSendComplete + } // if(bytes_read > 0) + free(_inputBuffer); + if (_onReceive && avail < _buffer_byte_size){ // when user callback is registered && and there is some data in ring buffer to read + _onReceive(); + } // user callback + } +} + +void I2SClass::_onTransferComplete(){ + uint8_t prev_item[_i2s_dma_buffer_size*4]; + esp_i2s::i2s_event_t i2s_event; + + while(true){ + xQueueReceive(_i2sEventQueue, &i2s_event, portMAX_DELAY); + if(i2s_event.type == esp_i2s::I2S_EVENT_TX_DONE){ + _tx_done_routine(prev_item); + }else if(i2s_event.type == esp_i2s::I2S_EVENT_RX_DONE){ + _rx_done_routine(); + } // RX Done + } // infinite loop +} + +void I2SClass::onDmaTransferComplete(void*){ + I2S._onTransferComplete(); +} + +void I2SClass::_take_if_not_holding(){ + TaskHandle_t mutex_holder = xSemaphoreGetMutexHolder(_i2s_general_mutex); + if(mutex_holder != NULL && mutex_holder == xTaskGetCurrentTaskHandle()){ + ++_nesting_counter; + return; // we are already holding this mutex - no need to take it + } + + // we are not holding the mutex - wait for it and take it + if(xSemaphoreTake(_i2s_general_mutex, portMAX_DELAY) != pdTRUE ){ + log_e("I2S internal mutex take returned with error"); + } + //_give_if_top_call(); // call after this function +} + +void I2SClass::_give_if_top_call(){ + if(_nesting_counter){ + --_nesting_counter; + }else{ + if(xSemaphoreGive(_i2s_general_mutex) != pdTRUE){ + log_e("I2S internal mutex give error"); + } + } +} + + +// Fixes data in-situ received from esp i2s driver. After fixing they reflect what was on the bus. +// input - bytes as received from i2s_read - this serves as input and output buffer +// size - number of bytes (this may be changed during operation) +void I2SClass::_post_read_data_fix(void *input, size_t *size){ + ulong dst_ptr = 0; + switch(_bitsPerSample){ + case 8: + for(int i = 0; i < *size; i+=4){ + ((uint8_t*)input)[dst_ptr++] = ((uint8_t*)input)[i+3]; + ((uint8_t*)input)[dst_ptr++] = ((uint8_t*)input)[i+1]; + } + *size /= 2; + break; + case 16: + uint16_t tmp; + for(int i = 0; i < *size/2; i+=2){ + tmp = ((uint16_t*)input)[i]; + ((uint16_t*)input)[dst_ptr++] = ((uint16_t*)input)[i+1]; + ((uint16_t*)input)[dst_ptr++] = tmp; + } + break; + default: ; // Do nothing + } // switch +} + +// Prepares data and writes them to IDF i2s driver. +// This counters possible bug in ESP IDF I2S driver +// output - bytes to be sent +// size - number of bytes in original buffer +// bytes_written - number of bytes used from original buffer +// actual_bytes_written - number of bytes written by i2s_write after fix +void I2SClass::_fix_and_write(void *output, size_t size, size_t *bytes_written, size_t *actual_bytes_written){ + ulong src_ptr = 0; + uint8_t* buff = NULL; + size_t buff_size = size; + switch(_bitsPerSample){ + case 8: + buff_size = size *2; + buff = (uint8_t*)calloc(buff_size, sizeof(uint8_t)); + if(buff == NULL){ + log_e("callock error"); + if(bytes_written != NULL){ *bytes_written = 0; } + return; + } + for(int i = 0; i < buff_size ; i+=4){ + ((uint8_t*)buff)[i+3] = (uint16_t)((uint8_t*)output)[src_ptr++]; + ((uint8_t*)buff)[i+1] = (uint16_t)((uint8_t*)output)[src_ptr++]; + } + break; + case 16: + buff = (uint8_t*)malloc(buff_size); + if(buff == NULL){ + log_e("malloc error"); + if(bytes_written != NULL){ *bytes_written = 0; } + return; + } + for(int i = 0; i < size/2; i += 2 ){ + ((uint16_t*)buff)[i] = ((uint16_t*)output)[i+1]; // [1] <- [0] + ((uint16_t*)buff)[i+1] = ((uint16_t*)output)[i]; // [0] <- [1] + } + break; + case 24: + buff = (uint8_t*)output; + break; + case 32: + buff = (uint8_t*)output; + break; + default: ; // Do nothing + } // switch + + size_t _bytes_written; + esp_err_t ret = esp_i2s::i2s_write((esp_i2s::i2s_port_t) _deviceIndex, buff, buff_size, &_bytes_written, 0); // fixed + if(ret != ESP_OK){ + log_e("Error: writing data to i2s - function returned with err code %d", ret); + } + if(ret == ESP_OK && buff_size != _bytes_written){ + log_w("Warning: writing data to i2s - written %d B instead of requested %d B", _bytes_written, buff_size); + } + // free if the buffer was actually allocated + if(_bitsPerSample == 8 || _bitsPerSample == 16){ + free(buff); + } + if(bytes_written != NULL){ + *bytes_written = _bitsPerSample == 8 ? _bytes_written/2 : _bytes_written; + } + if(actual_bytes_written != NULL){ + *actual_bytes_written = _bytes_written; + } +} + + +#if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) +int I2SClass::_gpioToAdcUnit(gpio_num_t gpio_num, esp_i2s::adc_unit_t* adc_unit){ + switch(gpio_num){ +#if CONFIG_IDF_TARGET_ESP32 + // ADC 1 + case GPIO_NUM_36: + case GPIO_NUM_37: + case GPIO_NUM_38: + case GPIO_NUM_39: + case GPIO_NUM_32: + case GPIO_NUM_33: + case GPIO_NUM_34: + case GPIO_NUM_35: + *adc_unit = esp_i2s::ADC_UNIT_1; + return 1; // OK + + // ADC 2 + case GPIO_NUM_0: + log_w("GPIO 0 for ADC should not be used for dev boards due to external auto program circuits."); + case GPIO_NUM_4: + case GPIO_NUM_2: + case GPIO_NUM_15: + case GPIO_NUM_13: + case GPIO_NUM_12: + case GPIO_NUM_14: + case GPIO_NUM_27: + case GPIO_NUM_25: + case GPIO_NUM_26: + *adc_unit = esp_i2s::ADC_UNIT_2; + return 1; // OK +#endif + +#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) + case GPIO_NUM_1: + case GPIO_NUM_2: + case GPIO_NUM_3: + case GPIO_NUM_4: + case GPIO_NUM_5: + case GPIO_NUM_6: + case GPIO_NUM_7: + case GPIO_NUM_8: + case GPIO_NUM_9: + case GPIO_NUM_10: + *adc_unit = esp_i2s::ADC_UNIT_1; + return 1; // OK +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 + case GPIO_NUM_11: + case GPIO_NUM_12: + case GPIO_NUM_13: + case GPIO_NUM_14: + case GPIO_NUM_15: + case GPIO_NUM_16: + case GPIO_NUM_17: + case GPIO_NUM_18: + case GPIO_NUM_19: + case GPIO_NUM_20: + *adc_unit = esp_i2s::ADC_UNIT_2; + return 1; // OK +#endif + +#if (CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2) + case GPIO_NUM_0: + case GPIO_NUM_1: + case GPIO_NUM_2: + case GPIO_NUM_3: + case GPIO_NUM_4: + *adc_unit = esp_i2s::ADC_UNIT_1; + return 1; // OK + case GPIO_NUM_5: + *adc_unit = esp_i2s::ADC_UNIT_2; + return 1; // OK +#endif + default: + log_e("GPIO %d not usable for ADC!", gpio_num); + log_i("Please refer to documentation https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html"); + return 0; // ERR + } +} + +int I2SClass::_gpioToAdcChannel(gpio_num_t gpio_num, esp_i2s::adc_channel_t* adc_channel){ + switch(gpio_num){ +#if CONFIG_IDF_TARGET_ESP32 + // ADC 1 + case GPIO_NUM_36: *adc_channel = esp_i2s::ADC_CHANNEL_0; return 1; // OK + case GPIO_NUM_37: *adc_channel = esp_i2s::ADC_CHANNEL_1; return 1; // OK + case GPIO_NUM_38: *adc_channel = esp_i2s::ADC_CHANNEL_2; return 1; // OK + case GPIO_NUM_39: *adc_channel = esp_i2s::ADC_CHANNEL_3; return 1; // OK + case GPIO_NUM_32: *adc_channel = esp_i2s::ADC_CHANNEL_4; return 1; // OK + case GPIO_NUM_33: *adc_channel = esp_i2s::ADC_CHANNEL_5; return 1; // OK + case GPIO_NUM_34: *adc_channel = esp_i2s::ADC_CHANNEL_6; return 1; // OK + case GPIO_NUM_35: *adc_channel = esp_i2s::ADC_CHANNEL_7; return 1; // OK + + // ADC 2 + case GPIO_NUM_0: + log_w("GPIO 0 for ADC should not be used for dev boards due to external auto program circuits."); + *adc_channel = esp_i2s::ADC_CHANNEL_1; return 1; // OK + case GPIO_NUM_4: *adc_channel = esp_i2s::ADC_CHANNEL_0; return 1; // OK + case GPIO_NUM_2: *adc_channel = esp_i2s::ADC_CHANNEL_2; return 1; // OK + case GPIO_NUM_15: *adc_channel = esp_i2s::ADC_CHANNEL_3; return 1; // OK + case GPIO_NUM_13: *adc_channel = esp_i2s::ADC_CHANNEL_4; return 1; // OK + case GPIO_NUM_12: *adc_channel = esp_i2s::ADC_CHANNEL_5; return 1; // OK + case GPIO_NUM_14: *adc_channel = esp_i2s::ADC_CHANNEL_6; return 1; // OK + case GPIO_NUM_27: *adc_channel = esp_i2s::ADC_CHANNEL_7; return 1; // OK + case GPIO_NUM_25: *adc_channel = esp_i2s::ADC_CHANNEL_8; return 1; // OK + case GPIO_NUM_26: *adc_channel = esp_i2s::ADC_CHANNEL_9; return 1; // OK +#endif + +#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) + case GPIO_NUM_1: *adc_channel = esp_i2s::ADC_CHANNEL_0; return 1; // OK + case GPIO_NUM_2: *adc_channel = esp_i2s::ADC_CHANNEL_1; return 1; // OK + case GPIO_NUM_3: *adc_channel = esp_i2s::ADC_CHANNEL_2; return 1; // OK + case GPIO_NUM_4: *adc_channel = esp_i2s::ADC_CHANNEL_3; return 1; // OK + case GPIO_NUM_5: *adc_channel = esp_i2s::ADC_CHANNEL_4; return 1; // OK + case GPIO_NUM_6: *adc_channel = esp_i2s::ADC_CHANNEL_5; return 1; // OK + case GPIO_NUM_7: *adc_channel = esp_i2s::ADC_CHANNEL_6; return 1; // OK + case GPIO_NUM_8: *adc_channel = esp_i2s::ADC_CHANNEL_7; return 1; // OK + case GPIO_NUM_9: *adc_channel = esp_i2s::ADC_CHANNEL_8; return 1; // OK + case GPIO_NUM_10: *adc_channel = esp_i2s::ADC_CHANNEL_9; return 1; // OK +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 + case GPIO_NUM_11: *adc_channel = esp_i2s::ADC_CHANNEL_0; return 1; // OK + case GPIO_NUM_12: *adc_channel = esp_i2s::ADC_CHANNEL_1; return 1; // OK + case GPIO_NUM_13: *adc_channel = esp_i2s::ADC_CHANNEL_2; return 1; // OK + case GPIO_NUM_14: *adc_channel = esp_i2s::ADC_CHANNEL_3; return 1; // OK + case GPIO_NUM_15: *adc_channel = esp_i2s::ADC_CHANNEL_4; return 1; // OK + case GPIO_NUM_16: *adc_channel = esp_i2s::ADC_CHANNEL_5; return 1; // OK + case GPIO_NUM_17: *adc_channel = esp_i2s::ADC_CHANNEL_6; return 1; // OK + case GPIO_NUM_18: *adc_channel = esp_i2s::ADC_CHANNEL_7; return 1; // OK + case GPIO_NUM_19: *adc_channel = esp_i2s::ADC_CHANNEL_8; return 1; // OK + case GPIO_NUM_20: *adc_channel = esp_i2s::ADC_CHANNEL_9; return 1; // OK +#endif + +#if (CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2) + case GPIO_NUM_0: *adc_channel = esp_i2s::ADC_CHANNEL_0; return 1; // OK + case GPIO_NUM_1: *adc_channel = esp_i2s::ADC_CHANNEL_1; return 1; // OK + case GPIO_NUM_2: *adc_channel = esp_i2s::ADC_CHANNEL_2; return 1; // OK + case GPIO_NUM_3: *adc_channel = esp_i2s::ADC_CHANNEL_3; return 1; // OK + case GPIO_NUM_4: *adc_channel = esp_i2s::ADC_CHANNEL_4; return 1; // OK + case GPIO_NUM_5: *adc_channel = esp_i2s::ADC_CHANNEL_0; return 1; // OK +#endif + default: + log_e("GPIO %d not usable for ADC!", gpio_num); + log_i("Please refer to documentation https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html"); + return 0; // ERR + } +} +#endif // SOC_I2S_SUPPORTS_ADC_DAC + +#if I2S_INTERFACES_COUNT > 0 + I2SClass I2S(I2S_DEVICE, I2S_CLOCK_GENERATOR, PIN_I2S_SD, PIN_I2S_SCK, PIN_I2S_FS); // default - half duplex +#endif + +#if I2S_INTERFACES_COUNT > 1 + // TODO set default pins for second module + //I2SClass I2S1(I2S_DEVICE+1, I2S_CLOCK_GENERATOR, PIN_I2S_SD, PIN_I2S_SCK, PIN_I2S_FS); // default - half duplex +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/src/I2S.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/src/I2S.h new file mode 100644 index 0000000..623fa89 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/I2S/src/I2S.h @@ -0,0 +1,195 @@ +/* + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _I2S_H_INCLUDED +#define _I2S_H_INCLUDED + +#include +#include "freertos/ringbuf.h" + +namespace esp_i2s { + #include "driver/i2s.h" // ESP specific i2s driver +} + +// Default pins +#ifndef PIN_I2S_SCK + #define PIN_I2S_SCK 14 +#endif + +#ifndef PIN_I2S_FS + #if CONFIG_IDF_TARGET_ESP32S2 + #define PIN_I2S_FS 27 + #else + #define PIN_I2S_FS 25 + #endif +#endif + +#ifndef PIN_I2S_SD + #define PIN_I2S_SD 26 +#endif + +#ifndef PIN_I2S_SD_OUT + #define PIN_I2S_SD_OUT 26 +#endif + +#ifndef PIN_I2S_SD_IN + #define PIN_I2S_SD_IN 35 // Pin 35 is only input! +#endif + +typedef enum { + I2S_PHILIPS_MODE, + I2S_RIGHT_JUSTIFIED_MODE, + I2S_LEFT_JUSTIFIED_MODE, + ADC_DAC_MODE, + PDM_STEREO_MODE, + PDM_MONO_MODE +} i2s_mode_t; + +class I2SClass : public Stream +{ +public: + // The device index and pins must map to the "COM" pads in Table 6-1 of the datasheet + I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin); + + // Init in MASTER mode: the SCK and FS pins are driven as outputs using the sample rate + int begin(int mode, int sampleRate, int bitsPerSample); + + // Init in SLAVE mode: the SCK and FS pins are inputs, other side controls sample rate + int begin(int mode, int bitsPerSample); + + // change pin setup and mode (default is Half Duplex) + // Can be called only on initialized object (after begin) + int setSckPin(int sckPin); + int setFsPin(int fsPin); + int setDataPin(int sdPin); // shared data pin for simplex + int setDataOutPin(int outSdPin); + int setDataInPin(int inSdPin); + + int setAllPins(); + int setAllPins(int sckPin, int fsPin, int sdPin, int outSdPin, int inSdPin); + + int getSckPin(); + int getFsPin(); + int getDataPin(); + int getDataOutPin(); + int getDataInPin(); + + int setDuplex(); + int setSimplex(); + int isDuplex(); + + void end(); + + // from Stream + virtual int available(); + virtual int read(); + virtual int peek(); + virtual void flush(); + + // from Print + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buffer, size_t size); + + virtual int availableForWrite(); + + int read(void* buffer, size_t size); + + //size_t write(int); + size_t write(int32_t); + size_t write(const void *buffer, size_t size); + size_t write_blocking(const void *buffer, size_t size); + size_t write_nonblocking(const void *buffer, size_t size); + + void onTransmit(void(*)(void)); + void onReceive(void(*)(void)); + + int setBufferSize(int bufferSize); + int getBufferSize(); +private: + #if (SOC_I2S_SUPPORTS_ADC && SOC_I2S_SUPPORTS_DAC) + int _gpioToAdcUnit(gpio_num_t gpio_num, esp_i2s::adc_unit_t* adc_unit); + int _gpioToAdcChannel(gpio_num_t gpio_num, esp_i2s::adc_channel_t* adc_channel); + #endif + int begin(int mode, int sampleRate, int bitsPerSample, bool driveClock); + + int _enableTransmitter(); + int _enableReceiver(); + void _onTransferComplete(); + + int _createCallbackTask(); + + static void onDmaTransferComplete(void*); + int _installDriver(); + void _uninstallDriver(); + void _setSckPin(int sckPin); + void _setFsPin(int fsPin); + void _setDataPin(int sdPin); + void _setDataOutPin(int outSdPin); + void _setDataInPin(int inSdPin); + int _applyPinSetting(); + +private: + typedef enum { + I2S_STATE_IDLE, + I2S_STATE_TRANSMITTER, + I2S_STATE_RECEIVER, + I2S_STATE_DUPLEX + } i2s_state_t; + + int _deviceIndex; + int _sdPin; + int _inSdPin; + int _outSdPin; + int _sckPin; + int _fsPin; + + i2s_state_t _state; + int _bitsPerSample; + uint32_t _sampleRate; + int _mode; + + uint16_t _buffer_byte_size; + + bool _driverInstalled; // Is IDF I2S driver installed? + bool _initialized; // Is everything initialized (callback task, I2S driver, ring buffers)? + TaskHandle_t _callbackTaskHandle; + QueueHandle_t _i2sEventQueue; + SemaphoreHandle_t _i2s_general_mutex; + RingbufHandle_t _input_ring_buffer; + RingbufHandle_t _output_ring_buffer; + int _i2s_dma_buffer_size; + bool _driveClock; + uint32_t _peek_buff; + bool _peek_buff_valid; + + void _tx_done_routine(uint8_t* prev_item); + void _rx_done_routine(); + + uint16_t _nesting_counter; + void _take_if_not_holding(); + void _give_if_top_call(); + void _post_read_data_fix(void *input, size_t *size); + void _fix_and_write(void *output, size_t size, size_t *bytes_written = NULL, size_t *actual_bytes_written = NULL); + + void (*_onTransmit)(void); + void (*_onReceive)(void); +}; + +extern I2SClass I2S; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino new file mode 100644 index 0000000..535409f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/DiagnosticsSmokeTest.ino @@ -0,0 +1,98 @@ +#include "Insights.h" +#include "WiFi.h" +#include "inttypes.h" +#include "esp_err.h" +#include "esp_random.h" + +const char insights_auth_key[] = ""; + +#define WIFI_SSID "" +#define WIFI_PASSPHRASE "" + +#define MAX_CRASHES 5 +#define MAX_PTRS 30 +#define TAG "sketch" + +RTC_NOINIT_ATTR static uint32_t s_reset_count; +static void *s_ptrs[MAX_PTRS]; + +static void smoke_test() +{ + int dice; + int count = 0; + bool allocating = false; + + while (1) { + dice = esp_random() % 500; + log_i("dice=%d", dice); + if (dice > 0 && dice < 150) { + log_e("[count][%d]", count); + } else if (dice > 150 && dice < 300) { + log_w("[count][%d]", count); + } else if (dice > 300 && dice < 470) { + Insights.event(TAG, "[count][%d]", count); + } else { + /* 30 in 500 probability to crash */ + if (s_reset_count > MAX_CRASHES) { + Insights.event(TAG, "[count][%d]", count); + } else { + log_e("[count][%d] [crash_count][%" PRIu32 "] [excvaddr][0x0f] Crashing...", count, s_reset_count); + *(int *)0x0F = 0x10; + } + } + + Insights.metrics.dumpHeap(); + if (count % MAX_PTRS == 0) { + allocating = !allocating; + log_i("Allocating:%s\n", allocating ? "true" : "false"); + } + if (allocating) { + uint32_t size = 1024 * (esp_random() % 8); + void *p = malloc(size); + if (p) { + memset(p, size, 'A' + (esp_random() % 26)); + log_i("Allocated %" PRIu32 " bytes", size); + } + s_ptrs[count % MAX_PTRS] = p; + } else { + free(s_ptrs[count % MAX_PTRS]); + s_ptrs[count % MAX_PTRS] = NULL; + log_i("Freeing some memory..."); + } + + count++; + delay(1000); + } +} + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSPHRASE); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + + if(!Insights.begin(insights_auth_key)){ + return; + } + Serial.println("========================================="); + Serial.printf("ESP Insights enabled Node ID %s\n", Insights.nodeID()); + Serial.println("========================================="); + + if (esp_reset_reason() == ESP_RST_POWERON) { + s_reset_count = 1; + } else { + s_reset_count++; + } +} + +void loop() +{ + smoke_test(); + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/README.md new file mode 100644 index 0000000..9094eec --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/DiagnosticsSmokeTest/README.md @@ -0,0 +1,45 @@ +# Smoke Test App + +## What to expect in this example? + +- This example is expected to exercise the various features of the ESP Insights framework +- As a smoke test, this allows you to validate, by a quick perusal of the ESP Insights dashboard, the functioning of all the high-level features + + +## End-to-End Tests + +### Lifecycle of the test (Hard reset resets the cycle) +* Device boots up and logs errors/warnings/events in random order every 10 seconds +* Every error/warning/event log with "diag_smoke" tag is associated with an incremental counter +* There's a 30/500 probability that device will crash, this is done for verification of crash +* Device will crash only five times and hard reset will reset the counter to 1 +* On sixth boot onwards device will not crash and logs errors/warnings/events and adds heap metrics + +### Facilitate the Auth Key +In this example we will be using the auth key that we downloaded while [setting up ESP Insights account](https://github.com/espressif/esp-insights/tree/main/examples#set-up-esp-insights-account). + +Copy Auth Key to the example +``` +const char insights_auth_key[] = ""; +``` + +### Enter WiFi Credentials +Inside the example sketch, enter your WiFi credentials in `WIFI_SSID` and `WIFI_PASSPHRASE` macros. + +### Setup +* Build and flash the sketch and monitor the console +* Device will eventually crash after some time +* Before every crash you will see below log print +``` +E (75826) diag_smoke: [count][7] [crash_count][1] [excvaddr][0x0f] Crashing... +// [count][7]: count associated with the log +// [crash_count][1]: This is the first crash since device boot up, this number will increment as the crash count increases +// [excvaddr][0x0f]: Exception vaddr, will see this in crash verification part below +``` +* You'll see five crashes([crash_count][5]) and after that device will not crash and will keep on logging and adding metrics +* Onwards this point keep device running for more than 30 minutes +* Now we are all set to visit the [dashboard](https://dashboard.insights.espressif.com) +* Select the node-id printed on the console, look for the below log. It is printed early when device boots up +``` +ESP Insights enabled for Node ID ----- wx3vEoGgJPk7Rn5JvRUFs9 +``` \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino new file mode 100644 index 0000000..39cac0c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/MinimalDiagnostics.ino @@ -0,0 +1,31 @@ +#include "Insights.h" +#include "WiFi.h" + +const char insights_auth_key[] = ""; + +#define WIFI_SSID "" +#define WIFI_PASSPHRASE "" + +void setup() +{ + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSPHRASE); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + if(!Insights.begin(insights_auth_key)){ + return; + } + Serial.println("========================================="); + Serial.printf("ESP Insights enabled Node ID %s\n", Insights.nodeID()); + Serial.println("========================================="); +} + +void loop() +{ + delay(1000); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/README.md new file mode 100644 index 0000000..35faa8d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/examples/MinimalDiagnostics/README.md @@ -0,0 +1,43 @@ +# Minimal Diagnostics example +- [What to expect in this example](#what-to-expect-in-this-example) +- [Try out the example](#try-out-the-example) +- [Insights Dashboard](#insights-dashboard) + +## What to expect in this example? +- This example demonstrates the use of ESP Insights framework in minimal way +- Device will try to connect with the configured WiFi network +- ESP Insights is enabled in this example, so any error/warning logs, crashes will be reported to cloud +- This example collects heap and wifi metrics every 10 minutes and network variables are collected when they change + +## Try out the example + +### Facilitate the Auth Key +In this example we will be using the auth key that we downloaded while [setting up ESP Insights account](https://github.com/espressif/esp-insights/tree/main/examples#set-up-esp-insights-account). + +Copy Auth Key to the example +``` +const char insights_auth_key[] = ""; +``` + +### Enter WiFi Credentials +Inside the example sketch, enter your WiFi credentials in `WIFI_SSID` and `WIFI_PASSPHRASE` macros. + +### Get the Node ID +- Start the Serial monitor + +- Once the device boots, it will connect to the Wi-Fi network, look for logs similar to below and make a note of Node ID. +``` +I (4161) esp_insights: ========================================= +I (4171) esp_insights: Insights enabled for Node ID 246F2880371C +I (4181) esp_insights: ========================================= +``` + + +## Insights Dashboard +Once everything is set up, any diagnostics information reported will show up on the [Insights Dashboard](https://dashboard.insights.espressif.com). Sign in using the your credentials. + + +### Monitor the device diagnostics +Visit [Nodes](https://dashboard.insights.espressif.com/home/nodes) section on the dashboard and click on the Node ID to monitor device diagnostics information. + +> Note: Diagnostics data is reported dynamically or when the buffers are filled to configured threshold. So, it can take some time for the logs to reflect on the dashboard. Moreover, if a large number of logs are generated then data will be sent to cloud but, if it fails(eg reasons: Wi-Fi failure, No internet) then any newer logs will be dropped. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/library.properties new file mode 100644 index 0000000..489aa29 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/library.properties @@ -0,0 +1,8 @@ +name=ESP Insights +version=1.0.0 +author=Sanket Wadekar +maintainer=Sanket Wadekar +sentence=ESP Insights +paragraph=With this library you can remotely monitor your device error logs, Network variables, WiFi/Heap Metrics, and also custom varibles / metrics. +url=https://insights.espressif.com +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/src/Insights.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/src/Insights.cpp new file mode 100644 index 0000000..49de5b2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/src/Insights.cpp @@ -0,0 +1,288 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "Insights.h" +#ifdef CONFIG_ESP_INSIGHTS_ENABLED +#include "esp_insights.h" +#include "esp_diagnostics.h" +#include "esp_diagnostics_metrics.h" +#include "esp_diagnostics_system_metrics.h" +#include "esp_diagnostics_variables.h" +#include "esp_diagnostics_network_variables.h" + +const char * ERROR_INSIGHTS_NOT_INIT = "ESP Insights not initialized"; + +#define BOOL_FN_OR_ERROR(f,e) \ + if(!initialized){ \ + log_e("%s",ERROR_INSIGHTS_NOT_INIT); \ + return false; \ + } \ + esp_err_t err = f; \ + if (err != ESP_OK) { \ + log_e("ESP Insights " e ", err:0x%x", err); \ + } \ + return err == ESP_OK; + +#define BOOL_FN_OR_ERROR_ARG(f,e,a) \ + if(!initialized){ \ + log_e("%s",ERROR_INSIGHTS_NOT_INIT); \ + return false; \ + } \ + esp_err_t err = f; \ + if (err != ESP_OK) { \ + log_e("ESP Insights " e ", err:0x%x", a, err); \ + } \ + return err == ESP_OK; + +#define VOID_FN_OR_ERROR(f) \ + if(!initialized){ \ + log_e("%s",ERROR_INSIGHTS_NOT_INIT); \ + return; \ + } \ + f; + +ESPInsightsClass::ESPInsightsClass(): initialized(false){} + +ESPInsightsClass::~ESPInsightsClass(){ + end(); +} + +bool ESPInsightsClass::begin(const char *auth_key, const char *node_id, uint32_t log_type, bool alloc_ext_ram, bool use_default_transport){ + if(!initialized){ + if(log_type == 0xFFFFFFFF){ + log_type = (ESP_DIAG_LOG_TYPE_ERROR | ESP_DIAG_LOG_TYPE_WARNING | ESP_DIAG_LOG_TYPE_EVENT); + } + esp_insights_config_t config = {.log_type = log_type, .node_id = node_id, .auth_key = auth_key, .alloc_ext_ram = alloc_ext_ram}; + esp_err_t err = ESP_OK; + if (use_default_transport) { + err = esp_insights_init(&config); + } else { + err = esp_insights_enable(&config); + } + if (err != ESP_OK) { + log_e("Failed to initialize ESP Insights, err:0x%x", err); + } + initialized = err == ESP_OK; + metrics.setInitialized(initialized); + variables.setInitialized(initialized); + } else { + log_i("ESP Insights already initialized"); + } + return initialized; +} + +void ESPInsightsClass::end(){ + if(initialized){ + esp_insights_deinit(); + initialized = false; + metrics.setInitialized(initialized); + variables.setInitialized(initialized); + } +} + +const char * ESPInsightsClass::nodeID(){ + if(!initialized){ + log_e("%s",ERROR_INSIGHTS_NOT_INIT); + return ""; + } + return esp_insights_get_node_id(); +} + +bool ESPInsightsClass::event(const char *tag, const char *format, ...){ + if(!initialized){ + log_e("%s",ERROR_INSIGHTS_NOT_INIT); + return false; + } + + char loc_buf[64]; + char * temp = loc_buf; + va_list arg; + va_list copy; + va_start(arg, format); + va_copy(copy, arg); + int len = vsnprintf(temp, sizeof(loc_buf), format, copy); + va_end(copy); + if(len < 0) { + va_end(arg); + return false; + }; + if(len >= (int)sizeof(loc_buf)){ // comparation of same sign type for the compiler + temp = (char*) malloc(len+1); + if(temp == NULL) { + va_end(arg); + return false; + } + len = vsnprintf(temp, len+1, format, arg); + } + va_end(arg); + esp_err_t err = esp_diag_log_event(tag, "%s", temp); + if(temp != loc_buf){ + free(temp); + } + if (err != ESP_OK) { + log_e("Failed to send ESP Insights event, err:0x%x", err); + } + return err == ESP_OK; +} + +bool ESPInsightsClass::send(){ + BOOL_FN_OR_ERROR(esp_insights_send_data(),"Failed to send"); +} + +void ESPInsightsClass::dumpTasksStatus(){ + VOID_FN_OR_ERROR(esp_diag_task_snapshot_dump()); +} + +// ESPInsightsMetricsClass + +bool ESPInsightsMetricsClass::addBool(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_BOOL),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::addInt(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_INT),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::addUint(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_UINT),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::addFloat(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_FLOAT),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::addString(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_STR),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::addIPv4(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_IPv4),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::addMAC(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_MAC),"Failed to add metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setBool(const char *key, bool b){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_bool(key, b),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setInt(const char *key, int32_t i){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_int(key, i),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setUint(const char *key, uint32_t u){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_uint(key, u),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setFloat(const char *key, float f){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_float(key, f),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setString(const char *key, const char *str){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_str(key, str),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setIPv4(const char *key, uint32_t ip){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_ipv4(key, ip),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::setMAC(const char *key, uint8_t *mac){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_add_mac(key, mac),"Failed to set metric '%s'",key); +} + +bool ESPInsightsMetricsClass::remove(const char *key){ + BOOL_FN_OR_ERROR_ARG(esp_diag_metrics_unregister(key),"Failed to remove metric '%s'",key); +} + +bool ESPInsightsMetricsClass::removeAll(){ + BOOL_FN_OR_ERROR(esp_diag_metrics_unregister_all(),"Failed to remove metrics"); +} + +void ESPInsightsMetricsClass::setHeapPeriod(uint32_t seconds){ + VOID_FN_OR_ERROR(esp_diag_heap_metrics_reset_interval(seconds)); +} + +bool ESPInsightsMetricsClass::dumpHeap(){ + BOOL_FN_OR_ERROR(esp_diag_heap_metrics_dump(),"Failed to send heap metrics"); +} + +void ESPInsightsMetricsClass::setWiFiPeriod(uint32_t seconds){ + VOID_FN_OR_ERROR(esp_diag_wifi_metrics_reset_interval(seconds)); +} + +bool ESPInsightsMetricsClass::dumpWiFi(){ + BOOL_FN_OR_ERROR(esp_diag_wifi_metrics_dump(),"Failed to send wifi metrics"); +} + +// ESPInsightsVariablesClass + +bool ESPInsightsVariablesClass::addBool(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_BOOL),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::addInt(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_INT),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::addUint(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_UINT),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::addFloat(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_FLOAT),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::addString(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_STR),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::addIPv4(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_IPv4),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::addMAC(const char *tag, const char *key, const char *label, const char *path){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_register(tag, key, label, path, ESP_DIAG_DATA_TYPE_MAC),"Failed to add variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setBool(const char *key, bool b){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_bool(key, b),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setInt(const char *key, int32_t i){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_int(key, i),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setUint(const char *key, uint32_t u){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_uint(key, u),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setFloat(const char *key, float f){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_float(key, f),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setString(const char *key, const char *str){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_str(key, str),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setIPv4(const char *key, uint32_t ip){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_ipv4(key, ip),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::setMAC(const char *key, uint8_t *mac){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_add_mac(key, mac),"Failed to set variable '%s'",key); +} + +bool ESPInsightsVariablesClass::remove(const char *key){ + BOOL_FN_OR_ERROR_ARG(esp_diag_variable_unregister(key),"Failed to remove variable '%s'",key); +} + +bool ESPInsightsVariablesClass::removeAll(){ + BOOL_FN_OR_ERROR(esp_diag_variable_unregister_all(),"Failed to remove variables"); +} + +ESPInsightsClass Insights; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/src/Insights.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/src/Insights.h new file mode 100644 index 0000000..d572c35 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Insights/src/Insights.h @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_INSIGHTS_ENABLED +#include "Arduino.h" + +#ifdef __cplusplus + +class ESPInsightsMetricsClass +{ + private: + bool initialized; + + public: + ESPInsightsMetricsClass():initialized(false){} + + bool addBool(const char *tag, const char *key, const char *label, const char *path); + bool addInt(const char *tag, const char *key, const char *label, const char *path); + bool addUint(const char *tag, const char *key, const char *label, const char *path); + bool addFloat(const char *tag, const char *key, const char *label, const char *path); + bool addString(const char *tag, const char *key, const char *label, const char *path); + bool addIPv4(const char *tag, const char *key, const char *label, const char *path); + bool addMAC(const char *tag, const char *key, const char *label, const char *path); + + bool setBool(const char *key, bool b); + bool setInt(const char *key, int32_t i); + bool setUint(const char *key, uint32_t u); + bool setFloat(const char *key, float f); + bool setString(const char *key, const char *str); + bool setIPv4(const char *key, uint32_t ip); + bool setMAC(const char *key, uint8_t *mac); + + bool remove(const char *key); + bool removeAll(); + + void setHeapPeriod(uint32_t seconds); + void setWiFiPeriod(uint32_t seconds); + + bool dumpHeap(); + bool dumpWiFi(); + + //internal use + void setInitialized(bool init){ initialized = init; } +}; + +class ESPInsightsVariablesClass +{ + private: + bool initialized; + + public: + ESPInsightsVariablesClass():initialized(false){} + + bool addBool(const char *tag, const char *key, const char *label, const char *path); + bool addInt(const char *tag, const char *key, const char *label, const char *path); + bool addUint(const char *tag, const char *key, const char *label, const char *path); + bool addFloat(const char *tag, const char *key, const char *label, const char *path); + bool addString(const char *tag, const char *key, const char *label, const char *path); + bool addIPv4(const char *tag, const char *key, const char *label, const char *path); + bool addMAC(const char *tag, const char *key, const char *label, const char *path); + + bool setBool(const char *key, bool b); + bool setInt(const char *key, int32_t i); + bool setUint(const char *key, uint32_t u); + bool setFloat(const char *key, float f); + bool setString(const char *key, const char *str); + bool setIPv4(const char *key, uint32_t ip); + bool setMAC(const char *key, uint8_t *mac); + + bool remove(const char *key); + bool removeAll(); + + //internal use + void setInitialized(bool init){ initialized = init; } +}; + +class ESPInsightsClass +{ + private: + bool initialized; + + public: + ESPInsightsMetricsClass metrics; + ESPInsightsVariablesClass variables; + + ESPInsightsClass(); + ~ESPInsightsClass(); + + bool begin(const char *auth_key, const char *node_id = NULL, uint32_t log_type = 0xFFFFFFFF, bool alloc_ext_ram = false, bool use_default_transport = true); + void end(); + bool send(); + const char * nodeID(); + + void dumpTasksStatus(); + + bool event(const char *tag, const char *format, ...); +}; + +extern ESPInsightsClass Insights; + +extern "C" +{ +#endif + +#include "esp_err.h" +#include "esp_log.h" +esp_err_t esp_diag_log_event(const char *tag, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +#define insightsEvent(tag, format, ...) {esp_diag_log_event(tag, "EV (%" PRIu32 ") %s: " format, esp_log_timestamp(), tag, ##__VA_ARGS__);} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/.gitignore b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/.gitignore new file mode 100644 index 0000000..87515a6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/.gitignore @@ -0,0 +1,4 @@ +.pio +.vscode +mklittlefs.exe +mklittlefs \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/README.md new file mode 100644 index 0000000..773445b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/README.md @@ -0,0 +1,68 @@ +# How to run on PlatformIO IDE + +- Download and extract to this project root a **mklittlefs** executable for your OS [from a zipped binary here](https://github.com/earlephilhower/mklittlefs/releases) +- Open **LITTLEFS_PlatformIO** folder +- Run PlatformIO project task: **Upload Filesystem Image** +- Run PlatformIO project task: **Upload and Monitor** +- You will see a Serial output like: +``` +--- Miniterm on COM5 115200,8,N,1 --- +--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- +ets Jun 8 2016 00:22:57 + +rst:0x1 (POWERON_RESET),boot:0x13 (Snfigsip: 0, SPIWP:0xee +clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 +mode:DIO, clock div:2 +load:0x3fff0018,len:4 +load:0x3fff001c,len:1044 +load:0x40078000,len:10044 +load:0x40080400,len:5872 +entry 0x400806ac +Listing directory: / + FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 + DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 +Creating Dir: /mydir +Dir created +Writing file: /mydir/hello2.txt +- file written +Listing directory: / + FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 + DIR : /mydir LAST WRITE: 1970-01-01 00:00:00 +Listing directory: /mydir + FILE: /mydir/hello2.txt SIZE: 6 LAST WRITE: 1970-01-01 00:00:00 + DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 +Listing directory: /testfolder + FILE: /testfolder/test2.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 +Deleting file: /mydir/hello2.txt +- file deleted +Removing Dir: /mydir +Dir removed +Listing directory: / + FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 + DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 +Listing directory: /testfolder + FILE: /testfolder/test2.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 +Writing file: /hello.txt +- file written +Appending to file: /hello.txt +- message appended +Reading file: /hello.txt +- read from file: +Hello World! +Renaming file /hello.txt to /foo.txt +- file renamed +Reading file: /foo.txt +- read from file: +Hello World! +Deleting file: /foo.txt +- file deleted +Testing file I/O with /test.txt +- writing................................................................ + - 1048576 bytes written in 12006 ms +- reading................................................................ +- 1048576 bytes read in 547 ms +Deleting file: /test.txt +- file deleted +Test complete +``` +- If you have a module with more than 4MB flash, you can uncomment **partitions_custom.csv** in **platformio.ini** and modify the csv file accordingly \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/file1.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/file1.txt new file mode 100644 index 0000000..7c4a013 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/file1.txt @@ -0,0 +1 @@ +aaa \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt new file mode 100644 index 0000000..01f02e3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt @@ -0,0 +1 @@ +bbb \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py new file mode 100644 index 0000000..9cda26f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py @@ -0,0 +1,2 @@ +Import("env") +env.Replace( MKFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' ) # PlatformIO now believes it has actually created a SPIFFS diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv new file mode 100644 index 0000000..97846fa --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +ota_0, app, ota_0, 0x10000, 0x1A0000, +ota_1, app, ota_1, , 0x1A0000, +otadata, data, ota, 0x350000, 0x2000, +nvs, data, nvs, , 0x6000, +data, data, spiffs, , 0xA8000, diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/platformio.ini b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/platformio.ini new file mode 100644 index 0000000..4d3087a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/platformio.ini @@ -0,0 +1,24 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = esp32 + +[env] +framework = arduino + +[env:esp32] +platform = espressif32 +board = esp32dev +;board_build.partitions = partitions_custom.csv +monitor_filters = esp32_exception_decoder +monitor_speed = 115200 + +extra_scripts = ./littlefsbuilder.py diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/src/main.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/src/main.cpp new file mode 100644 index 0000000..0fc275f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_PlatformIO/src/main.cpp @@ -0,0 +1,282 @@ +#include +#include "FS.h" +#include +#include + +/* You only need to format LittleFS the first time you run a + test or else use the LITTLEFS plugin to create a partition + https://github.com/lorol/arduino-esp32littlefs-plugin */ + +#define FORMAT_LITTLEFS_IF_FAILED true + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("- failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + + Serial.print(file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + + if(levels){ + listDir(fs, file.name(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + + File file = fs.open(path); + if(!file || file.isDirectory()){ + Serial.println("- failed to open file for reading"); + return; + } + + Serial.println("- read from file:"); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\r\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("- failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("- message appended"); + } else { + Serial.println("- append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\r\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("- file renamed"); + } else { + Serial.println("- rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\r\n", path); + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } +} + +// SPIFFS-like write and delete file + +// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.cpp#L60 +void writeFile2(fs::FS &fs, const char * path, const char * message){ + if(!fs.exists(path)){ + if (strchr(path, '/')) { + Serial.printf("Create missing folders of: %s\r\n", path); + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strchr(pathStr, '/'); + while (ptr) { + *ptr = 0; + fs.mkdir(pathStr); + *ptr = '/'; + ptr = strchr(ptr+1, '/'); + } + } + free(pathStr); + } + } + + Serial.printf("Writing file to: %s\r\n", path); + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h#L149 +void deleteFile2(fs::FS &fs, const char * path){ + Serial.printf("Deleting file and empty folders on path: %s\r\n", path); + + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } + + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strrchr(pathStr, '/'); + if (ptr) { + Serial.printf("Removing all empty folders on path: %s\r\n", path); + } + while (ptr) { + *ptr = 0; + fs.rmdir(pathStr); + ptr = strrchr(pathStr, '/'); + } + free(pathStr); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + Serial.printf("Testing file I/O with %s\r\n", path); + + static uint8_t buf[512]; + size_t len = 0; + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + + size_t i; + Serial.print("- writing" ); + uint32_t start = millis(); + for(i=0; i<2048; i++){ + if ((i & 0x001F) == 0x001F){ + Serial.print("."); + } + file.write(buf, 512); + } + Serial.println(""); + uint32_t end = millis() - start; + Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end); + file.close(); + + file = fs.open(path); + start = millis(); + end = start; + i = 0; + if(file && !file.isDirectory()){ + len = file.size(); + size_t flen = len; + start = millis(); + Serial.print("- reading" ); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + if ((i++ & 0x001F) == 0x001F){ + Serial.print("."); + } + len -= toRead; + } + Serial.println(""); + end = millis() - start; + Serial.printf("- %u bytes read in %u ms\r\n", flen, end); + file.close(); + } else { + Serial.println("- failed to open file for reading"); + } +} + +void setup(){ + Serial.begin(115200); + if(!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ + Serial.println("LittleFS Mount Failed"); + return; + } + + listDir(LittleFS, "/", 0); + createDir(LittleFS, "/mydir"); + writeFile(LittleFS, "/mydir/hello2.txt", "Hello2"); + //writeFile(LittleFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3"); + writeFile2(LittleFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3"); + listDir(LittleFS, "/", 3); + deleteFile(LittleFS, "/mydir/hello2.txt"); + //deleteFile(LittleFS, "/mydir/newdir2/newdir3/hello3.txt"); + deleteFile2(LittleFS, "/mydir/newdir2/newdir3/hello3.txt"); + removeDir(LittleFS, "/mydir"); + listDir(LittleFS, "/", 3); + writeFile(LittleFS, "/hello.txt", "Hello "); + appendFile(LittleFS, "/hello.txt", "World!\r\n"); + readFile(LittleFS, "/hello.txt"); + renameFile(LittleFS, "/hello.txt", "/foo.txt"); + readFile(LittleFS, "/foo.txt"); + deleteFile(LittleFS, "/foo.txt"); + testFileIO(LittleFS, "/test.txt"); + deleteFile(LittleFS, "/test.txt"); + + Serial.println( "Test complete" ); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_test/LITTLEFS_test.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_test/LITTLEFS_test.ino new file mode 100644 index 0000000..5c3ca4b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_test/LITTLEFS_test.ino @@ -0,0 +1,288 @@ +#include +#include "FS.h" +#include + +/* You only need to format LittleFS the first time you run a + test or else use the LITTLEFS plugin to create a partition + https://github.com/lorol/arduino-esp32littlefs-plugin + + If you test two partitions, you need to use a custom + partition.csv file, see in the sketch folder */ + +//#define TWOPART + +#define FORMAT_LITTLEFS_IF_FAILED true + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("- failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print("\tSIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + + File file = fs.open(path); + if(!file || file.isDirectory()){ + Serial.println("- failed to open file for reading"); + return; + } + + Serial.println("- read from file:"); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\r\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("- failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("- message appended"); + } else { + Serial.println("- append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\r\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("- file renamed"); + } else { + Serial.println("- rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\r\n", path); + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } +} + +// SPIFFS-like write and delete file, better use #define CONFIG_LITTLEFS_SPIFFS_COMPAT 1 + +void writeFile2(fs::FS &fs, const char * path, const char * message){ + if(!fs.exists(path)){ + if (strchr(path, '/')) { + Serial.printf("Create missing folders of: %s\r\n", path); + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strchr(pathStr, '/'); + while (ptr) { + *ptr = 0; + fs.mkdir(pathStr); + *ptr = '/'; + ptr = strchr(ptr+1, '/'); + } + } + free(pathStr); + } + } + + Serial.printf("Writing file to: %s\r\n", path); + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void deleteFile2(fs::FS &fs, const char * path){ + Serial.printf("Deleting file and empty folders on path: %s\r\n", path); + + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } + + char *pathStr = strdup(path); + if (pathStr) { + char *ptr = strrchr(pathStr, '/'); + if (ptr) { + Serial.printf("Removing all empty folders on path: %s\r\n", path); + } + while (ptr) { + *ptr = 0; + fs.rmdir(pathStr); + ptr = strrchr(pathStr, '/'); + } + free(pathStr); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + Serial.printf("Testing file I/O with %s\r\n", path); + + static uint8_t buf[512]; + size_t len = 0; + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + + size_t i; + Serial.print("- writing" ); + uint32_t start = millis(); + for(i=0; i<2048; i++){ + if ((i & 0x001F) == 0x001F){ + Serial.print("."); + } + file.write(buf, 512); + } + Serial.println(""); + uint32_t end = millis() - start; + Serial.printf(" - %u bytes written in %lu ms\r\n", 2048 * 512, end); + file.close(); + + file = fs.open(path); + start = millis(); + end = start; + i = 0; + if(file && !file.isDirectory()){ + len = file.size(); + size_t flen = len; + start = millis(); + Serial.print("- reading" ); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + if ((i++ & 0x001F) == 0x001F){ + Serial.print("."); + } + len -= toRead; + } + Serial.println(""); + end = millis() - start; + Serial.printf("- %u bytes read in %lu ms\r\n", flen, end); + file.close(); + } else { + Serial.println("- failed to open file for reading"); + } +} + +void setup(){ + Serial.begin(115200); + +#ifdef TWOPART + if(!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED, "/lfs2", 5, "part2")){ + Serial.println("part2 Mount Failed"); + return; + } + appendFile(LittleFS, "/hello0.txt", "World0!\r\n"); + readFile(LittleFS, "/hello0.txt"); + LittleFS.end(); + + Serial.println( "Done with part2, work with the first lfs partition..." ); +#endif + + if(!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ + Serial.println("LittleFS Mount Failed"); + return; + } + Serial.println( "SPIFFS-like write file to new path and delete it w/folders" ); + writeFile2(LittleFS, "/new1/new2/new3/hello3.txt", "Hello3"); + listDir(LittleFS, "/", 3); + deleteFile2(LittleFS, "/new1/new2/new3/hello3.txt"); + + listDir(LittleFS, "/", 3); + createDir(LittleFS, "/mydir"); + writeFile(LittleFS, "/mydir/hello2.txt", "Hello2"); + listDir(LittleFS, "/", 1); + deleteFile(LittleFS, "/mydir/hello2.txt"); + removeDir(LittleFS, "/mydir"); + listDir(LittleFS, "/", 1); + writeFile(LittleFS, "/hello.txt", "Hello "); + appendFile(LittleFS, "/hello.txt", "World!\r\n"); + readFile(LittleFS, "/hello.txt"); + renameFile(LittleFS, "/hello.txt", "/foo.txt"); + readFile(LittleFS, "/foo.txt"); + deleteFile(LittleFS, "/foo.txt"); + testFileIO(LittleFS, "/test.txt"); + deleteFile(LittleFS, "/test.txt"); + + Serial.println( "Test complete" ); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_test/partitions.csv b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_test/partitions.csv new file mode 100644 index 0000000..bf49289 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_test/partitions.csv @@ -0,0 +1,8 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x100000, +app1, app, ota_1, ,0x100000, +spiffs, data, spiffs, ,0x1D0000, +part2, data, spiffs, ,0x20000, +#1048576 \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_time/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_time/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_time/LITTLEFS_time.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_time/LITTLEFS_time.ino new file mode 100644 index 0000000..038261b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/examples/LITTLEFS_time/LITTLEFS_time.ino @@ -0,0 +1,214 @@ +#include "FS.h" +//#include "SPIFFS.h" +#include "LittleFS.h" +#include +#include + +#define SPIFFS LittleFS + +/* This examples uses "quick re-define" of SPIFFS to run + an existing sketch with LittleFS instead of SPIFFS + + You only need to format LittleFS the first time you run a + test or else use the LittleFS plugin to create a partition + https://github.com/lorol/arduino-esp32littlefs-plugin */ + +#define FORMAT_LITTLEFS_IF_FAILED true + +const char* ssid = "yourssid"; +const char* password = "yourpass"; + +long timezone = 1; +byte daysavetime = 1; + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.print (file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup(){ + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + + if(!SPIFFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ + Serial.println("LittleFS Mount Failed"); + return; + } + + Serial.println("----list 1----"); + listDir(SPIFFS, "/", 1); + + Serial.println("----remove old dir----"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----create a new dir----"); + createDir(SPIFFS, "/mydir"); + + Serial.println("----remove the new dir----"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----create the new again----"); + createDir(SPIFFS, "/mydir"); + + Serial.println("----create and work with file----"); + writeFile(SPIFFS, "/mydir/hello.txt", "Hello "); + appendFile(SPIFFS, "/mydir/hello.txt", "World!\n"); + + Serial.println("----list 2----"); + listDir(SPIFFS, "/", 1); + + Serial.println("----attempt to remove dir w/ file----"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----remove dir after deleting file----"); + deleteFile(SPIFFS, "/mydir/hello.txt"); + removeDir(SPIFFS, "/mydir"); + + Serial.println("----list 3----"); + listDir(SPIFFS, "/", 1); + + Serial.println( "Test complete" ); + +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/library.properties new file mode 100644 index 0000000..562cfaf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/library.properties @@ -0,0 +1,9 @@ +name=LittleFS +version=2.0.0 +author= +maintainer= +sentence=LittleFS for esp32 +paragraph=LittleFS for esp32 +category=Data Storage +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/src/LittleFS.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/src/LittleFS.cpp new file mode 100644 index 0000000..608e0ba --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/src/LittleFS.cpp @@ -0,0 +1,145 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + + +#include "vfs_api.h" + +extern "C" { +#include +#include +#include +} +#include "sdkconfig.h" +#include "LittleFS.h" + +#ifdef CONFIG_LITTLEFS_PAGE_SIZE +extern "C" { + #include "esp_littlefs.h" +} + +using namespace fs; + +class LittleFSImpl : public VFSImpl +{ +public: + LittleFSImpl(); + virtual ~LittleFSImpl() { } + virtual bool exists(const char* path); +}; + +LittleFSImpl::LittleFSImpl() +{ +} + +bool LittleFSImpl::exists(const char* path) +{ + File f = open(path, "r",false); + return (f == true); +} + +LittleFSFS::LittleFSFS() : FS(FSImplPtr(new LittleFSImpl())), partitionLabel_(NULL) +{ +} + +LittleFSFS::~LittleFSFS() +{ + if (partitionLabel_){ + free(partitionLabel_); + partitionLabel_ = NULL; + } +} + +bool LittleFSFS::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFiles, const char * partitionLabel) +{ + + if (partitionLabel_){ + free(partitionLabel_); + partitionLabel_ = NULL; + } + + if (partitionLabel){ + partitionLabel_ = strdup(partitionLabel); + } + + if(esp_littlefs_mounted(partitionLabel_)){ + log_w("LittleFS Already Mounted!"); + return true; + } + + esp_vfs_littlefs_conf_t conf = { + .base_path = basePath, + .partition_label = partitionLabel_, + .format_if_mount_failed = false, + .dont_mount = false + }; + + esp_err_t err = esp_vfs_littlefs_register(&conf); + if(err == ESP_FAIL && formatOnFail){ + if(format()){ + err = esp_vfs_littlefs_register(&conf); + } + } + if(err != ESP_OK){ + log_e("Mounting LittleFS failed! Error: %d", err); + return false; + } + _impl->mountpoint(basePath); + return true; +} + +void LittleFSFS::end() +{ + if(esp_littlefs_mounted(partitionLabel_)){ + esp_err_t err = esp_vfs_littlefs_unregister(partitionLabel_); + if(err){ + log_e("Unmounting LittleFS failed! Error: %d", err); + return; + } + _impl->mountpoint(NULL); + } +} + +bool LittleFSFS::format() +{ + disableCore0WDT(); + esp_err_t err = esp_littlefs_format(partitionLabel_); + enableCore0WDT(); + if(err){ + log_e("Formatting LittleFS failed! Error: %d", err); + return false; + } + return true; +} + +size_t LittleFSFS::totalBytes() +{ + size_t total,used; + if(esp_littlefs_info(partitionLabel_, &total, &used)){ + return 0; + } + return total; +} + +size_t LittleFSFS::usedBytes() +{ + size_t total,used; + if(esp_littlefs_info(partitionLabel_, &total, &used)){ + return 0; + } + return used; +} + +LittleFSFS LittleFS; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/src/LittleFS.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/src/LittleFS.h new file mode 100644 index 0000000..dbe45cb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/LittleFS/src/LittleFS.h @@ -0,0 +1,42 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _LITTLEFS_H_ +#define _LITTLEFS_H_ + +#include "FS.h" + +namespace fs +{ + +class LittleFSFS : public FS +{ +public: + LittleFSFS(); + ~LittleFSFS(); + bool begin(bool formatOnFail=false, const char * basePath="/littlefs", uint8_t maxOpenFiles=10, const char * partitionLabel="spiffs"); + bool format(); + size_t totalBytes(); + size_t usedBytes(); + void end(); + +private: + char * partitionLabel_; +}; + +} + +extern fs::LittleFSFS LittleFS; + + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/examples/ESP_NBNST/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/examples/ESP_NBNST/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/examples/ESP_NBNST/ESP_NBNST.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/examples/ESP_NBNST/ESP_NBNST.ino new file mode 100644 index 0000000..0f49e5a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/examples/ESP_NBNST/ESP_NBNST.ino @@ -0,0 +1,31 @@ +#include +#include + +const char* ssid = "............"; +const char* password = ".............."; + +void setup() { + Serial.begin(115200); + + // Connect to WiFi network + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + NBNS.begin("ESP"); +} + +void loop() { + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/keywords.txt new file mode 100644 index 0000000..68bcbee --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/keywords.txt @@ -0,0 +1,25 @@ +####################################### +# Syntax Coloring Map For ESPNBNS +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +NetBIOS KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +NBNS KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/library.properties new file mode 100644 index 0000000..c1ca95d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/library.properties @@ -0,0 +1,9 @@ +name=NetBIOS +version=2.0.0 +author=Pablo@xpablo.cz +maintainer=Hristo Gochkov +sentence=Enables NBNS (NetBIOS) name resolution. +paragraph=With this library you can connect to your ESP from Windows using a short name +category=Communication +url=http://www.xpablo.cz/?p=751#more-751 +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/src/NetBIOS.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/src/NetBIOS.cpp new file mode 100644 index 0000000..3470273 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/src/NetBIOS.cpp @@ -0,0 +1,131 @@ +#include "NetBIOS.h" + +#include + +#define NBNS_PORT 137 +#define NBNS_MAX_HOSTNAME_LEN 32 + +typedef struct { + uint16_t id; + uint8_t flags1; + uint8_t flags2; + uint16_t qcount; + uint16_t acount; + uint16_t nscount; + uint16_t adcount; + uint8_t name_len; + char name[NBNS_MAX_HOSTNAME_LEN + 1]; + uint16_t type; + uint16_t clas; +} __attribute__((packed)) nbns_question_t; + +typedef struct { + uint16_t id; + uint8_t flags1; + uint8_t flags2; + uint16_t qcount; + uint16_t acount; + uint16_t nscount; + uint16_t adcount; + uint8_t name_len; + char name[NBNS_MAX_HOSTNAME_LEN + 1]; + uint16_t type; + uint16_t clas; + uint32_t ttl; + uint16_t data_len; + uint16_t flags; + uint32_t addr; +} __attribute__((packed)) nbns_answer_t; + +static void _getnbname(const char *nbname, char *name, uint8_t maxlen){ + uint8_t b; + uint8_t c = 0; + + while ((*nbname) && (c < maxlen)) { + b = (*nbname++ - 'A') << 4; + c++; + if (*nbname) { + b |= *nbname++ - 'A'; + c++; + } + if(!b || b == ' '){ + break; + } + *name++ = b; + } + *name = 0; +} + +static void append_16(void * dst, uint16_t value){ + uint8_t * d = (uint8_t *)dst; + *d++ = (value >> 8) & 0xFF; + *d++ = value & 0xFF; +} + +static void append_32(void * dst, uint32_t value){ + uint8_t * d = (uint8_t *)dst; + *d++ = (value >> 24) & 0xFF; + *d++ = (value >> 16) & 0xFF; + *d++ = (value >> 8) & 0xFF; + *d++ = value & 0xFF; +} + +void NetBIOS::_onPacket(AsyncUDPPacket& packet){ + if (packet.length() >= sizeof(nbns_question_t)) { + nbns_question_t * question = (nbns_question_t *)packet.data(); + if (0 == (question->flags1 & 0x80)) { + char name[ NBNS_MAX_HOSTNAME_LEN + 1 ]; + _getnbname(&question->name[0], (char *)&name, question->name_len); + if (_name.equals(name)) { + nbns_answer_t nbnsa; + nbnsa.id = question->id; + nbnsa.flags1 = 0x85; + nbnsa.flags2 = 0; + append_16((void *)&nbnsa.qcount, 0); + append_16((void *)&nbnsa.acount, 1); + append_16((void *)&nbnsa.nscount, 0); + append_16((void *)&nbnsa.adcount, 0); + nbnsa.name_len = question->name_len; + memcpy(&nbnsa.name[0], &question->name[0], question->name_len + 1); + append_16((void *)&nbnsa.type, 0x20); + append_16((void *)&nbnsa.clas, 1); + append_32((void *)&nbnsa.ttl, 300000); + append_16((void *)&nbnsa.data_len, 6); + append_16((void *)&nbnsa.flags, 0); + nbnsa.addr = WiFi.localIP(); + _udp.writeTo((uint8_t *)&nbnsa, sizeof(nbnsa), packet.remoteIP(), NBNS_PORT); + } + } + } +} + +NetBIOS::NetBIOS(){ + +} +NetBIOS::~NetBIOS(){ + end(); +} + +bool NetBIOS::begin(const char *name){ + _name = name; + _name.toUpperCase(); + + if(_udp.connected()){ + return true; + } + + _udp.onPacket([](void * arg, AsyncUDPPacket& packet){ ((NetBIOS*)(arg))->_onPacket(packet); }, this); + return _udp.listen(NBNS_PORT); +} + +void NetBIOS::end(){ + if(_udp.connected()){ + _udp.close(); + } +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS) +NetBIOS NBNS; +#endif + +// EOF diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/src/NetBIOS.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/src/NetBIOS.h new file mode 100644 index 0000000..2548826 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/NetBIOS/src/NetBIOS.h @@ -0,0 +1,26 @@ +// +#ifndef __ESPNBNS_h__ +#define __ESPNBNS_h__ + +#include +#include "AsyncUDP.h" + +class NetBIOS +{ +protected: + AsyncUDP _udp; + String _name; + void _onPacket(AsyncUDPPacket& packet); + +public: + NetBIOS(); + ~NetBIOS(); + bool begin(const char *name); + void end(); +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS) +extern NetBIOS NBNS; +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/examples/Prefs2Struct/Prefs2Struct.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/examples/Prefs2Struct/Prefs2Struct.ino new file mode 100644 index 0000000..7ed2a73 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/examples/Prefs2Struct/Prefs2Struct.ino @@ -0,0 +1,43 @@ +/* +This example shows how to use Preferences (nvs) to store a +structure. Note that the maximum size of a putBytes is 496K +or 97% of the nvs partition size. nvs has signifcant overhead, +so should not be used for data that will change often. +*/ +#include +Preferences prefs; + +typedef struct { + uint8_t hour; + uint8_t minute; + uint8_t setting1; + uint8_t setting2; +} schedule_t; + +void setup() { + Serial.begin(115200); + prefs.begin("schedule"); // use "schedule" namespace + uint8_t content[] = {9, 30, 235, 255, 20, 15, 0, 1}; // two entries + prefs.putBytes("schedule", content, sizeof(content)); + size_t schLen = prefs.getBytesLength("schedule"); + char buffer[schLen]; // prepare a buffer for the data + prefs.getBytes("schedule", buffer, schLen); + if (schLen % sizeof(schedule_t)) { // simple check that data fits + log_e("Data is not correct size!"); + return; + } + schedule_t *schedule = (schedule_t *) buffer; // cast the bytes into a struct ptr + Serial.printf("%02d:%02d %d/%d\n", + schedule[1].hour, schedule[1].minute, + schedule[1].setting1, schedule[1].setting2); + schedule[2] = {8, 30, 20, 21}; // add a third entry (unsafely) +// force the struct array into a byte array + prefs.putBytes("schedule", schedule, 3*sizeof(schedule_t)); + schLen = prefs.getBytesLength("schedule"); + char buffer2[schLen]; + prefs.getBytes("schedule", buffer2, schLen); + for (int x=0; x + +Preferences preferences; + +void setup() { + Serial.begin(115200); + Serial.println(); + + // Open Preferences with my-app namespace. Each application module, library, etc + // has to use a namespace name to prevent key name collisions. We will open storage in + // RW-mode (second parameter has to be false). + // Note: Namespace name is limited to 15 chars. + preferences.begin("my-app", false); + + // Remove all preferences under the opened namespace + //preferences.clear(); + + // Or remove the counter key only + //preferences.remove("counter"); + + // Get the counter value, if the key does not exist, return a default value of 0 + // Note: Key name is limited to 15 chars. + unsigned int counter = preferences.getUInt("counter", 0); + + // Increase counter by 1 + counter++; + + // Print the counter to Serial Monitor + Serial.printf("Current counter value: %u\n", counter); + + // Store the counter to the Preferences + preferences.putUInt("counter", counter); + + // Close the Preferences + preferences.end(); + + // Wait 10 seconds + Serial.println("Restarting in 10 seconds..."); + delay(10000); + + // Restart ESP + ESP.restart(); +} + +void loop() {} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/keywords.txt new file mode 100644 index 0000000..fe2d433 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/keywords.txt @@ -0,0 +1,54 @@ +####################################### +# Syntax Coloring Map NVS +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Preferences KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 + +clear KEYWORD2 +remove KEYWORD2 + +putChar KEYWORD2 +putUChar KEYWORD2 +putShort KEYWORD2 +putUShort KEYWORD2 +putInt KEYWORD2 +putUInt KEYWORD2 +putLong KEYWORD2 +putULong KEYWORD2 +putLong64 KEYWORD2 +putULong64 KEYWORD2 +putFloat KEYWORD2 +putDouble KEYWORD2 +putBool KEYWORD2 +putString KEYWORD2 +putBytes KEYWORD2 + +getChar KEYWORD2 +getUChar KEYWORD2 +getShort KEYWORD2 +getUShort KEYWORD2 +getInt KEYWORD2 +getUInt KEYWORD2 +getLong KEYWORD2 +getULong KEYWORD2 +getLong64 KEYWORD2 +getULong64 KEYWORD2 +getFloat KEYWORD2 +getDouble KEYWORD2 +getBool KEYWORD2 +getString KEYWORD2 +getBytes KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/library.properties new file mode 100644 index 0000000..bda63d8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/library.properties @@ -0,0 +1,9 @@ +name=Preferences +version=2.0.0 +author=Hristo Gochkov +maintainer=Hristo Gochkov +sentence=Provides friendly access to ESP32's Non-Volatile Storage +paragraph= +category=Data Storage +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/src/Preferences.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/src/Preferences.cpp new file mode 100644 index 0000000..81397c8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/src/Preferences.cpp @@ -0,0 +1,534 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Preferences.h" + +#include "nvs.h" +#include "nvs_flash.h" + +const char * nvs_errors[] = { "OTHER", "NOT_INITIALIZED", "NOT_FOUND", "TYPE_MISMATCH", "READ_ONLY", "NOT_ENOUGH_SPACE", "INVALID_NAME", "INVALID_HANDLE", "REMOVE_FAILED", "KEY_TOO_LONG", "PAGE_FULL", "INVALID_STATE", "INVALID_LENGTH"}; +#define nvs_error(e) (((e)>ESP_ERR_NVS_BASE)?nvs_errors[(e)&~(ESP_ERR_NVS_BASE)]:nvs_errors[0]) + +Preferences::Preferences() + :_handle(0) + ,_started(false) + ,_readOnly(false) +{} + +Preferences::~Preferences(){ + end(); +} + +bool Preferences::begin(const char * name, bool readOnly, const char* partition_label){ + if(_started){ + return false; + } + _readOnly = readOnly; + esp_err_t err = ESP_OK; + if (partition_label != NULL) { + err = nvs_flash_init_partition(partition_label); + if (err) { + log_e("nvs_flash_init_partition failed: %s", nvs_error(err)); + return false; + } + err = nvs_open_from_partition(partition_label, name, readOnly ? NVS_READONLY : NVS_READWRITE, &_handle); + } else { + err = nvs_open(name, readOnly ? NVS_READONLY : NVS_READWRITE, &_handle); + } + if(err){ + log_e("nvs_open failed: %s", nvs_error(err)); + return false; + } + _started = true; + return true; +} + +void Preferences::end(){ + if(!_started){ + return; + } + nvs_close(_handle); + _started = false; +} + +/* + * Clear all keys in opened preferences + * */ + +bool Preferences::clear(){ + if(!_started || _readOnly){ + return false; + } + esp_err_t err = nvs_erase_all(_handle); + if(err){ + log_e("nvs_erase_all fail: %s", nvs_error(err)); + return false; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s", nvs_error(err)); + return false; + } + return true; +} + +/* + * Remove a key + * */ + +bool Preferences::remove(const char * key){ + if(!_started || !key || _readOnly){ + return false; + } + esp_err_t err = nvs_erase_key(_handle, key); + if(err){ + log_e("nvs_erase_key fail: %s %s", key, nvs_error(err)); + return false; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return false; + } + return true; +} + +/* + * Put a key value + * */ + +size_t Preferences::putChar(const char* key, int8_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i8(_handle, key, value); + if(err){ + log_e("nvs_set_i8 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 1; +} + +size_t Preferences::putUChar(const char* key, uint8_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u8(_handle, key, value); + if(err){ + log_e("nvs_set_u8 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 1; +} + +size_t Preferences::putShort(const char* key, int16_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i16(_handle, key, value); + if(err){ + log_e("nvs_set_i16 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 2; +} + +size_t Preferences::putUShort(const char* key, uint16_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u16(_handle, key, value); + if(err){ + log_e("nvs_set_u16 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 2; +} + +size_t Preferences::putInt(const char* key, int32_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i32(_handle, key, value); + if(err){ + log_e("nvs_set_i32 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 4; +} + +size_t Preferences::putUInt(const char* key, uint32_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u32(_handle, key, value); + if(err){ + log_e("nvs_set_u32 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 4; +} + +size_t Preferences::putLong(const char* key, int32_t value){ + return putInt(key, value); +} + +size_t Preferences::putULong(const char* key, uint32_t value){ + return putUInt(key, value); +} + +size_t Preferences::putLong64(const char* key, int64_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_i64(_handle, key, value); + if(err){ + log_e("nvs_set_i64 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 8; +} + +size_t Preferences::putULong64(const char* key, uint64_t value){ + if(!_started || !key || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_u64(_handle, key, value); + if(err){ + log_e("nvs_set_u64 fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return 8; +} + +size_t Preferences::putFloat(const char* key, const float_t value){ + return putBytes(key, (void*)&value, sizeof(float_t)); +} + +size_t Preferences::putDouble(const char* key, const double_t value){ + return putBytes(key, (void*)&value, sizeof(double_t)); +} + +size_t Preferences::putBool(const char* key, const bool value){ + return putUChar(key, (uint8_t) (value ? 1 : 0)); +} + +size_t Preferences::putString(const char* key, const char* value){ + if(!_started || !key || !value || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_str(_handle, key, value); + if(err){ + log_e("nvs_set_str fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return strlen(value); +} + +size_t Preferences::putString(const char* key, const String value){ + return putString(key, value.c_str()); +} + +size_t Preferences::putBytes(const char* key, const void* value, size_t len){ + if(!_started || !key || !value || !len || _readOnly){ + return 0; + } + esp_err_t err = nvs_set_blob(_handle, key, value, len); + if(err){ + log_e("nvs_set_blob fail: %s %s", key, nvs_error(err)); + return 0; + } + err = nvs_commit(_handle); + if(err){ + log_e("nvs_commit fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +PreferenceType Preferences::getType(const char* key) { + if(!_started || !key || strlen(key)>15){ + return PT_INVALID; + } + int8_t mt1; uint8_t mt2; int16_t mt3; uint16_t mt4; + int32_t mt5; uint32_t mt6; int64_t mt7; uint64_t mt8; + size_t len = 0; + if(nvs_get_i8(_handle, key, &mt1) == ESP_OK) return PT_I8; + if(nvs_get_u8(_handle, key, &mt2) == ESP_OK) return PT_U8; + if(nvs_get_i16(_handle, key, &mt3) == ESP_OK) return PT_I16; + if(nvs_get_u16(_handle, key, &mt4) == ESP_OK) return PT_U16; + if(nvs_get_i32(_handle, key, &mt5) == ESP_OK) return PT_I32; + if(nvs_get_u32(_handle, key, &mt6) == ESP_OK) return PT_U32; + if(nvs_get_i64(_handle, key, &mt7) == ESP_OK) return PT_I64; + if(nvs_get_u64(_handle, key, &mt8) == ESP_OK) return PT_U64; + if(nvs_get_str(_handle, key, NULL, &len) == ESP_OK) return PT_STR; + if(nvs_get_blob(_handle, key, NULL, &len) == ESP_OK) return PT_BLOB; + return PT_INVALID; +} + +bool Preferences::isKey(const char* key) { + return getType(key) != PT_INVALID; +} + +/* + * Get a key value + * */ + +int8_t Preferences::getChar(const char* key, const int8_t defaultValue){ + int8_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i8(_handle, key, &value); + if(err){ + log_v("nvs_get_i8 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint8_t Preferences::getUChar(const char* key, const uint8_t defaultValue){ + uint8_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u8(_handle, key, &value); + if(err){ + log_v("nvs_get_u8 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +int16_t Preferences::getShort(const char* key, const int16_t defaultValue){ + int16_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i16(_handle, key, &value); + if(err){ + log_v("nvs_get_i16 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint16_t Preferences::getUShort(const char* key, const uint16_t defaultValue){ + uint16_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u16(_handle, key, &value); + if(err){ + log_v("nvs_get_u16 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +int32_t Preferences::getInt(const char* key, const int32_t defaultValue){ + int32_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i32(_handle, key, &value); + if(err){ + log_v("nvs_get_i32 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint32_t Preferences::getUInt(const char* key, const uint32_t defaultValue){ + uint32_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u32(_handle, key, &value); + if(err){ + log_v("nvs_get_u32 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +int32_t Preferences::getLong(const char* key, const int32_t defaultValue){ + return getInt(key, defaultValue); +} + +uint32_t Preferences::getULong(const char* key, const uint32_t defaultValue){ + return getUInt(key, defaultValue); +} + +int64_t Preferences::getLong64(const char* key, const int64_t defaultValue){ + int64_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_i64(_handle, key, &value); + if(err){ + log_v("nvs_get_i64 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +uint64_t Preferences::getULong64(const char* key, const uint64_t defaultValue){ + uint64_t value = defaultValue; + if(!_started || !key){ + return value; + } + esp_err_t err = nvs_get_u64(_handle, key, &value); + if(err){ + log_v("nvs_get_u64 fail: %s %s", key, nvs_error(err)); + } + return value; +} + +float_t Preferences::getFloat(const char* key, const float_t defaultValue) { + float_t value = defaultValue; + getBytes(key, (void*) &value, sizeof(float_t)); + return value; +} + +double_t Preferences::getDouble(const char* key, const double_t defaultValue) { + double_t value = defaultValue; + getBytes(key, (void*) &value, sizeof(double_t)); + return value; +} + +bool Preferences::getBool(const char* key, const bool defaultValue) { + return getUChar(key, defaultValue ? 1 : 0) == 1; +} + +size_t Preferences::getString(const char* key, char* value, const size_t maxLen){ + size_t len = 0; + if(!_started || !key || !value || !maxLen){ + return 0; + } + esp_err_t err = nvs_get_str(_handle, key, NULL, &len); + if(err){ + log_e("nvs_get_str len fail: %s %s", key, nvs_error(err)); + return 0; + } + if(len > maxLen){ + log_e("not enough space in value: %u < %u", maxLen, len); + return 0; + } + err = nvs_get_str(_handle, key, value, &len); + if(err){ + log_e("nvs_get_str fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +String Preferences::getString(const char* key, const String defaultValue){ + char * value = NULL; + size_t len = 0; + if(!_started || !key){ + return String(defaultValue); + } + esp_err_t err = nvs_get_str(_handle, key, value, &len); + if(err){ + log_e("nvs_get_str len fail: %s %s", key, nvs_error(err)); + return String(defaultValue); + } + char buf[len]; + value = buf; + err = nvs_get_str(_handle, key, value, &len); + if(err){ + log_e("nvs_get_str fail: %s %s", key, nvs_error(err)); + return String(defaultValue); + } + return String(buf); +} + +size_t Preferences::getBytesLength(const char* key){ + size_t len = 0; + if(!_started || !key){ + return 0; + } + esp_err_t err = nvs_get_blob(_handle, key, NULL, &len); + if(err){ + log_e("nvs_get_blob len fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +size_t Preferences::getBytes(const char* key, void * buf, size_t maxLen){ + size_t len = getBytesLength(key); + if(!len || !buf || !maxLen){ + return len; + } + if(len > maxLen){ + log_e("not enough space in buffer: %u < %u", maxLen, len); + return 0; + } + esp_err_t err = nvs_get_blob(_handle, key, buf, &len); + if(err){ + log_e("nvs_get_blob fail: %s %s", key, nvs_error(err)); + return 0; + } + return len; +} + +size_t Preferences::freeEntries() { + nvs_stats_t nvs_stats; + esp_err_t err = nvs_get_stats(NULL, &nvs_stats); + if(err){ + log_e("Failed to get nvs statistics"); + return 0; + } + return nvs_stats.free_entries; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/src/Preferences.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/src/Preferences.h new file mode 100644 index 0000000..5dbcbd4 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/Preferences/src/Preferences.h @@ -0,0 +1,77 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _PREFERENCES_H_ +#define _PREFERENCES_H_ + +#include "Arduino.h" + +typedef enum { + PT_I8, PT_U8, PT_I16, PT_U16, PT_I32, PT_U32, PT_I64, PT_U64, PT_STR, PT_BLOB, PT_INVALID +} PreferenceType; + +class Preferences { + protected: + uint32_t _handle; + bool _started; + bool _readOnly; + public: + Preferences(); + ~Preferences(); + + bool begin(const char * name, bool readOnly=false, const char* partition_label=NULL); + void end(); + + bool clear(); + bool remove(const char * key); + + size_t putChar(const char* key, int8_t value); + size_t putUChar(const char* key, uint8_t value); + size_t putShort(const char* key, int16_t value); + size_t putUShort(const char* key, uint16_t value); + size_t putInt(const char* key, int32_t value); + size_t putUInt(const char* key, uint32_t value); + size_t putLong(const char* key, int32_t value); + size_t putULong(const char* key, uint32_t value); + size_t putLong64(const char* key, int64_t value); + size_t putULong64(const char* key, uint64_t value); + size_t putFloat(const char* key, float_t value); + size_t putDouble(const char* key, double_t value); + size_t putBool(const char* key, bool value); + size_t putString(const char* key, const char* value); + size_t putString(const char* key, String value); + size_t putBytes(const char* key, const void* value, size_t len); + + bool isKey(const char* key); + PreferenceType getType(const char* key); + int8_t getChar(const char* key, int8_t defaultValue = 0); + uint8_t getUChar(const char* key, uint8_t defaultValue = 0); + int16_t getShort(const char* key, int16_t defaultValue = 0); + uint16_t getUShort(const char* key, uint16_t defaultValue = 0); + int32_t getInt(const char* key, int32_t defaultValue = 0); + uint32_t getUInt(const char* key, uint32_t defaultValue = 0); + int32_t getLong(const char* key, int32_t defaultValue = 0); + uint32_t getULong(const char* key, uint32_t defaultValue = 0); + int64_t getLong64(const char* key, int64_t defaultValue = 0); + uint64_t getULong64(const char* key, uint64_t defaultValue = 0); + float_t getFloat(const char* key, float_t defaultValue = NAN); + double_t getDouble(const char* key, double_t defaultValue = NAN); + bool getBool(const char* key, bool defaultValue = false); + size_t getString(const char* key, char* value, size_t maxLen); + String getString(const char* key, String defaultValue = String()); + size_t getBytesLength(const char* key); + size_t getBytes(const char* key, void * buf, size_t maxLen); + size_t freeEntries(); +}; + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/README.md new file mode 100644 index 0000000..5edeebb --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/README.md @@ -0,0 +1,109 @@ +# ESP32 Libraries + +arduino-esp32 includes libraries for Arduino compatibility along with some object wrappers around hardware specific devices. Examples are included in the examples folder under each library folder. The ESP32 includes additional examples which need no special drivers. + +### ArduinoOTA + Over The Air firmware update daemon. Use espota.py to upload to the device. + +### AsyncUDP + Asynchronous task driven UDP datagram client/server + +### BLE + Bluetooth Low Energy v4.2 client/server framework + +### BluetoothSerial + Serial to Bluetooth redirection server\ + Note: This library depends on Bluetooth Classic which is only available for ESP32\ + (Bluetoothserial is **not available** for ESP32-S2, ESP32-C3, ESP32-S3). + +### DNSServer + A basic UDP DNS daemon (includes captive portal demo) + +### EEPROM + Arduino compatibility for EEPROM (using flash) + +### ESP32 + Additional examples + * AnalogOut + * Camera + * ChipID + * DeepSleep + * ESPNow + * FreeRTOS + * GPIO + * HallSensor + * I2S + * ResetReason + * RMT + * Time + * Timer + * Touch + +### ESPmDNS + mDNS service advertising + +### Ethernet + Ethernet networking + +### FFat + FAT indexed filesystem on SPI flash + +### FS + Filesystem virtualization framework + +### HTTPClient + A simple HTTP client, compatible with WiFiClientSecure + +### HTTPUpdate + Download a firmware update from HTTPd and apply it using Update + +### HTTPUpdateServer + Upload a firmware for the update from HTTPd + +### LittleFS + LittleFS (File System) + +### NetBIOS + NetBIOS name advertiser + +### Preferences + Flash keystore using ESP32 NVS + +### ESP RainMaker + End-to-end platform by Espressif that enables Makers to realize their IoT ideas faster + +### SD + Secure Digital card filesystem using SPI access + +### SD_MMC + Secure Digital card filesystem using 4-lane access + +### SimpleBLE + Minimal BLE advertiser + +### SPI + Arduino compatible Serial Peripheral Interface driver (master only) + +### SPIFFS + SPI Flash Filesystem (see [spiffs-plugin](https://github.com/me-no-dev/arduino-esp32fs-plugin) to upload to device) + +### Ticker + A timer to call functions on an interval + +### Update + Sketch Update using ESP32 OTA functionality + +### USB + Universal Serial Bus driver (device only) + +### WebServer + A simple HTTP daemon + +### WiFi + Arduino compatible WiFi driver (includes Ethernet driver) + +### WiFiClientSecure + Arduino compatible WiFi client object using embedded encryption + +### Wire + Arduino compatible I2C driver diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/README.md new file mode 100644 index 0000000..f12bef3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/README.md @@ -0,0 +1,483 @@ +# ESP RainMaker library for Arduino +This library allows to work with ESP RainMaker. + +ESP RainMaker is an end-to-end solution offered by Espressif to enable remote control and monitoring for ESP32-S2 and ESP32 based products without any configuration required in the Cloud. The primary components of this solution are: + +- Claiming Service (to get the Cloud connectivity credentials) +- RainMaker library (i.e. this library, to develop the firmware) +- RainMaker Cloud (backend, offering remote connectivity) +- RainMaker Phone App/CLI (Client utilities for remote access) + +The key features of ESP RainMaker are: + +1. Ability to define own devices and parameters, of any type, in the firmware. +2. Zero configuration required on the Cloud. +3. Phone apps that dynamically render the UI as per the device information. + +This ESP RainMaker library is built using esp-rainmaker component. + +#### Repository Source + +- [ESP RainMaker](https://github.com/espressif/esp-rainmaker) + +## Phone Apps + +#### Android + +- [Google PlayStore](https://play.google.com/store/apps/details?id=com.espressif.rainmaker) +- [Direct APK](https://github.com/espressif/esp-rainmaker/wiki) +- [Source Code](https://github.com/espressif/esp-rainmaker-android) + +#### iOS +- [Apple App Store](https://apps.apple.com/app/esp-rainmaker/id1497491540) +- [Source Code](https://github.com/espressif/esp-rainmaker-ios) + +## Documentation + +Additional information about ESP RainMaker can be found [here](https://rainmaker.espressif.com/) + +NOTE : ESP RainMaker library is currently supported for ESP32 board only. + +## ESP RainMaker Agent API + +### RMaker.initNode() +This initializes the ESP RainMaker agent, wifi and creates the node. +``` +Node initNode(const char *name, const char *type); +``` +* **Parameters** +1. `name`: Name of the node +2. `type`: Type of the node + +* **Return** +1. Object of Node. + +* You can also set the configuration of the node using the following API + 1. RMaker.setTimeSync(bool val) +> NOTE: If you want to set the configuration for the node then these configuration API must be called before `RMaker.initNode()`. + +### RMaker.start() +It starts the ESP RainMaker agent. +``` +esp_err_t start() +``` +* **Return** +1. ESP_OK : On success +2. Error in case of failure + +> NOTE : +> 1. ESP RainMaker agent should be initialized before this call. +> 2. Once ESP RainMaker agent starts, compulsorily call WiFi.beginProvision() API. + +### RMaker.stop() +It stops the ESP RainMaker agent which was started using `RMaker.start()`. +``` +esp_err_t stop() +``` +* **Return** +1. ESP_OK : On success +2. Error in case of failure + +### RMaker.deinitNode() +It deinitializes the ESP RainMaker agent and the node created using `RMaker.initNode()`. +``` +esp_err_t deinitNode(Node node) +``` +* **Parameter** +1. `node` : Node object created using `RMaker.initNode()` +* **Return** +1. ESP_OK : On success +2. Error in case of failure + +### RMaker.enableOTA() +It enables OTA as per the ESP RainMaker Specification. For more details refer ESP RainMaker documentation. check [here](https://rainmaker.espressif.com/docs/ota.html) +``` +esp_err_t enableOTA(ota_type_t type); +``` +* **Parameter** +1. `type` : The OTA workflow type. + - OTA_USING_PARAMS + - OTA_USING_TOPICS +* **Return** +1. ESP_OK : On success +2. Error in case of failure + +### RMaker.enableSchedule() +This API enables the scheduling service for the node. For more information, check [here](https://rainmaker.espressif.com/docs/scheduling.html). +``` +esp_err_t enableSchedule(); +``` +* **Return** +1. ESP_OK : On success +2. Error in case of failure + +### RMaker.setTimeZone() +This API set's the timezone as a user friendly location string. Check [here](https://rainmaker.espressif.com/docs/time-service.html) for a list of valid values. +``` +esp_err_t setTimeZone(const char *tz); +``` +* **Parameter** +1. `tz' : Valid values as specified in documentation. + +* **Return** +1. ESP_OK : On success +2. Error in case of failure +> NOTE : default value is "Asia/Shanghai". +> This API comes into picture only when working with scheduling. + +## ESP RainMaker NODE APIs +`Node` class expose API's for node. +> NOTE : my_node is the object of Node class. + +### my_node.getNodeID() +It returns the unique node_id assigned to the node. This node_id is usually the MAC address of the board. +``` +char * getNodeID() +``` +* **Return** +1. `char * ` : Pointer to a NULL terminated node_id string. + +### my_node.getNodeInfo() +It returns pointer to the node_info_t as configured during node initialisation. +``` +node_info_t * getNodeInfo(); +``` +* **Return** +1. `node_info_t` : Pointer to the structure node_info_t on success. +2. `NULL` : On failure. + +* **ESP RainMaker node info** +It has following data member +1. char * name +2. char * type +3. char * fw_version +4. char * model + +### my_node.addNodeAttr() +It adds a new attribute as the metadata to the node. +``` +esp_err_t addNodeAttr(const char *attr_name, const char *val); +``` +* **Parameters** +1. `attr_name` : Name of the attribute +2. `val` : Value of the attribute + +* **Return** +1. `ESP_OK` : On success +2. Error in case of failure + +> NOTE : Only string values are allowed. + +### my_node.addDevice() +It adds a device to the node. +``` +esp_err_t addDevice(Device device); +``` +* **Parameter** +1. `device` : Device object + +* **Return** +1. `ESP_OK` : On success +2. Error in case of failure + +> NOTE : +> - This is the mandatory API to register device to node. +> - Single Node can have multiple devices. +> - Device name should be unique for each device. + +### my_node.removeDevice() +It removes a device from the node. +``` +esp_err_t removeDevice(Device device); +``` +* **Parameter** +1. `device` : Device object + +* **Return** +1. `ESP_OK` : On success +2. Error in case of failure + +## ESP RainMaker DEVICE API's +`Device` class expose API's for virtual devices on the node. +Parameterized constructor is defined which creates the virtual device on the node. Using Device class object you can create your own device. +> NOTE : my_device is the object of Device class +``` +Device my_device(const char *dev_name, const char *dev_type, void *priv_data); +``` +* **Parameters** +1. `dev_name` : Unique device name +2. `dev_type` : Optional device type. It can be kept NULL. + * Standard Device Types + * ESP_RMAKER_DEVICE_SWITCH + * ESP_RMAKER_DEVICE_LIGHTBULB + * ESP_RMAKER_DEVICE_FAN + * ESP_RMAKER_DEVICE_TEMP_SENSOR +3. `priv_data` : Private data associated with the device. This will be passed to the callbacks. + +> NOTE : This created device should be added to the node using `my_node.addDevice(my_device)`. + +- Sample example +``` +Device my_device("Switch"); +Device my_device("Switch1", NULL, NULL); +``` +> Here, dev_name is compulsory, rest are optional. +> Node can have multiple device, each device should have unique device name. + +### Standard Device +- Classes are defined for the standard devices. +- Creating object of these class creates the standard device with default parameters to it. +- Class for standard devices + * Switch + * LightBulb + * TemperatureSensor + * Fan +``` +Switch my_switch(const char *dev_name, void *priv_data, bool power); +``` +* **Parameters** +1. `dev_name` : Unique device name by default it is "switch" for switch device. +2. `priv_data` : Private data associated with the device. This will be passed to the callbacks. +3. `power` : It is the value that can be set for primary parameter. + +- Sample example for standard device. +``` +Switch switch1; +Switch switch2("switch2", NULL, true); +``` +`"switch2"` : Name for standard device. + +`NULL` : Private data for the device, which will be used in callback. + +`true` : Default value for the primary param, in case of switch it is power. + +> NOTE : No parameter are compulsory for standard devices. However if you are creating two objects of same standard class then in that case you will have to set the device name, if not then both device will have same name which is set by default, hence device will not get create. Device name should be unique for each device. + +### my_device.getDeviceName() +It returns the name of the Device. +``` +const char * getDeviceName(); +``` +* **Return** +1. `char *`: Returns Device name. + +> NOTE : Each device on the node should have unique device name. + +### my_device.addDeviceAttr() +It adds attribute to the device. Device attributes are reported only once after a boot-up as part of the node configuration. Eg. Serial Number +``` +esp_err_t addDeviceAttr(const char *attr_name, const char *val); +``` +* **Parameters** +1. `attr_name` : Name of the attribute +2. `val` : Value of the attribute + +* **Return** +1. `ESP_OK` : On success +2. Error in case of failure + +### my_device.deleteDevice() +It deletes the device created using parameterized constructor. This device should be first removed from the node using `my_node.removeDevice(my_device)`. +``` +esp_err_t deleteDevice(); +``` +* **Return** +1. `ESP_OK` : On success +2. Error in case of failure + +### my_device.addXParam() +It adds standard parameter to the device. +> NOTE : X is the default name by which parameter is referred, you can specify your own name to each parameter. + +> Default + +> Eg. `my_device.addPowerParam(true)` here power parameter is referred with name Power. +> Eg. `my_device.addHueParam(12)` here hue parameter is referred with name Hue. + +> You can specify your own name to each parameter + +> Eg. `my_device.addNameParam("NickName")` here name parameter is referred with name NickName. +> Eg. `my_device.addPowerParam(true, "FanPower")` here power parameter is referred with name FanPower. + +``` +esp_err_t addNameParam(const char *param_name = ESP_RMAKER_DEF_NAME_PARAM); +esp_err_t addPowerParam(bool val, const char *param_name = ESP_RMAKER_DEF_POWER_NAME); +esp_err_t addBrightnessParam(int val, const char *param_name = ESP_RMAKER_DEF_BRIGHTNESS_NAME); +esp_err_t addHueParam(int val, const char *param_name = ESP_RMAKER_DEF_HUE_NAME); +esp_err_t addSaturationParam(int val, const char *param_name = ESP_RMAKER_DEF_SATURATION_NAME); +esp_err_t addIntensityParam(int val, const char *param_name = ESP_RMAKER_DEF_INTENSITY_NAME); +esp_err_t addCCTParam(int val, const char *param_name = ESP_RMAKER_DEF_CCT_NAME); +esp_err_t addDirectionParam(int val, const char *param_name = ESP_RMAKER_DEF_DIRECTION_NAME); +esp_err_t addSpeedParam(int val, const char *param_name = ESP_RMAKER_DEF_SPEED_NAME); +esp_err_t addTemperatureParam(float val, const char *param_name = ESP_RMAKER_DEF_TEMPERATURE_NAME); +``` +* **Standard Parameters** + +* These are the standard parameters. + * Name : ESP_RMAKER_DEF_NAME_PARAM + * Power : ESP_RMAKER_DEF_POWER_NAME + * Brightness : ESP_RMAKER_DEF_BRIGHTNESS_NAME + * Hue : ESP_RMAKER_DEF_HUE_NAME + * Saturation : ESP_RMAKER_DEF_SATURATION_NAME + * Intensity : ESP_RMAKER_DEF_INTENSITY_NAME + * CCT : ESP_RMAKER_DEF_CCT_NAME + * Direction : ESP_RMAKER_DEF_DIRECTION_NAME + * Speed : ESP_RMAKER_DEF_SPEED_NAME + * Temperature : ESP_RMAKER_DEF_TEMPERATURE_NAME +> NOTE : Care should be taken while accessing name of parameter. Above mentioned are the two ways using which default name of parameters can be accessed. Either LHS or RHS. + +### my_device.assignPrimaryParam() +It assigns a parameter (already added using addXParam() or addParam()) as a primary parameter, which can be used by clients (phone apps specifically) to give prominence to it. +``` +esp_err_t assignPrimaryParam(param_handle_t *param); +``` +* **Parameter** +1. `param` : Handle of the parameter. It is obtained using `my_device.getParamByName()`. +``` +param_handle_t * getParamByName(const char *param_name); +``` +> NOTE : +> `param_name` : It is the name of the parameter which was added using addXparam() or addParam(). + +### my_device.addParam() +It allows user to add custom parameter to the device created using `Param` class. +``` +esp_err_t addParam(Param parameter); +``` +* **Parameter** +1. `parameter` : Object of Param + +* **Return** +1. ESP_OK : On success +2. Error in case of failure +> NOTE : Param class exposes API's to create the custom parameter. + +### my_device.updateAndReportParam() +It updates the parameter assosicated with particular device on ESP RainMaker cloud. +``` +esp_err_t updateAndReportParam(const char *param_name, value); +``` +* **Parameters** +1. `param_name` : Name of the parameter +2. `value` : Value to be updated. It can be int, bool, char * , float. + +* **Return** +1. `ESP_OK` : On success +2. Error in case of failure + +### my_device.addCb() +It registers read and write callback for the device which will be invoked as per requests received from the cloud (or other paths as may be added in future). +``` +void addCb(deviceWriteCb write_cb, deviceReadCb read_cb); +``` +* **Parameters** +1. `write_cb` : Function with signature [ func_name(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx); ] +2. `read_cb` : Function with signature [ func_name(Device *device, Param *param, void *priv_data, read_ctx_t *ctx); ] + +* **param_val_t val** +Value can be accessed as below +1. `bool` : val.val.b +2. `integer` : val.val.i +3. `float` : val.val.f +4. `char *` : val.val.s + +## ESP RainMaker PARAM API's +`Param` class expose API's for creating custom parameters for the devices and report and update values associated with parameter to the ESP RainMaker cloud. Parameterized constructor is defined which creates custom parameter. +> NOTE : my_param is the object of Param class. + +``` +Param my_param(const char *param_name, const char *param_type, param_val_t val, uint8_t properties); +``` +* **Parameters** +1. `param_name` : Name of the parameter +2. `param_type` : Type of the parameter. It is optional can be kept NULL. +3. `val` : Define the default value for the parameter. It should be defined using `value(int ival)` , `value(bool bval)` , `value(float fval)` , `value(char *sval)`. +4. `properties` : Properties of the parameter, which will be a logical OR of flags. + * Flags + * PROP_FLAG_WRITE + * PROP_FLAG_READ + * PROP_FLAG_TIME_SERIES + * PROP_FLAG_PERSIST + +`Sample example : Param my_param("bright", NULL, value(30), PROP_FLAG_READ | PROP_FLAG_WRITE | PROP_FLAG_PERSIST);` +> NOTE : Parameter created using Param class should be added to the device using `my_device.addParam(my_param);` + +### my_param.addUIType() +Add a UI type to the parameter. This will be used by the Phone apps (or other clients) to render appropriate UI for the given parameter. Please refer the RainMaker documentation [here](https://rainmaker.espressif.com/docs/standard-types.html#ui-elements) for supported UI Types. +``` +esp_err_t addUIType(const char *ui_type); +``` +* **Paramter** +1. `ui_type` : String describing the UI Type. + * Standard UI Types + * ESP_RMAKER_UI_TOGGLE + * ESP_RMAKER_UI_SLIDER + * ESP_RMAKER_UI_DROPDOWN + * ESP_RMAKER_UI_TEXT + +* **Returns** +1. ESP_OK : On success. +2. Error in case of failure. + +### my_param.addBounds() +Add bounds for an integer/float parameter. This can be used to add bounds (min/max values) for a given integer/float parameter. Eg. brightness will have bounds as 0 and 100 if it is a percentage. +``` +esp_err_t addBounds(param_val_t min, param_val_t max, param_val_t step); +``` +* **Parameters** +1. `min` : Minimum value +2. `max` : Maximum value +3. `step` : step Minimum stepping + +* **Returns** +1. ESP_OK : On success. +2. Error in case of failure. + +`Sample example : my_param.addBounds(value(0), value(100), value(5));` + +### my_param.updateAndReport() +It updates the parameter and report it to ESP RainMaker cloud. This is called in callback. +``` +esp_err_t updateAndReport(param_val_t val); +``` +* **Parameters** +1. `val` : New value of the parameter + +* **Return** +1. ESP_OK : On success. +2. Error in case of failure. + +> NOTE : +> - This API should always be called inside device write callback, if you aimed at updating n reporting parameter values, changed via RainMaker Client (Phone App), to the ESP RainMaker cloud. +> - If not called then paramter values will not be updated to the ESP RainMaker cloud. + +### printQR() +This API displays QR code, which is used in provisioning. +``` +printQR(const char *serv_name, const char *pop, const char *transport); +``` +* **Parameters** +1. `name` : Service name used in provisioning API. +2. `pop` : Proof of posession used in provisioning API. +3. `transport` : + 1. `softap` : In case of provisioning using SOFTAP. + 2. `ble` : In case of provisioning using BLE. + +### RMakerFactoryReset() +Reset the device to factory defaults. + +``` +RMakerFactoryReset(2); +``` +* **Parameters** +1. `seconds` : Time in seconds after which the chip should reboot after doing a factory reset. + + +### RMakerWiFiReset() +Reset Wi-Fi credentials. +``` +RMakerWiFiReset(2); +``` + +* **Parameters** +1. `seconds` : Time in seconds after which the chip should reboot after doing a Wi-Fi reset. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/README.md new file mode 100644 index 0000000..0b97804 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/README.md @@ -0,0 +1,13 @@ +# ESP RainMaker Examples + +While building any examples for ESP RainMaker, take care of the following: + +1. Change partition scheme in Arduino IDE to RainMaker (Tools -> Partition Scheme -> RainMaker). +2. Once ESP RainMaker gets started, compulsorily call `WiFi.beginProvision()` which is responsible for user-node mapping. +3. Use the appropriate provisioning scheme as per the board. + - ESP32 Board: BLE Provisioning + - ESP32-C3 Board: BLE Provisioning + - ESP32-S3 Board: BLE Provisioning + - ESP32-S2 Board: SoftAP Provisioning +4. Set debug level to Info (Tools -> Core Debug Level -> Info). This is recommended debug level but not mandatory to run RainMaker. + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/README.md new file mode 100644 index 0000000..42c998d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/README.md @@ -0,0 +1,29 @@ +# ESP RainMaker Custom Device + +This example demonstrates how to build a custom device to be used with ESP RainMaker. + +## What to expect in this example? + +- This example sketch uses the on board Boot button and GPIO16 to demonstrate an ESP RainMaker AC dimmer device. +- After compiling and flashing the example, add your device using the [ESP RainMaker phone apps](https://rainmaker.espressif.com/docs/quick-links.html#phone-apps) by scanning the QR code. +- Toggling the state from the phone app will toggle the dimmer state (GPIO16). +- Pressing the Boot button will toggle the dimmer state (GPIO16) and the same will reflect on the phone app. +- You can also change the Level from the phone app and see it reflect on the device as a print message. + +### Output + +``` +[ 87][I][RMaker.cpp:13] event_handler(): RainMaker Initialised. +[ 94][I][WiFiProv.cpp:158] beginProvision(): Already Provisioned +[ 95][I][WiFiProv.cpp:162] beginProvision(): Attempting connect to AP: Viking007_2GEXT + +Received value = false for Dimmer - Power +Toggle State to true. +[ 22532][I][RMakerDevice.cpp:162] updateAndReportParam(): Device : Dimmer, Param Name : Power, Val : true + +Received value = 73 for Dimmer - Level +``` + +### Resetting the device +- Press and Hold the Boot button for more than 3 seconds and then release to reset Wi-Fi configuration. +- Press and Hold the Boot button for more than 10 seconds and then release to reset to factory defaults. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino new file mode 100644 index 0000000..0449203 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustom/RMakerCustom.ino @@ -0,0 +1,147 @@ +//This example demonstrates the ESP RainMaker with a custom device +#include "RMaker.h" +#include "WiFi.h" +#include "WiFiProv.h" + +#define DEFAULT_POWER_MODE true +#define DEFAULT_DIMMER_LEVEL 50 +const char *service_name = "PROV_1234"; +const char *pop = "abcd1234"; + +//GPIO for push button +#if CONFIG_IDF_TARGET_ESP32C3 +static int gpio_0 = 9; +static int gpio_dimmer = 7; +#else +//GPIO for virtual device +static int gpio_0 = 0; +static int gpio_dimmer = 16; +#endif + +bool dimmer_state = true; + +// The framework provides some standard device types like switch, lightbulb, fan, temperature sensor. +// But, you can also define custom devices using the 'Device' base class object, as shown here +static Device *my_device = NULL; + +void sysProvEvent(arduino_event_t *sys_event) +{ + switch (sys_event->event_id) { + case ARDUINO_EVENT_PROV_START: +#if CONFIG_IDF_TARGET_ESP32S2 + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop); + printQR(service_name, pop, "softap"); +#else + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop); + printQR(service_name, pop, "ble"); +#endif + break; + case ARDUINO_EVENT_PROV_INIT: + wifi_prov_mgr_disable_auto_stop(10000); + break; + case ARDUINO_EVENT_PROV_CRED_SUCCESS: + wifi_prov_mgr_stop_provisioning(); + break; + default:; + } +} + +void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx) +{ + const char *device_name = device->getDeviceName(); + const char *param_name = param->getParamName(); + + if (strcmp(param_name, "Power") == 0) { + Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name); + dimmer_state = val.val.b; + (dimmer_state == false) ? digitalWrite(gpio_dimmer, LOW) : digitalWrite(gpio_dimmer, HIGH); + param->updateAndReport(val); + } else if (strcmp(param_name, "Level") == 0) { + Serial.printf("\nReceived value = %d for %s - %s\n", val.val.i, device_name, param_name); + param->updateAndReport(val); + } +} + +void setup() +{ + Serial.begin(115200); + pinMode(gpio_0, INPUT); + pinMode(gpio_dimmer, OUTPUT); + digitalWrite(gpio_dimmer, DEFAULT_POWER_MODE); + + Node my_node; + my_node = RMaker.initNode("ESP RainMaker Node"); + my_device = new Device("Dimmer", "custom.device.dimmer", &gpio_dimmer); + if (!my_device) { + return; + } + //Create custom dimmer device + my_device->addNameParam(); + my_device->addPowerParam(DEFAULT_POWER_MODE); + my_device->assignPrimaryParam(my_device->getParamByName(ESP_RMAKER_DEF_POWER_NAME)); + + //Create and add a custom level parameter + Param level_param("Level", "custom.param.level", value(DEFAULT_DIMMER_LEVEL), PROP_FLAG_READ | PROP_FLAG_WRITE); + level_param.addBounds(value(0), value(100), value(1)); + level_param.addUIType(ESP_RMAKER_UI_SLIDER); + my_device->addParam(level_param); + + my_device->addCb(write_callback); + + //Add custom dimmer device to the node + my_node.addDevice(*my_device); + + //This is optional + RMaker.enableOTA(OTA_USING_TOPICS); + //If you want to enable scheduling, set time zone for your region using setTimeZone(). + //The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html + // RMaker.setTimeZone("Asia/Shanghai"); + // Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone + RMaker.enableTZService(); + + RMaker.enableSchedule(); + + RMaker.enableScenes(); + + RMaker.start(); + + WiFi.onEvent(sysProvEvent); +#if CONFIG_IDF_TARGET_ESP32S2 + WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); +#else + WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name); +#endif +} + +void loop() +{ + if (digitalRead(gpio_0) == LOW) { //Push button pressed + + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(gpio_0) == LOW) { + delay(50); + } + int endTime = millis(); + + if ((endTime - startTime) > 10000) { + // If key pressed for more than 10secs, reset all + Serial.printf("Reset to factory.\n"); + RMakerFactoryReset(2); + } else if ((endTime - startTime) > 3000) { + Serial.printf("Reset Wi-Fi.\n"); + // If key pressed for more than 3secs, but less than 10, reset Wi-Fi + RMakerWiFiReset(2); + } else { + // Toggle device state + dimmer_state = !dimmer_state; + Serial.printf("Toggle State to %s.\n", dimmer_state ? "true" : "false"); + if (my_device) { + my_device->updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, dimmer_state); + } + (dimmer_state == false) ? digitalWrite(gpio_dimmer, LOW) : digitalWrite(gpio_dimmer, HIGH); + } + } + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/README.md new file mode 100644 index 0000000..7b30b0a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/README.md @@ -0,0 +1,34 @@ +# ESP RainMaker Custom Device + +This example demonstrates how to build a custom device to be used with ESP RainMaker using Mode, Range and Toggle Parameters. + +## What to expect in this example? + +- This example sketch uses the on board Boot button and GPIOs 16, 17, 18, 19, 21, 22 to demonstrate an ESP RainMaker AirCooler device. +- After compiling and flashing the example, add your device using the [ESP RainMaker phone apps](https://rainmaker.espressif.com/docs/quick-links.html#phone-apps) by scanning the QR code. +- Toggling the power state from the phone app will toggle GPIO 16. +- Pressing the Boot button will toggle the power state (GPIO 16) and the same will reflect on the phone app. +- Toggling the swing state from the phone app will toggle GPIO 17. +- Changing the mode from the phone app will toggle the GPIOs 18 (auto), 19 (cool) and 21 (heat) +- Changing the Speed slider from the phone app will dimming GPIO 22 +- You can also change the Level from the phone app and see it reflect on the device as a print message. + +### Output + +``` +Received value = true for Air Cooler - Power +Received value = false for Air Cooler - Power +Received value = true for Air Cooler - Swing +Received value = false for Air Cooler - Swing +Received value = 0 for Air Cooler - Speed +Received value = 255 for Air Cooler - Speed +Received value = Auto for Air Cooler - Mode +Received value = Cool for Air Cooler - Mode +Received value = Heat for Air Cooler - Mode +Toggle power state to false. +Toggle power state to false. +``` + +### Resetting the device +- Press and Hold the Boot button for more than 3 seconds and then release to reset Wi-Fi configuration. +- Press and Hold the Boot button for more than 10 seconds and then release to reset to factory defaults. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino new file mode 100644 index 0000000..04c070c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerCustomAirCooler/RMakerCustomAirCooler.ino @@ -0,0 +1,213 @@ +//This example demonstrates the ESP RainMaker with a custom Air Cooler device +#include "RMaker.h" +#include "WiFi.h" +#include "WiFiProv.h" +#include "led_strip.h" + +#define DEFAULT_POWER_MODE true +#define DEFAULT_SWING false +#define DEFAULT_SPEED 0 +#define DEFAULT_MODE "Auto" + +const char *service_name = "PROV_1234"; +const char *pop = "abcd1234"; + +#if CONFIG_IDF_TARGET_ESP32C3 +//GPIO for push button +static int gpio_reset = 9; +//GPIO for virtual device +static int gpio_power = 7; +static int gpio_swing = 3; +static int gpio_mode_auto = 4; +static int gpio_mode_cool = 5; +static int gpio_mode_heat = 6; +static int gpio_speed = 10; + +#else +//GPIO for push button +static int gpio_reset = 0; +//GPIO for virtual device +static int gpio_power = 16; +static int gpio_swing = 17; +static int gpio_mode_auto = 18; +static int gpio_mode_cool = 19; +static int gpio_mode_heat = 21; +static int gpio_speed = 22; +#endif + +bool power_state = true; + +// The framework provides some standard device types like switch, lightbulb, fan, temperature sensor. +// But, you can also define custom devices using the 'Device' base class object, as shown here +static Device *my_device = NULL; + +void sysProvEvent(arduino_event_t *sys_event) +{ + switch (sys_event->event_id) { + case ARDUINO_EVENT_PROV_START: +#if CONFIG_IDF_TARGET_ESP32S2 + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop); + printQR(service_name, pop, "softap"); +#else + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop); + printQR(service_name, pop, "ble"); +#endif + break; + case ARDUINO_EVENT_PROV_INIT: + wifi_prov_mgr_disable_auto_stop(10000); + break; + case ARDUINO_EVENT_PROV_CRED_SUCCESS: + wifi_prov_mgr_stop_provisioning(); + break; + default:; + } +} + +void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx) +{ + const char *device_name = device->getDeviceName(); + const char *param_name = param->getParamName(); + + if (strcmp(param_name, "Power") == 0) { + Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name); + power_state = val.val.b; + (power_state == false) ? digitalWrite(gpio_power, LOW) : digitalWrite(gpio_power, HIGH); + param->updateAndReport(val); + } else if (strcmp(param_name, "Swing") == 0) { + Serial.printf("\nReceived value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name); + bool swing = val.val.b; + (swing == false) ? digitalWrite(gpio_swing, LOW) : digitalWrite(gpio_swing, HIGH); + param->updateAndReport(val); + } else if (strcmp(param_name, "Speed") == 0) { + Serial.printf("\nReceived value = %d for %s - %s\n", val.val.i, device_name, param_name); + int speed = val.val.i; + analogWrite(gpio_speed, speed); + param->updateAndReport(val); + } else if (strcmp(param_name, "Mode") == 0) { + const char *mode = val.val.s; + if (strcmp(mode, "Auto") == 0) { + digitalWrite(gpio_mode_auto, HIGH); + digitalWrite(gpio_mode_heat, LOW); + digitalWrite(gpio_mode_cool, LOW); + } else if (strcmp(mode, "Heat") == 0) { + digitalWrite(gpio_mode_auto, LOW); + digitalWrite(gpio_mode_heat, HIGH); + digitalWrite(gpio_mode_cool, LOW); + } else if (strcmp(mode, "Cool") == 0) { + digitalWrite(gpio_mode_auto, LOW); + digitalWrite(gpio_mode_heat, LOW); + digitalWrite(gpio_mode_cool, HIGH); + } + Serial.printf("\nReceived value = %s for %s - %s\n", val.val.s, device_name, param_name); + param->updateAndReport(val); + } +} + +void setup() +{ + Serial.begin(115200); + pinMode(gpio_reset, INPUT_PULLUP); + pinMode(gpio_power, OUTPUT); + digitalWrite(gpio_power, DEFAULT_POWER_MODE); + pinMode(gpio_swing, OUTPUT); + digitalWrite(gpio_swing, DEFAULT_SWING); + pinMode(gpio_mode_auto, OUTPUT); + if (strcmp(DEFAULT_MODE, "Auto") == 0) { + digitalWrite(gpio_mode_auto, HIGH); + } + pinMode(gpio_mode_cool, OUTPUT); + if (strcmp(DEFAULT_MODE, "Cool") == 0) { + digitalWrite(gpio_mode_auto, HIGH); + } + pinMode(gpio_mode_heat, OUTPUT); + if (strcmp(DEFAULT_MODE, "Heat") == 0) { + digitalWrite(gpio_mode_auto, HIGH); + } + pinMode(gpio_speed, OUTPUT); + analogWrite(gpio_speed, DEFAULT_SPEED); + + Node my_node; + my_node = RMaker.initNode("ESP RainMaker Node"); + my_device = new Device("Air Cooler", "my.device.air-cooler", NULL); + if (!my_device) { + return; + } + //Create custom air cooler device + my_device->addNameParam(); + my_device->addPowerParam(DEFAULT_POWER_MODE); + my_device->assignPrimaryParam(my_device->getParamByName(ESP_RMAKER_DEF_POWER_NAME)); + + Param swing("Swing", ESP_RMAKER_PARAM_TOGGLE, value(DEFAULT_SWING), PROP_FLAG_READ | PROP_FLAG_WRITE); + swing.addUIType(ESP_RMAKER_UI_TOGGLE); + my_device->addParam(swing); + + Param speed("Speed", ESP_RMAKER_PARAM_RANGE, value(DEFAULT_SPEED), PROP_FLAG_READ | PROP_FLAG_WRITE); + speed.addUIType(ESP_RMAKER_UI_SLIDER); + speed.addBounds(value(0), value(255), value(1)); + my_device->addParam(speed); + + static const char *modes[] = { "Auto", "Cool", "Heat" }; + Param mode_param("Mode", ESP_RMAKER_PARAM_MODE, value("Auto"), PROP_FLAG_READ | PROP_FLAG_WRITE); + mode_param.addValidStrList(modes, 3); + mode_param.addUIType(ESP_RMAKER_UI_DROPDOWN); + my_device->addParam(mode_param); + + my_device->addCb(write_callback); + + //Add custom Air Cooler device to the node + my_node.addDevice(*my_device); + + //This is optional + // RMaker.enableOTA(OTA_USING_TOPICS); + //If you want to enable scheduling, set time zone for your region using setTimeZone(). + //The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html + // RMaker.setTimeZone("Asia/Shanghai"); + //Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone + // RMaker.enableTZService(); + + RMaker.enableSchedule(); + + RMaker.enableScenes(); + + RMaker.start(); + + WiFi.onEvent(sysProvEvent); +#if CONFIG_IDF_TARGET_ESP32S2 + WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); +#else + WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name); +#endif +} + +void loop() +{ + if (digitalRead(gpio_reset) == LOW) { //Push button pressed + + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(gpio_reset) == LOW) { + delay(50); + } + int press_duration = millis() - startTime; + + if (press_duration > 10000) { + // If key pressed for more than 10secs, reset all + Serial.printf("Reset to factory.\n"); + RMakerFactoryReset(2); + } else if (press_duration > 3000) { + Serial.printf("Reset Wi-Fi.\n"); + // If key pressed for more than 3secs, but less than 10, reset Wi-Fi + RMakerWiFiReset(2); + } else { + // Toggle device state + power_state = !power_state; + Serial.printf("Toggle power state to %s.\n", power_state ? "true" : "false"); + if (my_device) { + my_device->updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, power_state); + } + (power_state == false) ? digitalWrite(gpio_power, LOW) : digitalWrite(gpio_power, HIGH); + } + } + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino new file mode 100644 index 0000000..1df84e6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSonoffDualR3/RMakerSonoffDualR3.ino @@ -0,0 +1,218 @@ +//This example demonstrates the ESP RainMaker with a standard Switch device. +#include "RMaker.h" +#include "WiFi.h" +#include "WiFiProv.h" + +#define DEFAULT_POWER_MODE false +const char *service_name = "PROV_SONOFF_DUALR3"; +const char *pop = "123456"; + +// GPIO for push button +static uint8_t gpio_reset = 0; +// GPIO for switch +static uint8_t gpio_switch1 = 32; +static uint8_t gpio_switch2 = 33; +// GPIO for virtual device +static uint8_t gpio_relay1 = 27; +static uint8_t gpio_relay2 = 14; +/* Variable for reading pin status*/ +bool switch_state_ch1 = true; +bool switch_state_ch2 = true; +// GPIO for link status LED +static uint8_t gpio_led = 13; + +struct LightSwitch { + const uint8_t pin; + bool pressed; +}; + +// Define the light switches for channel 1 and 2 +LightSwitch switch_ch1 = {gpio_switch1, false}; +LightSwitch switch_ch2 = {gpio_switch2, false}; + +//The framework provides some standard device types like switch, lightbulb, fan, temperature sensor. +static Switch *my_switch1 = NULL; +static Switch *my_switch2 = NULL; + +void sysProvEvent(arduino_event_t *sys_event) +{ + switch (sys_event->event_id) { + case ARDUINO_EVENT_PROV_START: +#if CONFIG_IDF_TARGET_ESP32 + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop); + printQR(service_name, pop, "ble"); +#else + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop); + printQR(service_name, pop, "softap"); +#endif + break; + case ARDUINO_EVENT_WIFI_STA_CONNECTED: + Serial.printf("\nConnected to Wi-Fi!\n"); + digitalWrite(gpio_led, true); + break; + case ARDUINO_EVENT_PROV_INIT: + wifi_prov_mgr_disable_auto_stop(10000); + break; + case ARDUINO_EVENT_PROV_CRED_SUCCESS: + wifi_prov_mgr_stop_provisioning(); + break; + default:; + } +} + + + +void write_callback(Device *device, Param *param, const param_val_t val, void *priv_data, write_ctx_t *ctx) +{ + const char *device_name = device->getDeviceName(); + const char *param_name = param->getParamName(); + + if (strcmp(device_name, "Switch_ch1") == 0) { + + Serial.printf("Lightbulb = %s\n", val.val.b ? "true" : "false"); + + if (strcmp(param_name, "Power") == 0) { + Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name); + switch_state_ch1 = val.val.b; + (switch_state_ch1 == false) ? digitalWrite(gpio_relay1, LOW) : digitalWrite(gpio_relay1, HIGH); + param->updateAndReport(val); + } + + } else if (strcmp(device_name, "Switch_ch2") == 0) { + + Serial.printf("Switch value = %s\n", val.val.b ? "true" : "false"); + + if (strcmp(param_name, "Power") == 0) { + Serial.printf("Received value = %s for %s - %s\n", val.val.b ? "true" : "false", device_name, param_name); + switch_state_ch2 = val.val.b; + (switch_state_ch2 == false) ? digitalWrite(gpio_relay2, LOW) : digitalWrite(gpio_relay2, HIGH); + param->updateAndReport(val); + } + + } + +} + +void ARDUINO_ISR_ATTR isr(void *arg) +{ + LightSwitch *s = static_cast(arg); + s->pressed = true; +} + +void setup() +{ + + uint32_t chipId = 0; + + Serial.begin(115200); + + // Configure the input GPIOs + pinMode(gpio_reset, INPUT); + pinMode(switch_ch1.pin, INPUT_PULLUP); + attachInterruptArg(switch_ch1.pin, isr, &switch_ch1, CHANGE); + pinMode(switch_ch2.pin, INPUT_PULLUP); + attachInterruptArg(switch_ch2.pin, isr, &switch_ch2, CHANGE); + + // Set the Relays GPIOs as output mode + pinMode(gpio_relay1, OUTPUT); + pinMode(gpio_relay2, OUTPUT); + pinMode(gpio_led, OUTPUT); + // Write to the GPIOs the default state on booting + digitalWrite(gpio_relay1, DEFAULT_POWER_MODE); + digitalWrite(gpio_relay2, DEFAULT_POWER_MODE); + digitalWrite(gpio_led, false); + + Node my_node; + my_node = RMaker.initNode("Sonoff Dual R3"); + + //Initialize switch device + my_switch1 = new Switch("Switch_ch1", &gpio_relay1); + my_switch2 = new Switch("Switch_ch2", &gpio_relay2); + + if (!my_switch1 || !my_switch2) { + return; + } + //Standard switch device + my_switch1->addCb(write_callback); + my_switch2->addCb(write_callback); + + //Add switch device to the node + my_node.addDevice(*my_switch1); + my_node.addDevice(*my_switch2); + + //This is optional + RMaker.enableOTA(OTA_USING_TOPICS); + //If you want to enable scheduling, set time zone for your region using setTimeZone(). + //The list of available values are provided here https://rainmaker.espressif.com/docs/time-service.html + // RMaker.setTimeZone("Asia/Shanghai"); + // Alternatively, enable the Timezone service and let the phone apps set the appropriate timezone + RMaker.enableTZService(); + RMaker.enableSchedule(); + RMaker.enableScenes(); + + //Service Name + for (int i = 0; i < 17; i = i + 8) { + chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; + } + + Serial.printf("\nChip ID: %lu Service Name: %s\n", chipId, service_name); + + Serial.printf("\nStarting ESP-RainMaker\n"); + RMaker.start(); + + WiFi.onEvent(sysProvEvent); +#if CONFIG_IDF_TARGET_ESP32 + WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name); +#else + WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name); +#endif +} + +void loop() +{ + + if (switch_ch1.pressed) { + Serial.printf("Switch 1 has been changed\n"); + switch_ch1.pressed = false; + // Toggle switch 1 device state + switch_state_ch1 = !switch_state_ch1; + Serial.printf("Toggle State to %s.\n", switch_state_ch1 ? "true" : "false"); + if (my_switch1) { + my_switch1->updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, switch_state_ch1); + } + (switch_state_ch1 == false) ? digitalWrite(gpio_relay1, LOW) : digitalWrite(gpio_relay1, HIGH); + } else if (switch_ch2.pressed) { + Serial.printf("Switch 2 has been changed\n"); + switch_ch2.pressed = false; + // Toggle switch 2 device state + switch_state_ch2 = !switch_state_ch2; + Serial.printf("Toggle State to %s.\n", switch_state_ch2 ? "true" : "false"); + if (my_switch2) { + my_switch2->updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, switch_state_ch2); + } + (switch_state_ch2 == false) ? digitalWrite(gpio_relay2, LOW) : digitalWrite(gpio_relay2, HIGH); + } + + // Read GPIO0 (external button to reset device + if (digitalRead(gpio_reset) == LOW) { //Push button pressed + Serial.printf("Reset Button Pressed!\n"); + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(gpio_reset) == LOW) { + delay(50); + } + int endTime = millis(); + + if ((endTime - startTime) > 10000) { + // If key pressed for more than 10secs, reset all + Serial.printf("Reset to factory.\n"); + RMakerFactoryReset(2); + } else if ((endTime - startTime) > 3000) { + Serial.printf("Reset Wi-Fi.\n"); + // If key pressed for more than 3secs, but less than 10, reset Wi-Fi + RMakerWiFiReset(2); + } + } + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/README.md new file mode 100644 index 0000000..55b5ab1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/README.md @@ -0,0 +1,31 @@ +# ESP RainMaker Switch + +This example demonstrates how to build a switch device to be used with ESP RainMaker. + +## What to expect in this example? + +- This example sketch uses the on board Boot button and GPIO16 to demonstrate an ESP RainMaker switch device. +- After compiling and flashing the example, add your device using the [ESP RainMaker phone apps](https://rainmaker.espressif.com/docs/quick-links.html#phone-apps) by scanning the QR code. +- Toggling the state from the phone app will toggle the switch state (GPIO16). +- Pressing the Boot button will toggle the switch state (GPIO16) and the same will reflect on the phone app. + +### Output + +``` +[ 63][I][RMaker.cpp:13] event_handler(): RainMaker Initialised. +[ 69][I][WiFiProv.cpp:158] beginProvision(): Already Provisioned +[ 69][I][WiFiProv.cpp:162] beginProvision(): Attempting connect to AP: Viking007_2GEXT + +Toggle State to false. +[ 8182][I][RMakerDevice.cpp:162] updateAndReportParam(): Device : Switch, Param Name : Power, Val : false +Toggle State to true. +[ 9835][I][RMakerDevice.cpp:162] updateAndReportParam(): Device : Switch, Param Name : Power, Val : true +Received value = false for Switch - Power +Received value = true for Switch - Power +Toggle State to false. +[ 29937][I][RMakerDevice.cpp:162] updateAndReportParam(): Device : Switch, Param Name : Power, Val : false +``` + +### Resetting the device +- Press and Hold the Boot button for more than 3 seconds and then release to reset Wi-Fi configuration. +- Press and Hold the Boot button for more than 10 seconds and then release to reset to factory defaults. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino new file mode 100644 index 0000000..688feed --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/examples/RMakerSwitch/RMakerSwitch.ino @@ -0,0 +1,153 @@ +// This example demonstrates the ESP RainMaker with a standard Switch device. +#include "RMaker.h" +#include "WiFi.h" +#include "WiFiProv.h" +#include "AppInsights.h" + +#define DEFAULT_POWER_MODE true +const char *service_name = "PROV_1234"; +const char *pop = "abcd1234"; + +// GPIO for push button +#if CONFIG_IDF_TARGET_ESP32C3 +static int gpio_0 = 9; +static int gpio_switch = 7; +#else +// GPIO for virtual device +static int gpio_0 = 0; +static int gpio_switch = 16; +#endif + +/* Variable for reading pin status*/ +bool switch_state = true; + +// The framework provides some standard device types like switch, lightbulb, +// fan, temperaturesensor. +static Switch *my_switch = NULL; + +void sysProvEvent(arduino_event_t *sys_event) +{ + switch (sys_event->event_id) { + case ARDUINO_EVENT_PROV_START: +#if CONFIG_IDF_TARGET_ESP32S2 + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", + service_name, pop); + printQR(service_name, pop, "softap"); +#else + Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", + service_name, pop); + printQR(service_name, pop, "ble"); +#endif + break; + case ARDUINO_EVENT_PROV_INIT: + wifi_prov_mgr_disable_auto_stop(10000); + break; + case ARDUINO_EVENT_PROV_CRED_SUCCESS: + wifi_prov_mgr_stop_provisioning(); + break; + default:; + } +} + +void write_callback(Device *device, Param *param, const param_val_t val, + void *priv_data, write_ctx_t *ctx) +{ + const char *device_name = device->getDeviceName(); + const char *param_name = param->getParamName(); + + if (strcmp(param_name, "Power") == 0) { + Serial.printf("Received value = %s for %s - %s\n", + val.val.b ? "true" : "false", device_name, param_name); + switch_state = val.val.b; + (switch_state == false) ? digitalWrite(gpio_switch, LOW) + : digitalWrite(gpio_switch, HIGH); + param->updateAndReport(val); + } +} + +void setup() +{ + Serial.begin(115200); + pinMode(gpio_0, INPUT); + pinMode(gpio_switch, OUTPUT); + digitalWrite(gpio_switch, DEFAULT_POWER_MODE); + + Node my_node; + my_node = RMaker.initNode("ESP RainMaker Node"); + + // Initialize switch device + my_switch = new Switch("Switch", &gpio_switch); + if (!my_switch) { + return; + } + // Standard switch device + my_switch->addCb(write_callback); + + // Add switch device to the node + my_node.addDevice(*my_switch); + + // This is optional + RMaker.enableOTA(OTA_USING_TOPICS); + // If you want to enable scheduling, set time zone for your region using + // setTimeZone(). The list of available values are provided here + // https://rainmaker.espressif.com/docs/time-service.html + // RMaker.setTimeZone("Asia/Shanghai"); + // Alternatively, enable the Timezone service and let the phone apps set the + // appropriate timezone + RMaker.enableTZService(); + + RMaker.enableSchedule(); + + RMaker.enableScenes(); + // Enable ESP Insights. Insteads of using the default http transport, this function will + // reuse the existing MQTT connection of Rainmaker, thereby saving memory space. + initAppInsights(); + + RMaker.enableSystemService(SYSTEM_SERV_FLAGS_ALL, 2, 2, 2); + + RMaker.start(); + + WiFi.onEvent(sysProvEvent); +#if CONFIG_IDF_TARGET_ESP32S2 + WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, + WIFI_PROV_SECURITY_1, pop, service_name); +#else + WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, + WIFI_PROV_SECURITY_1, pop, service_name); +#endif +} + +void loop() +{ + if (digitalRead(gpio_0) == LOW) { // Push button pressed + + // Key debounce handling + delay(100); + int startTime = millis(); + while (digitalRead(gpio_0) == LOW) { + delay(50); + } + int endTime = millis(); + + if ((endTime - startTime) > 10000) { + // If key pressed for more than 10secs, reset all + Serial.printf("Reset to factory.\n"); + RMakerFactoryReset(2); + } else if ((endTime - startTime) > 3000) { + Serial.printf("Reset Wi-Fi.\n"); + // If key pressed for more than 3secs, but less than 10, reset Wi-Fi + RMakerWiFiReset(2); + } else { + // Toggle device state + switch_state = !switch_state; + Serial.printf("Toggle State to %s.\n", switch_state ? "true" : "false"); + if (my_switch) { + my_switch->updateAndReportParam(ESP_RMAKER_DEF_POWER_NAME, + switch_state); + } + (switch_state == false) ? digitalWrite(gpio_switch, LOW) + : digitalWrite(gpio_switch, HIGH); + } + } + delay(100); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/library.properties new file mode 100644 index 0000000..b144328 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/library.properties @@ -0,0 +1,8 @@ +name=ESP RainMaker +version=2.0.0 +author=Sweety Mhaiske +maintainer=Hristo Gochkov +sentence=ESP RainMaker Support +paragraph=With this library you can build connected devices and access them via phone apps without having to manage the infrastructure. +url=https://rainmaker.espressif.com +architectures=esp32,esp32s2 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/AppInsights.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/AppInsights.cpp new file mode 100644 index 0000000..591f5e6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/AppInsights.cpp @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#if defined(CONFIG_ESP_INSIGHTS_ENABLED) && defined(CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK) +#include "Arduino.h" +#include "AppInsights.h" +#include "Insights.h" +#include +#include +#include +#include +#include + +extern "C" { + bool esp_rmaker_mqtt_is_budget_available(); +} + +#define INSIGHTS_TOPIC_SUFFIX "diagnostics/from-node" +#define INSIGHTS_TOPIC_RULE "insights_message_delivery" + +static void _rmakerCommonEventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) +{ + if (event_base != RMAKER_COMMON_EVENT) { + return; + } + esp_insights_transport_event_data_t data; + switch(event_id) { + case RMAKER_MQTT_EVENT_PUBLISHED: + memset(&data, 0, sizeof(data)); + data.msg_id = *(int *)event_data; + esp_event_post(INSIGHTS_EVENT, INSIGHTS_EVENT_TRANSPORT_SEND_SUCCESS, &data, sizeof(data), portMAX_DELAY); + break; + default: + break; + } +} + +static int _appInsightsDataSend(void *data, size_t len) +{ + char topic[128]; + int msg_id = -1; + if (data == NULL) { + return 0; + } + char *node_id = esp_rmaker_get_node_id(); + if (!node_id) { + return -1; + } + if (esp_rmaker_mqtt_is_budget_available() == false) { + return ESP_FAIL; + } + esp_rmaker_create_mqtt_topic(topic, sizeof(topic), INSIGHTS_TOPIC_SUFFIX, INSIGHTS_TOPIC_RULE); + esp_rmaker_mqtt_publish(topic, data, len, RMAKER_MQTT_QOS1, &msg_id); + return msg_id; +} + +bool initAppInsights(uint32_t log_type, bool alloc_ext_ram) +{ + char *node_id = esp_rmaker_get_node_id(); + esp_insights_transport_config_t transport; + transport.userdata = NULL; + transport.callbacks.data_send = _appInsightsDataSend; + transport.callbacks.init = NULL; + transport.callbacks.deinit = NULL; + transport.callbacks.connect = NULL; + transport.callbacks.disconnect = NULL; + esp_insights_transport_register(&transport); + esp_event_handler_register(RMAKER_COMMON_EVENT, ESP_EVENT_ANY_ID, _rmakerCommonEventHandler, NULL); + return Insights.begin(NULL, node_id, log_type, alloc_ext_ram, false); +} +#else +bool initAppInsights(uint32_t log_type, bool alloc_ext_ram) +{ + return false; +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/AppInsights.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/AppInsights.h new file mode 100644 index 0000000..ddb32f1 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/AppInsights.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include "sdkconfig.h" +#include "Arduino.h" +#include + +bool initAppInsights(uint32_t log_type = 0xffffffff, bool alloc_ext_ram = false); diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMaker.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMaker.cpp new file mode 100644 index 0000000..dab002c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMaker.cpp @@ -0,0 +1,173 @@ +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMaker.h" +#include +#include +#include +bool wifiLowLevelInit(bool persistent); +static esp_err_t err; + +extern "C" bool verifyRollbackLater() { return true; } + +static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + if (event_base == RMAKER_EVENT) { + switch (event_id) { + case RMAKER_EVENT_INIT_DONE: + log_i("RainMaker Initialised."); + break; + case RMAKER_EVENT_CLAIM_STARTED: + log_i("RainMaker Claim Started."); + break; + case RMAKER_EVENT_CLAIM_SUCCESSFUL: + log_i("RainMaker Claim Successful."); + break; + case RMAKER_EVENT_CLAIM_FAILED: + log_i("RainMaker Claim Failed."); + break; + default: + log_i("Unhandled RainMaker Event:"); + } + } else if (event_base == RMAKER_OTA_EVENT) { + if (event_data == NULL) { + event_data = (void*)""; + } + switch(event_id) { + case RMAKER_OTA_EVENT_STARTING: + log_i("Starting OTA"); + break; + case RMAKER_OTA_EVENT_IN_PROGRESS: + log_i("OTA in progress : %s", (char*)event_data); + break; + case RMAKER_OTA_EVENT_SUCCESSFUL: + log_i("OTA Successful : %s", (char*)event_data); + break; + case RMAKER_OTA_EVENT_FAILED: + log_i("OTA Failed : %s", (char*)event_data); + break; + case RMAKER_OTA_EVENT_DELAYED: + log_i("OTA Delayed : %s", (char*)event_data); + break; + case RMAKER_OTA_EVENT_REJECTED: + log_i("OTA Rejected : %s", (char*)event_data); + break; + default: + log_i("Unhandled OTA Event"); + break; + } + } +} + +void RMakerClass::setTimeSync(bool val) +{ + rainmaker_cfg.enable_time_sync = val; +} + +Node RMakerClass::initNode(const char *name, const char *type) +{ + wifiLowLevelInit(true); + Node node; + esp_rmaker_node_t *rnode = NULL; + esp_event_handler_register(RMAKER_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL); + esp_event_handler_register(RMAKER_OTA_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL); + rnode = esp_rmaker_node_init(&rainmaker_cfg, name, type); + if (!rnode){ + log_e("Node init failed"); + return node; + } + node.setNodeHandle(rnode); + return node; +} + +esp_err_t RMakerClass::start() +{ + err = esp_rmaker_start(); + if(err != ESP_OK){ + log_e("ESP RainMaker core task failed"); + } + return err; +} + +esp_err_t RMakerClass::stop() +{ + err = esp_rmaker_stop(); + if(err != ESP_OK) { + log_e("ESP RainMaker stop error"); + } + return err; +} + +esp_err_t RMakerClass::deinitNode(Node rnode) +{ + err = esp_rmaker_node_deinit(rnode.getNodeHandle()); + if(err != ESP_OK) { + log_e("Node deinit failed"); + } + return err; +} + +esp_err_t RMakerClass::setTimeZone(const char *tz) +{ + err = esp_rmaker_time_set_timezone(tz); + if(err != ESP_OK) { + log_e("Setting time zone error"); + } + return err; +} + +esp_err_t RMakerClass::enableSchedule() +{ + err = esp_rmaker_schedule_enable(); + if(err != ESP_OK) { + log_e("Schedule enable failed"); + } + return err; +} + +esp_err_t RMakerClass::enableTZService() +{ + err = esp_rmaker_timezone_service_enable(); + if(err != ESP_OK) { + log_e("Timezone service enable failed"); + } + return err; +} + +esp_err_t RMakerClass::enableOTA(ota_type_t type, const char *cert) +{ + esp_rmaker_ota_config_t ota_config = { + .ota_cb = NULL, + .ota_diag = NULL, + .server_cert = cert, + .priv = NULL + }; + err = esp_rmaker_ota_enable(&ota_config, type); + if(err != ESP_OK) { + log_e("OTA enable failed"); + } + return err; +} + +esp_err_t RMakerClass::enableScenes() +{ + err = esp_rmaker_scenes_enable(); + if (err != ESP_OK) { + log_e("Scenes enable failed"); + } + return err; +} + +esp_err_t RMakerClass::enableSystemService(uint16_t flags, int8_t reboot_seconds, int8_t reset_seconds, int8_t reset_reboot_seconds) +{ + esp_rmaker_system_serv_config_t config = { + .flags = flags, + .reboot_seconds = reboot_seconds, + .reset_seconds = reset_seconds, + .reset_reboot_seconds = reset_reboot_seconds + }; + err = esp_rmaker_system_service_enable(&config); + return err; +} + +RMakerClass RMaker; +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMaker.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMaker.h new file mode 100644 index 0000000..0d6420c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMaker.h @@ -0,0 +1,45 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "esp_system.h" +#include "Arduino.h" +#include "RMakerNode.h" +#include "RMakerQR.h" +#include "RMakerUtils.h" +#include + +class RMakerClass +{ + private: + esp_rmaker_config_t rainmaker_cfg = {false}; + + public: + + void setTimeSync(bool val); + Node initNode(const char *name, const char *type = "ESP RainMaker with Arduino"); + esp_err_t deinitNode(Node node); + esp_err_t setTimeZone(const char *tz = "Asia/Shanghai"); + esp_err_t enableSchedule(); + esp_err_t enableTZService(); + esp_err_t enableOTA(ota_type_t type, const char *cert = ESP_RMAKER_OTA_DEFAULT_SERVER_CERT); + esp_err_t enableScenes(); + esp_err_t enableSystemService(uint16_t flags, int8_t reboot_seconds = 2, int8_t reset_seconds = 2, int8_t reset_reboot_seconds = 2); + esp_err_t start(); + esp_err_t stop(); +}; + +extern RMakerClass RMaker; +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerDevice.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerDevice.cpp new file mode 100644 index 0000000..c042e0d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerDevice.cpp @@ -0,0 +1,213 @@ +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMakerDevice.h" + +static esp_err_t err; +typedef void (*deviceWriteCb)(Device*, Param*, const param_val_t val, void *priv_data, write_ctx_t *ctx); +typedef void (*deviceReadCb)(Device*, Param*, void *priv_data, read_ctx_t *ctx); +typedef struct { + void *priv_data; + deviceWriteCb write_cb; + deviceReadCb read_cb; +} RMakerDevicePrivT; + +static esp_err_t write_callback(const device_handle_t *dev_handle, const param_handle_t *par_handle, const param_val_t val, void *priv_data, write_ctx_t *ctx) +{ + Device device; + Param param; + device.setDeviceHandle(dev_handle); + param.setParamHandle(par_handle); + deviceWriteCb cb = ((RMakerDevicePrivT *)priv_data)->write_cb; + cb(&device, ¶m, val, ((RMakerDevicePrivT *)priv_data)->priv_data, ctx); + return ESP_OK; +} + +static esp_err_t read_callback(const device_handle_t *dev_handle, const param_handle_t *par_handle, void *priv_data, read_ctx_t *ctx) +{ + Device device; + Param param; + device.setDeviceHandle(dev_handle); + param.setParamHandle(par_handle); + deviceReadCb cb = ((RMakerDevicePrivT *)priv_data)->read_cb; + cb(&device, ¶m, ((RMakerDevicePrivT *)priv_data)->priv_data, ctx); + return ESP_OK; +} + +esp_err_t Device::deleteDevice() +{ + err = esp_rmaker_device_delete(getDeviceHandle()); + if(err != ESP_OK) { + log_e("Failed to delete device"); + return err; + } + return ESP_OK; +} + +void Device::addCb(deviceWriteCb writeCb, deviceReadCb readCb) +{ + this->private_data.write_cb = writeCb; + this->private_data.read_cb = readCb; + err = esp_rmaker_device_add_cb(getDeviceHandle(), write_callback, read_callback); + if(err != ESP_OK) { + log_e("Failed to register callback"); + } +} + +esp_err_t Device::addDeviceAttr(const char *attr_name, const char *val) +{ + err = esp_rmaker_device_add_attribute(getDeviceHandle(), attr_name, val); + if(err != ESP_OK) { + log_e("Failed to add attriute to the device"); + return err; + } + return ESP_OK; +} + +//Generic Parameter +esp_err_t Device::addParam(Param parameter) +{ + err = esp_rmaker_device_add_param(getDeviceHandle(), parameter.getParamHandle()); + if(err != ESP_OK) { + log_e("Failed to add custom parameter"); + return err; + } + return ESP_OK; +} + +//Standard Device Parameter +esp_err_t Device::addNameParam(const char *param_name) +{ + param_handle_t *param = esp_rmaker_name_param_create(param_name, getDeviceName()); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addPowerParam(bool val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_power_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addBrightnessParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_brightness_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addHueParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_hue_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addSaturationParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_saturation_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addIntensityParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_intensity_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addCCTParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_cct_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addDirectionParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_direction_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addSpeedParam(int val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_speed_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +esp_err_t Device::addTemperatureParam(float val, const char *param_name) +{ + param_handle_t *param = esp_rmaker_temperature_param_create(param_name, val); + return esp_rmaker_device_add_param(getDeviceHandle(), param); +} + +param_handle_t *Device::getParamByName(const char *param_name) +{ + return esp_rmaker_device_get_param_by_name(getDeviceHandle(), param_name); +} + +esp_err_t Device::assignPrimaryParam(param_handle_t *param) +{ + err = esp_rmaker_device_assign_primary_param(getDeviceHandle(), param); + if(err != ESP_OK){ + log_e("Failed to assign primary parameter"); + } + return err; +} + +const param_handle_t* getParamHandlebyName(const esp_rmaker_device_t *device_handle, const char *param_name) +{ + const param_handle_t *param = esp_rmaker_device_get_param_by_name(device_handle, param_name); + return param; +} + +esp_err_t Device::updateAndReportParam(const char *param_name, bool my_val) +{ + const param_handle_t *param = getParamHandlebyName(getDeviceHandle(), param_name); + param_val_t val = esp_rmaker_bool(my_val); + err = esp_rmaker_param_update_and_report(param, val); + if(err != ESP_OK) { + log_e("Update parameter failed"); + return err; + }else { + log_i("Device : %s, Param Name : %s, Val : %s", getDeviceName(), param_name, my_val ? "true" : "false"); + } + return ESP_OK; +} + +esp_err_t Device::updateAndReportParam(const char *param_name, int my_val) +{ + const param_handle_t *param = getParamHandlebyName(getDeviceHandle(), param_name); + param_val_t val = esp_rmaker_int(my_val); + esp_err_t err = esp_rmaker_param_update_and_report(param, val); + if(err != ESP_OK) { + log_e("Update parameter failed"); + return err; + }else { + log_i("Device : %s, Param Name : %s, Val : %d", getDeviceName(), param_name, my_val); + } + return ESP_OK; +} + +esp_err_t Device::updateAndReportParam(const char *param_name, float my_val) +{ + const param_handle_t *param = getParamHandlebyName(getDeviceHandle(), param_name); + param_val_t val = esp_rmaker_float(my_val); + esp_err_t err = esp_rmaker_param_update_and_report(param, val); + if(err != ESP_OK) { + log_e("Update parameter failed"); + return err; + }else { + log_i("Device : %s, Param Name : %s, Val : %f", getDeviceName(), param_name, my_val); + } + return ESP_OK; +} + +esp_err_t Device::updateAndReportParam(const char *param_name, const char *my_val) +{ + const param_handle_t *param = getParamHandlebyName(getDeviceHandle(), param_name); + param_val_t val = esp_rmaker_str(my_val); + esp_err_t err = esp_rmaker_param_update_and_report(param, val); + if(err != ESP_OK) { + log_e("Update parameter failed"); + return err; + }else { + log_i("Device : %s, Param Name : %s, Val : %s", getDeviceName(), param_name, my_val); + } + return ESP_OK; +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerDevice.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerDevice.h new file mode 100644 index 0000000..cba498c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerDevice.h @@ -0,0 +1,192 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "esp_system.h" +#include "RMakerParam.h" +#include +#include + +class Device +{ + public: + typedef void (*deviceWriteCb)(Device*, Param*, const param_val_t val, void *priv_data, write_ctx_t *ctx); + typedef void (*deviceReadCb)(Device*, Param*, void *priv_data, read_ctx_t *ctx); + typedef struct { + void *priv_data; + deviceWriteCb write_cb; + deviceReadCb read_cb; + } RMakerDevicePrivT; + private: + const device_handle_t *device_handle; + RMakerDevicePrivT private_data; + + protected: + void setPrivateData(void *priv_data) { + this->private_data.priv_data = priv_data; + } + + const RMakerDevicePrivT* getDevicePrivateData() + { + return &this->private_data; + } + public: + Device() + { + device_handle = NULL; + this->private_data.priv_data = NULL; + this->private_data.write_cb = NULL; + this->private_data.read_cb = NULL; + } + + Device(const char *dev_name, const char *dev_type = NULL, void *priv_data = NULL) + { + this->private_data.priv_data = priv_data; + this->private_data.write_cb = NULL; + this->private_data.read_cb = NULL; + device_handle = esp_rmaker_device_create(dev_name, dev_type, &this->private_data); + if(device_handle == NULL){ + log_e("Device create error"); + } + } + void setDeviceHandle(const esp_rmaker_device_t *device_handle) + { + this->device_handle = device_handle; + } + const char *getDeviceName() + { + return esp_rmaker_device_get_name(device_handle); + } + const esp_rmaker_device_t *getDeviceHandle() + { + return device_handle; + } + + esp_err_t deleteDevice(); + void addCb(deviceWriteCb write_cb, deviceReadCb read_cb = NULL); + esp_err_t addDeviceAttr(const char *attr_name, const char *val); + param_handle_t *getParamByName(const char *param_name); + esp_err_t assignPrimaryParam(param_handle_t *param); + + //Generic Device Parameter + esp_err_t addParam(Param parameter); + + //Standard Device Parameter + esp_err_t addNameParam(const char *param_name = ESP_RMAKER_DEF_NAME_PARAM); + esp_err_t addPowerParam(bool val, const char *param_name = ESP_RMAKER_DEF_POWER_NAME); + esp_err_t addBrightnessParam(int val, const char *param_name = ESP_RMAKER_DEF_BRIGHTNESS_NAME); + esp_err_t addHueParam(int val, const char *param_name = ESP_RMAKER_DEF_HUE_NAME); + esp_err_t addSaturationParam(int val, const char *param_name = ESP_RMAKER_DEF_SATURATION_NAME); + esp_err_t addIntensityParam(int val, const char *param_name = ESP_RMAKER_DEF_INTENSITY_NAME); + esp_err_t addCCTParam(int val, const char *param_name = ESP_RMAKER_DEF_CCT_NAME); + esp_err_t addDirectionParam(int val, const char *param_name = ESP_RMAKER_DEF_DIRECTION_NAME); + esp_err_t addSpeedParam(int val, const char *param_name = ESP_RMAKER_DEF_SPEED_NAME); + esp_err_t addTemperatureParam(float val, const char *param_name = ESP_RMAKER_DEF_TEMPERATURE_NAME); + + //Update Parameter + esp_err_t updateAndReportParam(const char *param_name, bool val); + esp_err_t updateAndReportParam(const char *param_name, int val); + esp_err_t updateAndReportParam(const char *param_name, float val); + esp_err_t updateAndReportParam(const char *param_name, const char *val); + +}; + +class Switch : public Device +{ + public: + Switch() + { + standardSwitchDevice("Switch", NULL, true); + } + Switch(const char *dev_name, void *priv_data = NULL, bool power = true) + { + standardSwitchDevice(dev_name, priv_data, power); + } + void standardSwitchDevice(const char *dev_name, void *priv_data, bool power) + { + this->setPrivateData(priv_data); + esp_rmaker_device_t *dev_handle = esp_rmaker_switch_device_create(dev_name, (void *)this->getDevicePrivateData(), power); + setDeviceHandle(dev_handle); + if(dev_handle == NULL){ + log_e("Switch device not created"); + } + } +}; + +class LightBulb : public Device +{ + public: + LightBulb() + { + standardLightBulbDevice("Light", NULL, true); + } + LightBulb(const char *dev_name, void *priv_data = NULL, bool power = true) + { + standardLightBulbDevice(dev_name, priv_data, power); + } + void standardLightBulbDevice(const char *dev_name, void *priv_data, bool power) + { + this->setPrivateData(priv_data); + esp_rmaker_device_t *dev_handle = esp_rmaker_lightbulb_device_create(dev_name, (void *)this->getDevicePrivateData(), power); + setDeviceHandle(dev_handle); + if(dev_handle == NULL){ + log_e("Light device not created"); + } + } +}; + +class Fan : public Device +{ + public: + Fan() + { + standardFanDevice("Fan", NULL, true); + } + Fan(const char *dev_name, void *priv_data = NULL, bool power = true) + { + standardFanDevice(dev_name, priv_data, power); + } + void standardFanDevice(const char *dev_name, void *priv_data, bool power) + { + esp_rmaker_device_t *dev_handle = esp_rmaker_fan_device_create(dev_name, priv_data, power); + setDeviceHandle(dev_handle); + if(dev_handle == NULL){ + log_e("Fan device not created"); + } + } +}; + +class TemperatureSensor : public Device +{ + public: + TemperatureSensor() + { + standardTemperatureSensorDevice("Temperature-Sensor", NULL, 25.0); + } + TemperatureSensor(const char *dev_name, void *priv_data = NULL, float temp = 25.0) + { + standardTemperatureSensorDevice(dev_name, priv_data, temp); + } + void standardTemperatureSensorDevice(const char *dev_name, void *priv_data, float temp) + { + this->setPrivateData(priv_data); + esp_rmaker_device_t *dev_handle = esp_rmaker_temp_sensor_device_create(dev_name, (void *)this->getDevicePrivateData(), temp); + setDeviceHandle(dev_handle); + if(dev_handle == NULL){ + log_e("Temperature Sensor device not created"); + } + } +}; +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerNode.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerNode.cpp new file mode 100644 index 0000000..5cae9e8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerNode.cpp @@ -0,0 +1,42 @@ +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMakerNode.h" +static esp_err_t err; + +esp_err_t Node::addDevice(Device device) +{ + err = esp_rmaker_node_add_device(node, device.getDeviceHandle()); + if(err != ESP_OK){ + log_e("Device was not added to the Node"); + } + return err; +} + +esp_err_t Node::removeDevice(Device device) +{ + err = esp_rmaker_node_remove_device(node, device.getDeviceHandle()); + if(err != ESP_OK){ + log_e("Device was not removed from the Node"); + } + return err; +} + +char *Node::getNodeID() +{ + return esp_rmaker_get_node_id(); +} + +node_info_t *Node::getNodeInfo() +{ + return esp_rmaker_node_get_info(node); +} + +esp_err_t Node::addNodeAttr(const char *attr_name, const char *val) +{ + err = esp_rmaker_node_add_attribute(node, attr_name, val); + if(err != ESP_OK) { + log_e("Failed to add attribute to the Node"); + } + return err; +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerNode.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerNode.h new file mode 100644 index 0000000..d169870 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerNode.h @@ -0,0 +1,46 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "esp_system.h" +#include "RMakerDevice.h" + +class Node +{ + private: + esp_rmaker_node_t *node; + + public: + Node() + { + node = NULL; + } + void setNodeHandle(esp_rmaker_node_t *rnode) + { + node = rnode; + } + esp_rmaker_node_t *getNodeHandle() + { + return node; + } + + esp_err_t addDevice(Device device); + esp_err_t removeDevice(Device device); + + char *getNodeID(); + node_info_t *getNodeInfo(); + esp_err_t addNodeAttr(const char *attr_name, const char *val); +}; +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerParam.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerParam.cpp new file mode 100644 index 0000000..f5f132f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerParam.cpp @@ -0,0 +1,41 @@ +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMakerParam.h" + +static esp_err_t err; + +esp_err_t Param::addUIType(const char *ui_type) +{ + err = esp_rmaker_param_add_ui_type(param_handle, ui_type); + if(err != ESP_OK) { + log_e("Add UI type error"); + } + return err; +} + +esp_err_t Param::addBounds(param_val_t min, param_val_t max, param_val_t step) +{ + err = esp_rmaker_param_add_bounds(param_handle, min, max, step); + if(err != ESP_OK) { + log_e("Add Bounds error"); + } + return err; +} + +esp_err_t Param::updateAndReport(param_val_t val) +{ + err = esp_rmaker_param_update_and_report(getParamHandle(), val); + if(err != ESP_OK){ + log_e("Update and Report param failed"); + } + return err; +} + +esp_err_t Param::addValidStrList(const char **string_list, uint8_t count) { + esp_err_t err = esp_rmaker_param_add_valid_str_list(getParamHandle(), string_list, count); + if (err != ESP_OK) { + log_e("Add valid string list error"); + } + return err; +} +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerParam.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerParam.h new file mode 100644 index 0000000..64785d9 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerParam.h @@ -0,0 +1,52 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "esp_system.h" +#include "RMakerType.h" + +class Param +{ + private: + const param_handle_t *param_handle; + + public: + Param() + { + param_handle = NULL; + } + Param(const char *param_name, const char *param_type, param_val_t val, uint8_t properties) + { + param_handle = esp_rmaker_param_create(param_name, param_type, val, properties); + } + void setParamHandle(const param_handle_t *param_handle) + { + this->param_handle = param_handle; + } + const char *getParamName() + { + return esp_rmaker_param_get_name(param_handle); + } + const param_handle_t *getParamHandle() + { + return param_handle; + } + + esp_err_t addUIType(const char *ui_type); + esp_err_t addBounds(param_val_t min, param_val_t max, param_val_t step); + esp_err_t updateAndReport(param_val_t val); + esp_err_t addValidStrList(const char **string_list, uint8_t count); +}; +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerQR.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerQR.cpp new file mode 100644 index 0000000..7f94f70 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerQR.cpp @@ -0,0 +1,21 @@ +#include "RMakerQR.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +void printQR(const char *name, const char *pop, const char *transport) +{ + if (!name || !pop || !transport) { + log_w("Cannot generate QR code payload. Data missing."); + return; + } + char payload[150]; + snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \ + ",\"pop\":\"%s\",\"transport\":\"%s\"}", + PROV_QR_VERSION, name, pop, transport); + if(Serial){ + Serial.printf("Scan this QR code from the ESP RainMaker phone app.\n"); + } + qrcode_display(payload); + if(Serial){ + Serial.printf("If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s\n", QRCODE_BASE_URL, payload); + } +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerQR.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerQR.h new file mode 100644 index 0000000..cb282a2 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerQR.h @@ -0,0 +1,25 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMaker.h" +#include "esp_system.h" +#include + +#define PROV_QR_VERSION "v1" +#define QRCODE_BASE_URL "https://rainmaker.espressif.com/qrcode.html" + +void printQR(const char *name, const char *pop, const char *transport); +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerType.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerType.cpp new file mode 100644 index 0000000..536e90d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerType.cpp @@ -0,0 +1,29 @@ +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMakerType.h" + +param_val_t value(int ival) +{ + return esp_rmaker_int(ival); +} + +param_val_t value(bool bval) +{ + return esp_rmaker_bool(bval); +} + +param_val_t value(char *sval) +{ + return esp_rmaker_str(sval); +} + +param_val_t value(float fval) +{ + return esp_rmaker_float(fval); +} + +param_val_t value(const char* sval) +{ + return esp_rmaker_str(sval); +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerType.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerType.h new file mode 100644 index 0000000..aa100b8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerType.h @@ -0,0 +1,37 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "esp_system.h" +#include +#include +#include +#include + +typedef esp_rmaker_node_t* node_t; +typedef esp_rmaker_node_info_t node_info_t; +typedef esp_rmaker_param_val_t param_val_t; +typedef esp_rmaker_write_ctx_t write_ctx_t; +typedef esp_rmaker_read_ctx_t read_ctx_t; +typedef esp_rmaker_device_t device_handle_t; +typedef esp_rmaker_param_t param_handle_t; +typedef esp_rmaker_ota_type_t ota_type_t; + +param_val_t value(int); +param_val_t value(bool); +param_val_t value(char *); +param_val_t value(float); +param_val_t value(const char*); +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerUtils.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerUtils.cpp new file mode 100644 index 0000000..b8af218 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerUtils.cpp @@ -0,0 +1,13 @@ +#include "RMakerUtils.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#define RESET_DELAY_SEC 2 +void RMakerFactoryReset(int reboot_seconds) +{ + esp_rmaker_factory_reset(RESET_DELAY_SEC, reboot_seconds); +} + +void RMakerWiFiReset(int reboot_seconds) +{ + esp_rmaker_wifi_reset(RESET_DELAY_SEC, reboot_seconds); +} +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerUtils.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerUtils.h new file mode 100644 index 0000000..17b7533 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/RainMaker/src/RMakerUtils.h @@ -0,0 +1,23 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once +#include "sdkconfig.h" +#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK +#include "RMaker.h" +#include "esp_system.h" +#include + +void RMakerFactoryReset(int seconds); +void RMakerWiFiReset(int seconds); +#endif \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/README.md new file mode 100644 index 0000000..136703c --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/README.md @@ -0,0 +1,47 @@ +# SD library + +This library provides the integration of ESP32 and SD (Secure Digital) and MMC (Multi Media Card) cards without additional modules. This library is using SPI to interface with the cards. Please note that SPI mode is slower than the intended SD or MMC mode, however, provides more flexibility as the SPI module is available on all ESP SoCs and can be routed to any GPIO through GPIO matrix. + +## Sample wiring diagram: + +![Connections](http://i.imgur.com/4CoXOuR.png) + +For other SD formats: + +![Other SD card formats](https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/MMC-SD-miniSD-microSD-Color-Numbers-Names.gif/330px-MMC-SD-miniSD-microSD-Color-Numbers-Names.gif) + +Image source: [Wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/MMC-SD-miniSD-microSD-Color-Numbers-Names.gif/330px-MMC-SD-miniSD-microSD-Color-Numbers-Names.gif) + +> **Warning** +Some ESP32 modules have different pin outs! + +## Default SPI pins: +Note that SPI pins can be configured by using `SPI.begin(sck, miso, mosi, cs);` alternatively, you can change only the CS pin with `SD.begin(CSpin)` + +| SPI Pin Name | ESP8266 | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | +|--------------|---------|-------|----------|----------|----------| +| CS (SS) | GPIO15 | GPIO5 | GPIO5 | GPIO13 | GPIO13 | +| DI (MOSI) | GPIO13 | GPIO23| GPIO24 | GPIO14 | GPIO14 | +| DO (MISO) | GPIO12 | GPIO19| GPIO25 | GPIO15 | GPIO15 | +| SCK (SCLK) | GPIO14 | GPIO18| GPIO19 | GPIO16 | GPIO16 | + +## FAQ: + +**Do I need any additional modules**, like **the **Arduino**** SD module**?** + +No, just wire your SD card directly to ESP32. + +Tip: If you are using a microSD card and have a spare adapter to full-sized SD, you can solder Dupont pins on the adapter. + + +**What is the difference between SD and SD_MMC libraries?** + +SD runs on SPI, and SD_MMC uses the SDMMC hardware bus on the ESP32. +The SPI uses 4 communication pins + 2 power connections and operates on up to 80MHz. The SPI option offers flexibility on pin connection because the data connections can be routed through GPIO matrix to any data pin. +SD-SPI speed is approximately half of the SD-MMC even when used on 1-bit line. +You can read more about SD SPI in the [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdspi_host.html) + +SD_MMC is supported only by ESP32 and ESP32-S3 and can be connected only to dedicated pins. SD_MMC allows to use of 1, 4 or 8 data pins + 2 additional communication pins and 2 power pins. The data pins need to be pulled up externally. +You can read more about SD_MMC in the [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdmmc_host.html) +1-bit: SD_MMC_ speed is approximately two-times faster than SPI mode +4-bit: SD_MMC speed is approximately three-times faster than SPI mode. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_Test/SD_Test.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_Test/SD_Test.ino new file mode 100644 index 0000000..2028f91 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_Test/SD_Test.ino @@ -0,0 +1,262 @@ +/* + * pin 1 - not used | Micro SD card | + * pin 2 - CS (SS) | / + * pin 3 - DI (MOSI) | |__ + * pin 4 - VDD (3.3V) | | + * pin 5 - SCK (SCLK) | 8 7 6 5 4 3 2 1 / + * pin 6 - VSS (GND) | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄ / + * pin 7 - DO (MISO) | ▀ ▀ █ ▀ █ ▀ ▀ ▀ | + * pin 8 - not used |_________________| + * ║ ║ ║ ║ ║ ║ ║ ║ + * ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗ + * ║ ║ ║ ║ ║ ║ ╚══════╗ ║ + * ║ ╔═════╝ ║ ║ ║ ╚═════╗ ║ ║ + * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║ + * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║ + * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║ + * Pin name | - DO VSS SCK VDD VSS DI CS - | + * SD pin number | 8 7 6 5 4 3 2 1 9 / + * | █/ + * |__▍___▊___█___█___█___█___█___█___/ + * + * Note: The SPI pins can be manually configured by using `SPI.begin(sck, miso, mosi, cs).` + * Alternatively, you can change the CS pin and use the other default settings by using `SD.begin(cs)`. + * + * +--------------+---------+-------+----------+----------+----------+ + * | SPI Pin Name | ESP8266 | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | + * +==============+=========+=======+==========+==========+==========+ + * | CS (SS) | GPIO15 | GPIO5 | GPIO5 | GPIO13 | GPIO13 | + * +--------------+---------+-------+----------+----------+----------+ + * | DI (MOSI) | GPIO13 | GPIO23| GPIO24 | GPIO14 | GPIO14 | + * +--------------+---------+-------+----------+----------+----------+ + * | DO (MISO) | GPIO12 | GPIO19| GPIO25 | GPIO15 | GPIO15 | + * +--------------+---------+-------+----------+----------+----------+ + * | SCK (SCLK) | GPIO14 | GPIO18| GPIO19 | GPIO16 | GPIO16 | + * +--------------+---------+-------+----------+----------+----------+ + * + * For more info see file README.md in this library or on URL: + * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD + */ + +#include "FS.h" +#include "SD.h" +#include "SPI.h" + +/* +Uncomment and set up if you want to use custom pins for the SPI communication +#define REASSIGN_PINS +int sck = -1; +int miso = -1; +int mosi = -1; +int cs = -1; +*/ + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + File file = fs.open(path); + static uint8_t buf[512]; + size_t len = 0; + uint32_t start = millis(); + uint32_t end = start; + if(file){ + len = file.size(); + size_t flen = len; + start = millis(); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + len -= toRead; + } + end = millis() - start; + Serial.printf("%u bytes read for %lu ms\n", flen, end); + file.close(); + } else { + Serial.println("Failed to open file for reading"); + } + + + file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + + size_t i; + start = millis(); + for(i=0; i<2048; i++){ + file.write(buf, 512); + } + end = millis() - start; + Serial.printf("%u bytes written for %lu ms\n", 2048 * 512, end); + file.close(); +} + +void setup(){ + Serial.begin(115200); + while(!Serial) { delay (10); } + +#ifdef REASSIGN_PINS + SPI.begin(sck, miso, mosi, cs); +#endif + //if(!SD.begin(cs)){ //Change to this function to manually change CS pin + if(!SD.begin()){ + Serial.println("Card Mount Failed"); + return; + } + uint8_t cardType = SD.cardType(); + + if(cardType == CARD_NONE){ + Serial.println("No SD card attached"); + return; + } + + Serial.print("SD Card Type: "); + if(cardType == CARD_MMC){ + Serial.println("MMC"); + } else if(cardType == CARD_SD){ + Serial.println("SDSC"); + } else if(cardType == CARD_SDHC){ + Serial.println("SDHC"); + } else { + Serial.println("UNKNOWN"); + } + + uint64_t cardSize = SD.cardSize() / (1024 * 1024); + Serial.printf("SD Card Size: %lluMB\n", cardSize); + + listDir(SD, "/", 0); + createDir(SD, "/mydir"); + listDir(SD, "/", 0); + removeDir(SD, "/mydir"); + listDir(SD, "/", 2); + writeFile(SD, "/hello.txt", "Hello "); + appendFile(SD, "/hello.txt", "World!\n"); + readFile(SD, "/hello.txt"); + deleteFile(SD, "/foo.txt"); + renameFile(SD, "/hello.txt", "/foo.txt"); + readFile(SD, "/foo.txt"); + testFileIO(SD, "/test.txt"); + Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024)); + Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024)); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_time/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_time/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_time/SD_time.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_time/SD_time.ino new file mode 100644 index 0000000..e161bf0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/examples/SD_time/SD_time.ino @@ -0,0 +1,251 @@ +/* + * pin 1 - not used | Micro SD card | + * pin 2 - CS (SS) | / + * pin 3 - DI (MOSI) | |__ + * pin 4 - VDD (3.3V) | | + * pin 5 - SCK (SCLK) | 8 7 6 5 4 3 2 1 / + * pin 6 - VSS (GND) | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄ / + * pin 7 - DO (MISO) | ▀ ▀ █ ▀ █ ▀ ▀ ▀ | + * pin 8 - not used |_________________| + * ║ ║ ║ ║ ║ ║ ║ ║ + * ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗ + * ║ ║ ║ ║ ║ ║ ╚══════╗ ║ + * ║ ╔═════╝ ║ ║ ║ ╚═════╗ ║ ║ + * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║ + * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║ + * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║ + * Pin name | - DO VSS SCK VDD VSS DI CS - | + * SD pin number | 8 7 6 5 4 3 2 1 9 / + * | █/ + * |__▍___▊___█___█___█___█___█___█___/ + * + * Note: The SPI pins can be manually configured by using `SPI.begin(sck, miso, mosi, cs);`. + * Alternatively you can change only the CS pin with `SD.begin(CSpin)` and keep the default settings for other pins. + * + * +--------------+---------+-------+----------+----------+----------+ + * | SPI Pin Name | ESP8266 | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | + * +==============+=========+=======+==========+==========+==========+ + * | CS (SS) | GPIO15 | GPIO5 | GPIO5 | GPIO13 | GPIO13 | + * +--------------+---------+-------+----------+----------+----------+ + * | DI (MOSI) | GPIO13 | GPIO23| GPIO24 | GPIO14 | GPIO14 | + * +--------------+---------+-------+----------+----------+----------+ + * | DO (MISO) | GPIO12 | GPIO19| GPIO25 | GPIO15 | GPIO15 | + * +--------------+---------+-------+----------+----------+----------+ + * | SCK (SCLK) | GPIO14 | GPIO18| GPIO19 | GPIO16 | GPIO16 | + * +--------------+---------+-------+----------+----------+----------+ + * + * For more info see file README.md in this library or on URL: + * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD + */ + +#include "FS.h" +#include "SD.h" +#include "SPI.h" +#include +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +long timezone = 1; +byte daysavetime = 1; + +/* +Uncomment and setup pins you want to use for the SPI communication +#define REASSIGN_PINS +int sck = -1; +int miso = -1; +int mosi = -1; +int cs = -1; +*/ + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.print (file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup(){ + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + +#ifdef REASSIGN_PINS + SPI.begin(sck, miso, mosi, cs); +#endif + //if(!SD.begin(cs)){ //Change to this function to manually change CS pin + if(!SD.begin()){ + Serial.println("Card Mount Failed"); + return; + } + uint8_t cardType = SD.cardType(); + + if(cardType == CARD_NONE){ + Serial.println("No SD card attached"); + return; + } + + Serial.print("SD Card Type: "); + if(cardType == CARD_MMC){ + Serial.println("MMC"); + } else if(cardType == CARD_SD){ + Serial.println("SDSC"); + } else if(cardType == CARD_SDHC){ + Serial.println("SDHC"); + } else { + Serial.println("UNKNOWN"); + } + + uint64_t cardSize = SD.cardSize() / (1024 * 1024); + Serial.printf("SD Card Size: %lluMB\n", cardSize); + + listDir(SD, "/", 0); + removeDir(SD, "/mydir"); + createDir(SD, "/mydir"); + deleteFile(SD, "/hello.txt"); + writeFile(SD, "/hello.txt", "Hello "); + appendFile(SD, "/hello.txt", "World!\n"); + listDir(SD, "/", 0); +} + +void loop(){ + +} + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/library.properties new file mode 100644 index 0000000..449d0b0 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/library.properties @@ -0,0 +1,9 @@ +name=SD +version=2.0.0 +author=Arduino, SparkFun +maintainer=Arduino +sentence=Enables reading and writing on SD cards. For all Arduino boards. +paragraph=Once an SD memory card is connected to the SPI interfare of the Arduino board you are enabled to create files and read/write on them. You can also move through directories on the SD card. +category=Data Storage +url=http://www.arduino.cc/en/Reference/SD +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/SD.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/SD.cpp new file mode 100644 index 0000000..75f9e23 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/SD.cpp @@ -0,0 +1,135 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "vfs_api.h" +#include "sd_diskio.h" +#include "ff.h" +#include "FS.h" +#include "SD.h" + +using namespace fs; + +SDFS::SDFS(FSImplPtr impl): FS(impl), _pdrv(0xFF) {} + +bool SDFS::begin(uint8_t ssPin, SPIClass &spi, uint32_t frequency, const char * mountpoint, uint8_t max_files, bool format_if_empty) +{ + if(_pdrv != 0xFF) { + return true; + } + + spi.begin(); + + _pdrv = sdcard_init(ssPin, &spi, frequency); + if(_pdrv == 0xFF) { + return false; + } + + if(!sdcard_mount(_pdrv, mountpoint, max_files, format_if_empty)){ + sdcard_unmount(_pdrv); + sdcard_uninit(_pdrv); + _pdrv = 0xFF; + return false; + } + + _impl->mountpoint(mountpoint); + return true; +} + +void SDFS::end() +{ + if(_pdrv != 0xFF) { + _impl->mountpoint(NULL); + sdcard_unmount(_pdrv); + + sdcard_uninit(_pdrv); + _pdrv = 0xFF; + } +} + +sdcard_type_t SDFS::cardType() +{ + if(_pdrv == 0xFF) { + return CARD_NONE; + } + return sdcard_type(_pdrv); +} + +uint64_t SDFS::cardSize() +{ + if(_pdrv == 0xFF) { + return 0; + } + size_t sectors = sdcard_num_sectors(_pdrv); + size_t sectorSize = sdcard_sector_size(_pdrv); + return (uint64_t)sectors * sectorSize; +} + +size_t SDFS::numSectors() +{ + if(_pdrv == 0xFF) { + return 0; + } + return sdcard_num_sectors(_pdrv); +} + +size_t SDFS::sectorSize() +{ + if(_pdrv == 0xFF) { + return 0; + } + return sdcard_sector_size(_pdrv); +} + +uint64_t SDFS::totalBytes() +{ + FATFS* fsinfo; + DWORD fre_clust; + char drv[3] = {(char)(48+_pdrv), ':', 0}; + if(f_getfree(drv,&fre_clust,&fsinfo)!= 0) return 0; + uint64_t size = ((uint64_t)(fsinfo->csize))*(fsinfo->n_fatent - 2) +#if _MAX_SS != 512 + *(fsinfo->ssize); +#else + *512; +#endif + return size; +} + +uint64_t SDFS::usedBytes() +{ + FATFS* fsinfo; + DWORD fre_clust; + char drv[3] = {(char)(48+_pdrv), ':', 0}; + if(f_getfree(drv,&fre_clust,&fsinfo)!= 0) return 0; + uint64_t size = ((uint64_t)(fsinfo->csize))*((fsinfo->n_fatent - 2) - (fsinfo->free_clst)) +#if _MAX_SS != 512 + *(fsinfo->ssize); +#else + *512; +#endif + return size; +} + +bool SDFS::readRAW(uint8_t* buffer, uint32_t sector) +{ + return sd_read_raw(_pdrv, buffer, sector); +} + +bool SDFS::writeRAW(uint8_t* buffer, uint32_t sector) +{ + return sd_write_raw(_pdrv, buffer, sector); +} + + +SDFS SD = SDFS(FSImplPtr(new VFSImpl())); diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/SD.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/SD.h new file mode 100644 index 0000000..a554857 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/SD.h @@ -0,0 +1,52 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SD_H_ +#define _SD_H_ + +#include "FS.h" +#include "SPI.h" +#include "sd_defines.h" + +namespace fs +{ + +class SDFS : public FS +{ +protected: + uint8_t _pdrv; + +public: + SDFS(FSImplPtr impl); + bool begin(uint8_t ssPin=SS, SPIClass &spi=SPI, uint32_t frequency=4000000, const char * mountpoint="/sd", uint8_t max_files=5, bool format_if_empty=false); + void end(); + sdcard_type_t cardType(); + uint64_t cardSize(); + size_t numSectors(); + size_t sectorSize(); + uint64_t totalBytes(); + uint64_t usedBytes(); + bool readRAW(uint8_t* buffer, uint32_t sector); + bool writeRAW(uint8_t* buffer, uint32_t sector); +}; + +} + +extern fs::SDFS SD; + +using namespace fs; +typedef fs::File SDFile; +typedef fs::SDFS SDFileSystemClass; +#define SDFileSystem SD + +#endif /* _SD_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_defines.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_defines.h new file mode 100644 index 0000000..6e42855 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_defines.h @@ -0,0 +1,25 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SD_DEFINES_H_ +#define _SD_DEFINES_H_ + +typedef enum { + CARD_NONE, + CARD_MMC, + CARD_SD, + CARD_SDHC, + CARD_UNKNOWN +} sdcard_type_t; + +#endif /* _SD_DISKIO_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio.cpp new file mode 100644 index 0000000..d1aabea --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio.cpp @@ -0,0 +1,861 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "sd_diskio.h" +#include "esp_system.h" +extern "C" { + #include "ff.h" + #include "diskio.h" +#if ESP_IDF_VERSION_MAJOR > 3 + #include "diskio_impl.h" +#endif + //#include "esp_vfs.h" + #include "esp_vfs_fat.h" + char CRC7(const char* data, int length); + unsigned short CRC16(const char* data, int length); +} + +typedef enum { + GO_IDLE_STATE = 0, + SEND_OP_COND = 1, + SEND_CID = 2, + SEND_RELATIVE_ADDR = 3, + SEND_SWITCH_FUNC = 6, + SEND_IF_COND = 8, + SEND_CSD = 9, + STOP_TRANSMISSION = 12, + SEND_STATUS = 13, + SET_BLOCKLEN = 16, + READ_BLOCK_SINGLE = 17, + READ_BLOCK_MULTIPLE = 18, + SEND_NUM_WR_BLOCKS = 22, + SET_WR_BLK_ERASE_COUNT = 23, + WRITE_BLOCK_SINGLE = 24, + WRITE_BLOCK_MULTIPLE = 25, + APP_OP_COND = 41, + APP_CLR_CARD_DETECT = 42, + APP_CMD = 55, + READ_OCR = 58, + CRC_ON_OFF = 59 +} ardu_sdcard_command_t; + +typedef struct { + uint8_t ssPin; + SPIClass * spi; + int frequency; + char * base_path; + sdcard_type_t type; + unsigned long sectors; + bool supports_crc; + int status; +} ardu_sdcard_t; + +static ardu_sdcard_t* s_cards[FF_VOLUMES] = { NULL }; + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR +const char * fferr2str[] = { + "(0) Succeeded", + "(1) A hard error occurred in the low level disk I/O layer", + "(2) Assertion failed", + "(3) The physical drive cannot work", + "(4) Could not find the file", + "(5) Could not find the path", + "(6) The path name format is invalid", + "(7) Access denied due to prohibited access or directory full", + "(8) Access denied due to prohibited access", + "(9) The file/directory object is invalid", + "(10) The physical drive is write protected", + "(11) The logical drive number is invalid", + "(12) The volume has no work area", + "(13) There is no valid FAT volume", + "(14) The f_mkfs() aborted due to any problem", + "(15) Could not get a grant to access the volume within defined period", + "(16) The operation is rejected according to the file sharing policy", + "(17) LFN working buffer could not be allocated", + "(18) Number of open files > FF_FS_LOCK", + "(19) Given parameter is invalid" +}; +#endif + +/* + * SD SPI + * */ + +bool sdWait(uint8_t pdrv, int timeout) +{ + char resp; + uint32_t start = millis(); + + do { + resp = s_cards[pdrv]->spi->transfer(0xFF); + } while (resp == 0x00 && (millis() - start) < (unsigned int)timeout); + + if (!resp) { + log_w("Wait Failed"); + } + return (resp > 0x00); +} + +void sdStop(uint8_t pdrv) +{ + s_cards[pdrv]->spi->write(0xFD); +} + +void sdDeselectCard(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + digitalWrite(card->ssPin, HIGH); +} + +bool sdSelectCard(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + digitalWrite(card->ssPin, LOW); + bool s = sdWait(pdrv, 500); + if (!s) { + log_e("Select Failed"); + digitalWrite(card->ssPin, HIGH); + return false; + } + return true; +} + +char sdCommand(uint8_t pdrv, char cmd, unsigned int arg, unsigned int* resp) +{ + char token; + ardu_sdcard_t * card = s_cards[pdrv]; + + for (int f = 0; f < 3; f++) { + if (cmd == SEND_NUM_WR_BLOCKS || cmd == SET_WR_BLK_ERASE_COUNT || cmd == APP_OP_COND || cmd == APP_CLR_CARD_DETECT) { + token = sdCommand(pdrv, APP_CMD, 0, NULL); + sdDeselectCard(pdrv); + if (token > 1) { + break; + } + if(!sdSelectCard(pdrv)) { + token = 0xFF; + break; + } + } + + char cmdPacket[7]; + cmdPacket[0] = cmd | 0x40; + cmdPacket[1] = arg >> 24; + cmdPacket[2] = arg >> 16; + cmdPacket[3] = arg >> 8; + cmdPacket[4] = arg; + if(card->supports_crc || cmd == GO_IDLE_STATE || cmd == SEND_IF_COND) { + cmdPacket[5] = (CRC7(cmdPacket, 5) << 1) | 0x01; + } else { + cmdPacket[5] = 0x01; + } + cmdPacket[6] = 0xFF; + + card->spi->writeBytes((uint8_t*)cmdPacket, (cmd == STOP_TRANSMISSION)?7:6); + + for (int i = 0; i < 9; i++) { + token = card->spi->transfer(0xFF); + if (!(token & 0x80)) { + break; + } + } + + if (token == 0xFF) { + log_w("no token received"); + sdDeselectCard(pdrv); + delay(100); + sdSelectCard(pdrv); + continue; + } else if (token & 0x08) { + log_w("crc error"); + sdDeselectCard(pdrv); + delay(100); + sdSelectCard(pdrv); + continue; + } else if (token > 1) { + log_w("token error [%u] 0x%x", cmd, token); + break; + } + + if (cmd == SEND_STATUS && resp) { + *resp = card->spi->transfer(0xFF); + } else if ((cmd == SEND_IF_COND || cmd == READ_OCR) && resp) { + *resp = card->spi->transfer32(0xFFFFFFFF); + } + + break; + } + if (token == 0xFF) { + log_e("Card Failed! cmd: 0x%02x", cmd); + card->status = STA_NOINIT; + } + return token; +} + +bool sdReadBytes(uint8_t pdrv, char* buffer, int length) +{ + char token; + unsigned short crc; + ardu_sdcard_t * card = s_cards[pdrv]; + + uint32_t start = millis(); + do { + token = card->spi->transfer(0xFF); + } while (token == 0xFF && (millis() - start) < 500); + + if (token != 0xFE) { + return false; + } + + card->spi->transferBytes(NULL, (uint8_t*)buffer, length); + crc = card->spi->transfer16(0xFFFF); + return (!card->supports_crc || crc == CRC16(buffer, length)); +} + +char sdWriteBytes(uint8_t pdrv, const char* buffer, char token) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + unsigned short crc = (card->supports_crc)?CRC16(buffer, 512):0xFFFF; + if (!sdWait(pdrv, 500)) { + return false; + } + + card->spi->write(token); + card->spi->writeBytes((uint8_t*)buffer, 512); + card->spi->write16(crc); + return (card->spi->transfer(0xFF) & 0x1F); +} + +/* + * SPI SDCARD Communication + * */ + +char sdTransaction(uint8_t pdrv, char cmd, unsigned int arg, unsigned int* resp) +{ + if(!sdSelectCard(pdrv)) { + return 0xFF; + } + char token = sdCommand(pdrv, cmd, arg, resp); + sdDeselectCard(pdrv); + return token; +} + +bool sdReadSector(uint8_t pdrv, char* buffer, unsigned long long sector) +{ + for (int f = 0; f < 3; f++) { + if(!sdSelectCard(pdrv)) { + return false; + } + if (!sdCommand(pdrv, READ_BLOCK_SINGLE, (s_cards[pdrv]->type == CARD_SDHC) ? sector : sector << 9, NULL)) { + bool success = sdReadBytes(pdrv, buffer, 512); + sdDeselectCard(pdrv); + if (success) { + return true; + } + } else { + break; + } + } + sdDeselectCard(pdrv); + return false; +} + +bool sdReadSectors(uint8_t pdrv, char* buffer, unsigned long long sector, int count) +{ + for (int f = 0; f < 3;) { + if(!sdSelectCard(pdrv)) { + return false; + } + + if (!sdCommand(pdrv, READ_BLOCK_MULTIPLE, (s_cards[pdrv]->type == CARD_SDHC) ? sector : sector << 9, NULL)) { + do { + if (!sdReadBytes(pdrv, buffer, 512)) { + f++; + break; + } + + sector++; + buffer += 512; + f = 0; + } while (--count); + + if (sdCommand(pdrv, STOP_TRANSMISSION, 0, NULL)) { + log_e("command failed"); + break; + } + + sdDeselectCard(pdrv); + if (count == 0) { + return true; + } + } else { + break; + } + } + sdDeselectCard(pdrv); + return false; +} + +bool sdWriteSector(uint8_t pdrv, const char* buffer, unsigned long long sector) +{ + for (int f = 0; f < 3; f++) { + if(!sdSelectCard(pdrv)) { + return false; + } + if (!sdCommand(pdrv, WRITE_BLOCK_SINGLE, (s_cards[pdrv]->type == CARD_SDHC) ? sector : sector << 9, NULL)) { + char token = sdWriteBytes(pdrv, buffer, 0xFE); + sdDeselectCard(pdrv); + + if (token == 0x0A) { + continue; + } else if (token == 0x0C) { + return false; + } + + unsigned int resp; + if (sdTransaction(pdrv, SEND_STATUS, 0, &resp) || resp) { + return false; + } + return true; + } else { + break; + } + } + sdDeselectCard(pdrv); + return false; +} + +bool sdWriteSectors(uint8_t pdrv, const char* buffer, unsigned long long sector, int count) +{ + char token; + const char* currentBuffer = buffer; + unsigned long long currentSector = sector; + int currentCount = count; + ardu_sdcard_t * card = s_cards[pdrv]; + + for (int f = 0; f < 3;) { + if (card->type != CARD_MMC) { + if (sdTransaction(pdrv, SET_WR_BLK_ERASE_COUNT, currentCount, NULL)) { + return false; + } + } + + if(!sdSelectCard(pdrv)) { + return false; + } + + if (!sdCommand(pdrv, WRITE_BLOCK_MULTIPLE, (card->type == CARD_SDHC) ? currentSector : currentSector << 9, NULL)) { + do { + token = sdWriteBytes(pdrv, currentBuffer, 0xFC); + if (token != 0x05) { + f++; + break; + } + currentBuffer += 512; + f = 0; + } while (--currentCount); + + if (!sdWait(pdrv, 500)) { + break; + } + + if (currentCount == 0) { + sdStop(pdrv); + sdDeselectCard(pdrv); + + unsigned int resp; + if (sdTransaction(pdrv, SEND_STATUS, 0, &resp) || resp) { + return false; + } + return true; + } else { + if (sdCommand(pdrv, STOP_TRANSMISSION, 0, NULL)) { + break; + } + + if (token == 0x0A) { + sdDeselectCard(pdrv); + unsigned int writtenBlocks = 0; + if (card->type != CARD_MMC && sdSelectCard(pdrv)) { + if (!sdCommand(pdrv, SEND_NUM_WR_BLOCKS, 0, NULL)) { + char acmdData[4]; + if (sdReadBytes(pdrv, acmdData, 4)) { + writtenBlocks = acmdData[0] << 24; + writtenBlocks |= acmdData[1] << 16; + writtenBlocks |= acmdData[2] << 8; + writtenBlocks |= acmdData[3]; + } + } + sdDeselectCard(pdrv); + } + currentBuffer = buffer + (writtenBlocks << 9); + currentSector = sector + writtenBlocks; + currentCount = count - writtenBlocks; + continue; + } else { + break; + } + } + } else { + break; + } + } + sdDeselectCard(pdrv); + return false; +} + +unsigned long sdGetSectorsCount(uint8_t pdrv) +{ + for (int f = 0; f < 3; f++) { + if(!sdSelectCard(pdrv)) { + return false; + } + + if (!sdCommand(pdrv, SEND_CSD, 0, NULL)) { + char csd[16]; + bool success = sdReadBytes(pdrv, csd, 16); + sdDeselectCard(pdrv); + if (success) { + if ((csd[0] >> 6) == 0x01) { + unsigned long size = ( + ((unsigned long)(csd[7] & 0x3F) << 16) + | ((unsigned long)csd[8] << 8) + | csd[9] + ) + 1; + return size << 10; + } + unsigned long size = ( + ((unsigned long)(csd[6] & 0x03) << 10) + | ((unsigned long)csd[7] << 2) + | ((csd[8] & 0xC0) >> 6) + ) + 1; + size <<= (( + ((csd[9] & 0x03) << 1) + | ((csd[10] & 0x80) >> 7) + ) + 2); + size <<= (csd[5] & 0x0F); + return size >> 9; + } + } else { + break; + } + } + + sdDeselectCard(pdrv); + return 0; +} + + +namespace +{ + +struct AcquireSPI +{ + ardu_sdcard_t *card; + explicit AcquireSPI(ardu_sdcard_t* card) + : card(card) + { + card->spi->beginTransaction(SPISettings(card->frequency, MSBFIRST, SPI_MODE0)); + } + AcquireSPI(ardu_sdcard_t* card, int frequency) + : card(card) + { + card->spi->beginTransaction(SPISettings(frequency, MSBFIRST, SPI_MODE0)); + } + ~AcquireSPI() + { + card->spi->endTransaction(); + } +private: + AcquireSPI(AcquireSPI const&); + AcquireSPI& operator=(AcquireSPI const&); +}; + +} + + +/* + * FATFS API + * */ + +DSTATUS ff_sd_initialize(uint8_t pdrv) +{ + char token; + unsigned int resp; + unsigned int start; + ardu_sdcard_t * card = s_cards[pdrv]; + + if (!(card->status & STA_NOINIT)) { + return card->status; + } + + AcquireSPI card_locked(card, 400000); + + digitalWrite(card->ssPin, HIGH); + for (uint8_t i = 0; i < 20; i++) { + card->spi->transfer(0XFF); + } + + // Fix mount issue - sdWait fail ignored before command GO_IDLE_STATE + digitalWrite(card->ssPin, LOW); + if(!sdWait(pdrv, 500)){ + log_w("sdWait fail ignored, card initialize continues"); + } + if (sdCommand(pdrv, GO_IDLE_STATE, 0, NULL) != 1){ + sdDeselectCard(pdrv); + log_w("GO_IDLE_STATE failed"); + goto unknown_card; + } + sdDeselectCard(pdrv); + + token = sdTransaction(pdrv, CRC_ON_OFF, 1, NULL); + if (token == 0x5) { + //old card maybe + card->supports_crc = false; + } else if (token != 1) { + log_w("CRC_ON_OFF failed: %u", token); + goto unknown_card; + } + + if (sdTransaction(pdrv, SEND_IF_COND, 0x1AA, &resp) == 1) { + if ((resp & 0xFFF) != 0x1AA) { + log_w("SEND_IF_COND failed: %03X", resp & 0xFFF); + goto unknown_card; + } + + if (sdTransaction(pdrv, READ_OCR, 0, &resp) != 1 || !(resp & (1 << 20))) { + log_w("READ_OCR failed: %X", resp); + goto unknown_card; + } + + start = millis(); + do { + token = sdTransaction(pdrv, APP_OP_COND, 0x40100000, NULL); + } while (token == 1 && (millis() - start) < 1000); + + if (token) { + log_w("APP_OP_COND failed: %u", token); + goto unknown_card; + } + + if (!sdTransaction(pdrv, READ_OCR, 0, &resp)) { + if (resp & (1 << 30)) { + card->type = CARD_SDHC; + } else { + card->type = CARD_SD; + } + } else { + log_w("READ_OCR failed: %X", resp); + goto unknown_card; + } + } else { + if (sdTransaction(pdrv, READ_OCR, 0, &resp) != 1 || !(resp & (1 << 20))) { + log_w("READ_OCR failed: %X", resp); + goto unknown_card; + } + + start = millis(); + do { + token = sdTransaction(pdrv, APP_OP_COND, 0x100000, NULL); + } while (token == 0x01 && (millis() - start) < 1000); + + if (!token) { + card->type = CARD_SD; + } else { + start = millis(); + do { + token = sdTransaction(pdrv, SEND_OP_COND, 0x100000, NULL); + } while (token != 0x00 && (millis() - start) < 1000); + + if (token == 0x00) { + card->type = CARD_MMC; + } else { + log_w("SEND_OP_COND failed: %u", token); + goto unknown_card; + } + } + } + + if (card->type != CARD_MMC) { + if (sdTransaction(pdrv, APP_CLR_CARD_DETECT, 0, NULL)) { + log_w("APP_CLR_CARD_DETECT failed"); + goto unknown_card; + } + } + + if (card->type != CARD_SDHC) { + if (sdTransaction(pdrv, SET_BLOCKLEN, 512, NULL) != 0x00) { + log_w("SET_BLOCKLEN failed"); + goto unknown_card; + } + } + + card->sectors = sdGetSectorsCount(pdrv); + + if (card->frequency > 25000000) { + card->frequency = 25000000; + } + + card->status &= ~STA_NOINIT; + return card->status; + +unknown_card: + card->type = CARD_UNKNOWN; + return card->status; +} + +DSTATUS ff_sd_status(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + AcquireSPI lock(card); + + if(sdTransaction(pdrv, SEND_STATUS, 0, NULL)) + { + log_e("Check status failed"); + return STA_NOINIT; + } + return s_cards[pdrv]->status; +} + +DRESULT ff_sd_read(uint8_t pdrv, uint8_t* buffer, DWORD sector, UINT count) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if (card->status & STA_NOINIT) { + return RES_NOTRDY; + } + DRESULT res = RES_OK; + + AcquireSPI lock(card); + + if (count > 1) { + res = sdReadSectors(pdrv, (char*)buffer, sector, count) ? RES_OK : RES_ERROR; + } else { + res = sdReadSector(pdrv, (char*)buffer, sector) ? RES_OK : RES_ERROR; + } + return res; +} + +DRESULT ff_sd_write(uint8_t pdrv, const uint8_t* buffer, DWORD sector, UINT count) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if (card->status & STA_NOINIT) { + return RES_NOTRDY; + } + + if (card->status & STA_PROTECT) { + return RES_WRPRT; + } + DRESULT res = RES_OK; + + AcquireSPI lock(card); + + if (count > 1) { + res = sdWriteSectors(pdrv, (const char*)buffer, sector, count) ? RES_OK : RES_ERROR; + } else { + res = sdWriteSector(pdrv, (const char*)buffer, sector) ? RES_OK : RES_ERROR; + } + return res; +} + +DRESULT ff_sd_ioctl(uint8_t pdrv, uint8_t cmd, void* buff) +{ + switch(cmd) { + case CTRL_SYNC: + { + AcquireSPI lock(s_cards[pdrv]); + if (sdSelectCard(pdrv)) { + sdDeselectCard(pdrv); + return RES_OK; + } + } + return RES_ERROR; + case GET_SECTOR_COUNT: + *((unsigned long*) buff) = s_cards[pdrv]->sectors; + return RES_OK; + case GET_SECTOR_SIZE: + *((WORD*) buff) = 512; + return RES_OK; + case GET_BLOCK_SIZE: + *((uint32_t*)buff) = 1; + return RES_OK; + } + return RES_PARERR; +} + +bool sd_read_raw(uint8_t pdrv, uint8_t* buffer, DWORD sector) +{ + return ff_sd_read(pdrv, buffer, sector, 1) == ESP_OK; +} + +bool sd_write_raw(uint8_t pdrv, uint8_t* buffer, DWORD sector) +{ + return ff_sd_write(pdrv, buffer, sector, 1) == ESP_OK; +} + +/* + * Public methods + * */ + +uint8_t sdcard_uninit(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if (pdrv >= FF_VOLUMES || card == NULL) { + return 1; + } + sdTransaction(pdrv, GO_IDLE_STATE, 0, NULL); + ff_diskio_register(pdrv, NULL); + s_cards[pdrv] = NULL; + esp_err_t err = ESP_OK; + if (card->base_path) { + err = esp_vfs_fat_unregister_path(card->base_path); + free(card->base_path); + } + free(card); + return err; +} + +uint8_t sdcard_init(uint8_t cs, SPIClass * spi, int hz) +{ + + uint8_t pdrv = 0xFF; + if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == 0xFF) { + return pdrv; + } + + ardu_sdcard_t * card = (ardu_sdcard_t *)malloc(sizeof(ardu_sdcard_t)); + if (!card) { + return 0xFF; + } + + card->base_path = NULL; + card->frequency = hz; + card->spi = spi; + card->ssPin = cs; + + card->supports_crc = true; + card->type = CARD_NONE; + card->status = STA_NOINIT; + + pinMode(card->ssPin, OUTPUT); + digitalWrite(card->ssPin, HIGH); + + s_cards[pdrv] = card; + + static const ff_diskio_impl_t sd_impl = { + .init = &ff_sd_initialize, + .status = &ff_sd_status, + .read = &ff_sd_read, + .write = &ff_sd_write, + .ioctl = &ff_sd_ioctl + }; + ff_diskio_register(pdrv, &sd_impl); + + return pdrv; +} + +uint8_t sdcard_unmount(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if (pdrv >= FF_VOLUMES || card == NULL) { + return 1; + } + card->status |= STA_NOINIT; + card->type = CARD_NONE; + + char drv[3] = {(char)('0' + pdrv), ':', 0}; + f_mount(NULL, drv, 0); + return 0; +} + +bool sdcard_mount(uint8_t pdrv, const char* path, uint8_t max_files, bool format_if_empty) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if(pdrv >= FF_VOLUMES || card == NULL){ + return false; + } + + if(card->base_path){ + free(card->base_path); + } + card->base_path = strdup(path); + + FATFS* fs; + char drv[3] = {(char)('0' + pdrv), ':', 0}; + esp_err_t err = esp_vfs_fat_register(path, drv, max_files, &fs); + if (err == ESP_ERR_INVALID_STATE) { + log_e("esp_vfs_fat_register failed 0x(%x): SD is registered.", err); + return false; + } else if (err != ESP_OK) { + log_e("esp_vfs_fat_register failed 0x(%x)", err); + return false; + } + + FRESULT res = f_mount(fs, drv, 1); + if (res != FR_OK) { + log_e("f_mount failed: %s", fferr2str[res]); + if(res == 13 && format_if_empty){ + BYTE* work = (BYTE*) malloc(sizeof(BYTE) * FF_MAX_SS); + if (!work) { + log_e("alloc for f_mkfs failed"); + return false; + } + //FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); + const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, 0}; + res = f_mkfs(drv, &opt, work, sizeof(work)); + free(work); + if (res != FR_OK) { + log_e("f_mkfs failed: %s", fferr2str[res]); + esp_vfs_fat_unregister_path(path); + return false; + } + res = f_mount(fs, drv, 1); + if (res != FR_OK) { + log_e("f_mount failed: %s", fferr2str[res]); + esp_vfs_fat_unregister_path(path); + return false; + } + } else { + esp_vfs_fat_unregister_path(path); + return false; + } + } + AcquireSPI lock(card); + card->sectors = sdGetSectorsCount(pdrv); + return true; +} + +uint32_t sdcard_num_sectors(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if(pdrv >= FF_VOLUMES || card == NULL){ + return 0; + } + return card->sectors; +} + +uint32_t sdcard_sector_size(uint8_t pdrv) +{ + if(pdrv >= FF_VOLUMES || s_cards[pdrv] == NULL){ + return 0; + } + return 512; +} + +sdcard_type_t sdcard_type(uint8_t pdrv) +{ + ardu_sdcard_t * card = s_cards[pdrv]; + if(pdrv >= FF_VOLUMES || card == NULL){ + return CARD_NONE; + } + return card->type; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio.h new file mode 100644 index 0000000..06a861b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio.h @@ -0,0 +1,34 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SD_DISKIO_H_ +#define _SD_DISKIO_H_ + +#include "Arduino.h" +#include "SPI.h" +#include "sd_defines.h" +// #include "diskio.h" + +uint8_t sdcard_init(uint8_t cs, SPIClass * spi, int hz); +uint8_t sdcard_uninit(uint8_t pdrv); + +bool sdcard_mount(uint8_t pdrv, const char* path, uint8_t max_files, bool format_if_empty); +uint8_t sdcard_unmount(uint8_t pdrv); + +sdcard_type_t sdcard_type(uint8_t pdrv); +uint32_t sdcard_num_sectors(uint8_t pdrv); +uint32_t sdcard_sector_size(uint8_t pdrv); +bool sd_read_raw(uint8_t pdrv, uint8_t* buffer, uint32_t sector); +bool sd_write_raw(uint8_t pdrv, uint8_t* buffer, uint32_t sector); + +#endif /* _SD_DISKIO_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio_crc.c b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio_crc.c new file mode 100644 index 0000000..0372df8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD/src/sd_diskio_crc.c @@ -0,0 +1,103 @@ +/* SD/MMC File System Library + * Copyright (c) 2014 Neil Thiessen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const char m_CRC7Table[] = { + 0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, + 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77, + 0x19, 0x10, 0x0B, 0x02, 0x3D, 0x34, 0x2F, 0x26, + 0x51, 0x58, 0x43, 0x4A, 0x75, 0x7C, 0x67, 0x6E, + 0x32, 0x3B, 0x20, 0x29, 0x16, 0x1F, 0x04, 0x0D, + 0x7A, 0x73, 0x68, 0x61, 0x5E, 0x57, 0x4C, 0x45, + 0x2B, 0x22, 0x39, 0x30, 0x0F, 0x06, 0x1D, 0x14, + 0x63, 0x6A, 0x71, 0x78, 0x47, 0x4E, 0x55, 0x5C, + 0x64, 0x6D, 0x76, 0x7F, 0x40, 0x49, 0x52, 0x5B, + 0x2C, 0x25, 0x3E, 0x37, 0x08, 0x01, 0x1A, 0x13, + 0x7D, 0x74, 0x6F, 0x66, 0x59, 0x50, 0x4B, 0x42, + 0x35, 0x3C, 0x27, 0x2E, 0x11, 0x18, 0x03, 0x0A, + 0x56, 0x5F, 0x44, 0x4D, 0x72, 0x7B, 0x60, 0x69, + 0x1E, 0x17, 0x0C, 0x05, 0x3A, 0x33, 0x28, 0x21, + 0x4F, 0x46, 0x5D, 0x54, 0x6B, 0x62, 0x79, 0x70, + 0x07, 0x0E, 0x15, 0x1C, 0x23, 0x2A, 0x31, 0x38, + 0x41, 0x48, 0x53, 0x5A, 0x65, 0x6C, 0x77, 0x7E, + 0x09, 0x00, 0x1B, 0x12, 0x2D, 0x24, 0x3F, 0x36, + 0x58, 0x51, 0x4A, 0x43, 0x7C, 0x75, 0x6E, 0x67, + 0x10, 0x19, 0x02, 0x0B, 0x34, 0x3D, 0x26, 0x2F, + 0x73, 0x7A, 0x61, 0x68, 0x57, 0x5E, 0x45, 0x4C, + 0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04, + 0x6A, 0x63, 0x78, 0x71, 0x4E, 0x47, 0x5C, 0x55, + 0x22, 0x2B, 0x30, 0x39, 0x06, 0x0F, 0x14, 0x1D, + 0x25, 0x2C, 0x37, 0x3E, 0x01, 0x08, 0x13, 0x1A, + 0x6D, 0x64, 0x7F, 0x76, 0x49, 0x40, 0x5B, 0x52, + 0x3C, 0x35, 0x2E, 0x27, 0x18, 0x11, 0x0A, 0x03, + 0x74, 0x7D, 0x66, 0x6F, 0x50, 0x59, 0x42, 0x4B, + 0x17, 0x1E, 0x05, 0x0C, 0x33, 0x3A, 0x21, 0x28, + 0x5F, 0x56, 0x4D, 0x44, 0x7B, 0x72, 0x69, 0x60, + 0x0E, 0x07, 0x1C, 0x15, 0x2A, 0x23, 0x38, 0x31, + 0x46, 0x4F, 0x54, 0x5D, 0x62, 0x6B, 0x70, 0x79 +}; + +char CRC7(const char* data, int length) +{ + char crc = 0; + for (int i = 0; i < length; i++) { + crc = m_CRC7Table[(crc << 1) ^ data[i]]; + } + return crc; +} + +const unsigned short m_CRC16Table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +unsigned short CRC16(const char* data, int length) +{ + unsigned short crc = 0; + for (int i = 0; i < length; i++) { + crc = (crc << 8) ^ m_CRC16Table[((crc >> 8) ^ data[i]) & 0x00FF]; + } + return crc; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/README.md new file mode 100644 index 0000000..6d6bc69 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/README.md @@ -0,0 +1,112 @@ +# SD_MMC library + +This library provides the integration of ESP32 and ESP32-S3 with SD (Secure Digital) and MMC (Multi Media Card) cards using a built-in SDMMC module. + +Please note that SD_MMC is only available for ESP32 and ESP32-S3. For other SoCs please use the SD library based on SPI. + +## Wiring: + +![SD cards pins](https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/MMC-SD-miniSD-microSD-Color-Numbers-Names.gif/330px-MMC-SD-miniSD-microSD-Color-Numbers-Names.gif) + +Image source: [Wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/a/ab/MMC-SD-miniSD-microSD-Color-Numbers-Names.gif/330px-MMC-SD-miniSD-microSD-Color-Numbers-Names.gif) + +![SD and MMC pins](https://upload.wikimedia.org/wikipedia/commons/f/ff/15-04-29-MMC-Karte-dscf4734-e.jpg) + +Image source: [Wikipedia](https://commons.wikimedia.org/wiki/File:15-04-29-MMC-Karte-dscf4734-e.jpg) + +pin number (refer to the picture) | micro SD - SD mode | micro SD - SPI mode | mini SD - SD mode | mini SD - SPI mode | SD - SD mode | SD - SPI mode | MMC (MMC3) - MMC mode | MMC (MMC3) - SPI mode | MMCplus / MMCmobile (MMC4) - MMC mode | MMCplus / MMCmobile (MMC4) - SPI mode +----------------------------------|--------------------|---------------------|-------------------|--------------------|--------------|---------------|-----------------------|-----------------------|-----------------------------------------|-------------------------------------- +1 | D2 | not used | D3 | CS | D3 | CS | RES | CS | D3 | CS +2 | D3 | CS | CMD | DI | CMD | DI | CMD | DI | CMD | DI +3 | CMD | DI | VSS1 (GND) | VSS1 (GND) | VSS1 (GND) | VSS1 (GND) | VSS1 (GND) | VSS1 (GND) | VSS1 (GND) | VSS1 (GND) +4 | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) | VDD (3.3V) +5 | CLK | SCLK | CLK | SCLK | CLK | SCLK | CLK | SCLK | CLK | SCLK +6 | VSS (GND) | VSS (GND) | VSS2 (GND) | VSS2 (GND) | VSS2 (GND) | VSS2 (GND) | VSS2 (GND) | VSS2 (GND) | VSS2 (GND) | VSS2 (GND) +7 | D0 | DO | D0 | DO | D0 | DO | DAT | DO | D0 | DO +8 | D1 | not used | D1 | not used | D1 | not used | - | - | D1 | not used +9 | - | - | D2 | not used | D2 | not used | - | - | D2 | not used +10 | - | - | For future use | For future use | - | - | - | - | D3 | not used +11 | - | - | For future use | For future use | - | - | - | - | D4 | not used +12 | - | - | - | - | - | - | - | - | D5 | not used +13 | - | - | - | - | - | - | - | - | D6 | not used + +### Pin assignments for ESP32 + +On ESP32, SD_MMC peripheral is connected to specific GPIO pins and cannot be changed (rerouted). Please see the table below for the pin connections. + +When using an ESP-WROVER-KIT board, this example runs without any extra modifications required. Only an SD card needs to be inserted into the slot. + +ESP32 pin | SD card pin | Notes +--------------|-------------|------------ +GPIO14 (MTMS) | CLK | 10k pullup in SD mode +GPIO15 (MTDO) | CMD | 10k pullup in SD mode +GPIO2 | D0 | 10k pullup in SD mode, pull low to go into download mode (see Note about GPIO2 below!) +GPIO4 | D1 | not used in 1-line SD mode; 10k pullup in 4-line SD mode +GPIO12 (MTDI) | D2 | not used in 1-line SD mode; 10k pullup in 4-line SD mode (see Note about GPIO12 below!) +GPIO13 (MTCK) | D3 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup + + +### Pin assignments for ESP32-S3 + +On ESP32-S3, SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card or MMC. The GPIOs can be configured with the following commands: +``` + setPins(int clk, int cmd, int d0)) + setPins(int clk, int cmd, int d0, int d1, int d2, int d3)) +``` + +The table below lists the default pin assignments. + +When using an ESP32-S3-USB-OTG board, this example runs without any extra modifications required. Only an SD card needs to be inserted into the slot. + +ESP32-S3 pin | SD card pin | Notes +--------------|-------------|------------ +GPIO36 | CLK | 10k pullup +GPIO35 | CMD | 10k pullup +GPIO37 | D0 | 10k pullup +GPIO38 | D1 | not used in 1-line SD mode; 10k pullup in 4-line mode +GPIO33 | D2 | not used in 1-line SD mode; 10k pullup in 4-line mode +GPIO34 | D3 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup + +Warning: ESP32-S3-WROOM-2 is using most of the default GPIOs (33-37) to interface with on-board OPI flash. If the SD_MMC is initialized with default pins it will result in rebooting loop - please reassign the pins elsewhere using the mentioned command `setPins`. + +> **Note:** ESP32-S3-DevKitC-1 v1.1 does NOT have GPIOs 33 and 34 broken out, so it will be necessary to change at least the pin for D2 and D3. + +### 4-line and 1-line SD modes + +By default, this library uses 4-bit line mode, utilizing 6 pins: CLK, CMD, D0 - D3 and 2 power lines (3.3V and GND). It is possible to use 1-bit line mode (CLK, CMD, D0, 3.3V, GND) by passing the second argument `mode1bit==true`: +``` + SD_MMC.begin("/sdcard", true); +``` + +> **Note:** Even if card's D3 line is not connected to the ESP chip, it still has to be pulled up, otherwise the card will go into SPI protocol mode. + +### Note about GPIO2 (ESP32 only) + +GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. One way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset circuit on most development boards will pull GPIO2 low along with GPIO0, when entering download mode. + +- Some boards have pulldown and/or LED on GPIO2. LED is usually ok, but pulldown will interfere with D0 signals and must be removed. Check the schematic of your development board for anything connected to GPIO2. + +### Note about GPIO12 (ESP32 only) + +GPIO12 is used as a bootstrapping pin to select output voltage of an internal regulator which powers the flash chip (VDD_SDIO). This pin has an internal pulldown so if left unconnected it will read low at reset (selecting default 3.3V operation). When adding a pullup to this pin for SD card operation, consider the following: + +## FAQ: + +#### Do I need any additional modules, like the Arduino SD module? + +No, just wire your SD card directly to ESP32. + +Tip: If you are using a microSD card and have a spare adapter to full-sized SD, you can solder Dupont pins on the adapter. + + +#### What is the difference between SD and SD_MMC libraries? + +SD runs on SPI, and SD_MMC uses the SDMMC hardware bus on the ESP32. +The SPI uses 4 communication pins + 2 power connections and operates on up to 80MHz. The SPI option offers flexibility on pin connection because the data connections can be routed through GPIO matrix to any data pin. +SD-SPI speed is approximately half of the SD-MMC even when used on 1-bit line. +You can read more about SD SPI in the [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdspi_host.html) + +SD_MMC is supported only by ESP32 and ESP32-S3 and can be connected only to dedicated pins. SD_MMC allows to use of 1, 4 or 8 data pins + 2 additional communication pins and 2 power pins. The data pins need to be pulled up externally. +You can read more about SD_MMC in the [documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/sdmmc_host.html) +1-bit: SD_MMC_ speed is approximately two-times faster than SPI mode +4-bit: SD_MMC speed is approximately three-times faster than SPI mode. diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino new file mode 100644 index 0000000..70545f8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_Test/SDMMC_Test.ino @@ -0,0 +1,268 @@ +/* + * pin 1 - D2 | Micro SD card | + * pin 2 - D3 | / + * pin 3 - CMD | |__ + * pin 4 - VDD (3.3V) | | + * pin 5 - CLK | 8 7 6 5 4 3 2 1 / + * pin 6 - VSS (GND) | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄ / + * pin 7 - D0 | ▀ ▀ █ ▀ █ ▀ ▀ ▀ | + * pin 8 - D1 |_________________| + * ║ ║ ║ ║ ║ ║ ║ ║ + * ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗ + * ║ ║ ║ ║ ║ ║ ╚══════╗ ║ + * ║ ╔═════╝ ║ ║ ║ ╚═════╗ ║ ║ + * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║ + * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║ + * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║ + * ESP32-S3 DevKit | 21 47 GND 39 3V3 GND 40 41 42 | + * ESP32-S3-USB-OTG | 38 37 GND 36 3V3 GND 35 34 33 | + * ESP32 | 4 2 GND 14 3V3 GND 15 13 12 | + * Pin name | D1 D0 VSS CLK VDD VSS CMD D3 D2 | + * SD pin number | 8 7 6 5 4 3 2 1 9 / + * | █/ + * |__▍___▊___█___█___█___█___█___█___/ + * WARNING: ALL data pins must be pulled up to 3.3V with an external 10k Ohm resistor! + * Note to ESP32 pin 2 (D0): Add a 1K Ohm pull-up resistor to 3.3V after flashing + * + * SD Card | ESP32 + * D2 12 + * D3 13 + * CMD 15 + * VSS GND + * VDD 3.3V + * CLK 14 + * VSS GND + * D0 2 (add 1K pull up after flashing) + * D1 4 + * + * For more info see file README.md in this library or on URL: + * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD_MMC + */ + +#include "FS.h" +#include "SD_MMC.h" + +// Default pins for ESP-S3 +// Warning: ESP32-S3-WROOM-2 is using most of the default GPIOs (33-37) to interface with on-board OPI flash. +// If the SD_MMC is initialized with default pins it will result in rebooting loop - please +// reassign the pins elsewhere using the mentioned command `setPins`. +// Note: ESP32-S3-WROOM-1 does not have GPIO 33 and 34 broken out. +// Note: if it's ok to use default pins, you do not need to call the setPins +int clk = 36; +int cmd = 35; +int d0 = 37; +int d1 = 38; +int d2 = 33; +int d3 = 39; // GPIO 34 is not broken-out on ESP32-S3-DevKitC-1 v1.1 + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + File file = fs.open(path); + static uint8_t buf[512]; + size_t len = 0; + uint32_t start = millis(); + uint32_t end = start; + if(file){ + len = file.size(); + size_t flen = len; + start = millis(); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + len -= toRead; + } + end = millis() - start; + Serial.printf("%u bytes read for %lu ms\n", flen, end); + file.close(); + } else { + Serial.println("Failed to open file for reading"); + } + + + file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + + size_t i; + start = millis(); + for(i=0; i<2048; i++){ + file.write(buf, 512); + } + end = millis() - start; + Serial.printf("%u bytes written for %lu ms\n", 2048 * 512, end); + file.close(); +} + +void setup(){ + Serial.begin(115200); + /* + // If you want to change the pin assigment on ESP32-S3 uncomment this block and the appropriate + // line depending if you want to use 1-bit or 4-bit line. + // Please note that ESP32 does not allow pin change and will always fail. + //if(! setPins(clk, cmd, d0)){ + //if(! setPins(clk, cmd, d0, d1, d2, d3)){ + Serial.println("Pin change failed!"); + return; + } + */ + + if(!SD_MMC.begin()){ + Serial.println("Card Mount Failed"); + return; + } + uint8_t cardType = SD_MMC.cardType(); + + if(cardType == CARD_NONE){ + Serial.println("No SD_MMC card attached"); + return; + } + + Serial.print("SD_MMC Card Type: "); + if(cardType == CARD_MMC){ + Serial.println("MMC"); + } else if(cardType == CARD_SD){ + Serial.println("SDSC"); + } else if(cardType == CARD_SDHC){ + Serial.println("SDHC"); + } else { + Serial.println("UNKNOWN"); + } + + uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024); + Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize); + + listDir(SD_MMC, "/", 0); + createDir(SD_MMC, "/mydir"); + listDir(SD_MMC, "/", 0); + removeDir(SD_MMC, "/mydir"); + listDir(SD_MMC, "/", 2); + writeFile(SD_MMC, "/hello.txt", "Hello "); + appendFile(SD_MMC, "/hello.txt", "World!\n"); + readFile(SD_MMC, "/hello.txt"); + deleteFile(SD_MMC, "/foo.txt"); + renameFile(SD_MMC, "/hello.txt", "/foo.txt"); + readFile(SD_MMC, "/foo.txt"); + testFileIO(SD_MMC, "/test.txt"); + Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024)); + Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024)); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino new file mode 100644 index 0000000..cf21e6d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/examples/SDMMC_time/SDMMC_time.ino @@ -0,0 +1,274 @@ +/* + * pin 1 - D2 | Micro SD card | + * pin 2 - D3 | / + * pin 3 - CMD | |__ + * pin 4 - VDD (3.3V) | | + * pin 5 - CLK | 8 7 6 5 4 3 2 1 / + * pin 6 - VSS (GND) | ▄ ▄ ▄ ▄ ▄ ▄ ▄ ▄ / + * pin 7 - D0 | ▀ ▀ █ ▀ █ ▀ ▀ ▀ | + * pin 8 - D1 |_________________| + * ║ ║ ║ ║ ║ ║ ║ ║ + * ╔═══════╝ ║ ║ ║ ║ ║ ║ ╚═════════╗ + * ║ ║ ║ ║ ║ ║ ╚══════╗ ║ + * ║ ╔═════╝ ║ ║ ║ ╚═════╗ ║ ║ + * Connections for ║ ║ ╔═══╩═║═║═══╗ ║ ║ ║ + * full-sized ║ ║ ║ ╔═╝ ║ ║ ║ ║ ║ + * SD card ║ ║ ║ ║ ║ ║ ║ ║ ║ + * ESP32-S3 DevKit | 21 47 GND 39 3V3 GND 40 41 42 | + * ESP32-S3-USB-OTG | 38 37 GND 36 3V3 GND 35 34 33 | + * ESP32 | 4 2 GND 14 3V3 GND 15 13 12 | + * Pin name | D1 D0 VSS CLK VDD VSS CMD D3 D2 | + * SD pin number | 8 7 6 5 4 3 2 1 9 / + * | █/ + * |__▍___▊___█___█___█___█___█___█___/ + * WARNING: ALL data pins must be pulled up to 3.3V with external 10k Ohm resistor! + * Note to ESP32 pin 2 (D0): Add 1K Ohm pull-up resistor to 3.3V after flashing + * + * For more info see file README.md in this library or on URL: + * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD_MMC + */ + +#include "FS.h" +#include "SD_MMC.h" +#include "SPI.h" +#include +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +long timezone = 1; +byte daysavetime = 1; + +// Default pins for ESP-S3 +// Warning: ESP32-S3-WROOM-2 is using most of the default SD_MMC GPIOs (33-37) to interface with on-board OPI flash. +// If the SD_MMC is initialized with default pins it will result in rebooting loop - please +// reassign the pins elsewhere using the mentioned command `setPins`. +// Note: ESP32-S3-WROOM-1 does not have GPIO 33 and 34 broken out. +// Note: The board ESP32-S3-USB-OTG has predefined default pins and the following definitions with the setPins() call will not be compiled. +// Note: Pins in this definition block are ordered from top down in order in which they are on the full-sized SD card +// from left to right when facing the pins down (when connected to a breadboard) + +#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && not defined(BOARD_HAS_SDMMC) + int d1 = 21; // SD pin 8 - Add a 10k Ohm pull-up resistor to 3.3V if using 4-bit mode (use_1_bit_mode = false) + int d0 = 47; // SD pin 7 - Add a 10k Ohm pull-up resistor to 3.3V + // GND pin - SD pin 6 + int clk = 39; // SD pin 5 - Add a 10k Ohm pull-up resistor to 3.3V + // 3.3V pin - SD pin 4 + // GND pin - SD pin 3 + int cmd = 40; // SD pin 2 - Add a 10k Ohm pull-up resistor to 3.3V + int d3 = 41; // SD pin 1 - Add a 10k Ohm pull-up resistor to 3.3V to card's pin even when using 1-bit mode + int d2 = 42; // SD pin 9 - Add a 10k Ohm pull-up resistor to 3.3V if using 4-bit mode (use_1_bit_mode = false) +#endif + +bool use_1_bit_mode = false; // Change the value to `true` to use 1-bit mode instead of the 4-bit mode + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.print (file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup(){ + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + + // If you are using any other ESP32-S3 board than ESP32-S3-USB-OTG which has preset default pins, you will + // need to specify the pins with the following example of SD_MMC.setPins() + // If you want to use only 1-bit mode, you can use the line with only one data pin (d0) begin changed. + // Please note that ESP32 does not allow pin changes and will fail unless you enter the same pin config as is the hardwired. +#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && not defined(BOARD_HAS_SDMMC) + if(use_1_bit_mode){ + if(! SD_MMC.setPins(clk, cmd, d0)){ // 1-bit line version + Serial.println("Pin change failed!"); + return; + } + } else { + if(! SD_MMC.setPins(clk, cmd, d0, d1, d2, d3)){ // 4-bit line version + Serial.println("Pin change failed!"); + return; + } + } +#endif + + if(!SD_MMC.begin("/sdcard", use_1_bit_mode)){ + Serial.println("Card Mount Failed."); + Serial.println("Increase log level to see more info: Tools > Core Debug Level > Verbose"); + Serial.println("Make sure that all data pins have a 10k Ohm pull-up resistor to 3.3V"); +#ifdef SOC_SDMMC_USE_GPIO_MATRIX + Serial.println("Make sure that when using generic ESP32-S3 board the pins are setup using SD_MMC.setPins()"); +#endif + return; + } + uint8_t cardType = SD_MMC.cardType(); + + if(cardType == CARD_NONE){ + Serial.println("No SD card attached"); + return; + } + + Serial.print("SD Card Type: "); + if(cardType == CARD_MMC){ + Serial.println("MMC"); + } else if(cardType == CARD_SD){ + Serial.println("SDSC"); + } else if(cardType == CARD_SDHC){ + Serial.println("SDHC"); + } else { + Serial.println("UNKNOWN"); + } + + uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024); + Serial.printf("SD Card Size: %lluMB\n", cardSize); + + listDir(SD_MMC, "/", 0); + removeDir(SD_MMC, "/mydir"); + createDir(SD_MMC, "/mydir"); + deleteFile(SD_MMC, "/hello.txt"); + writeFile(SD_MMC, "/hello.txt", "Hello "); + appendFile(SD_MMC, "/hello.txt", "World!\n"); + listDir(SD_MMC, "/", 0); +} + +void loop(){ + +} + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/library.properties new file mode 100644 index 0000000..9e281aa --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/library.properties @@ -0,0 +1,9 @@ +name=SD_MMC +version=2.0.0 +author=Hristo Gochkov, Ivan Grokhtkov +maintainer=Hristo Gochkov +sentence=ESP32 SDMMC File System +paragraph= +category=Data Storage +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/SD_MMC.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/SD_MMC.cpp new file mode 100644 index 0000000..cdc41ca --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/SD_MMC.cpp @@ -0,0 +1,255 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pins_arduino.h" +#include "SD_MMC.h" +#ifdef SOC_SDMMC_HOST_SUPPORTED +#include "vfs_api.h" + +#include +#include "esp_vfs_fat.h" +#include "driver/sdmmc_host.h" +#include "driver/sdmmc_defs.h" +#include "sdmmc_cmd.h" +#include "soc/sdmmc_pins.h" +#include "ff.h" +#include "esp32-hal-periman.h" + +using namespace fs; + +SDMMCFS::SDMMCFS(FSImplPtr impl) + : FS(impl), _card(nullptr) +{ +#if defined(SOC_SDMMC_USE_GPIO_MATRIX) && defined(BOARD_HAS_SDMMC) + _pin_clk = SDMMC_CLK; + _pin_cmd = SDMMC_CMD; + _pin_d0 = SDMMC_D0; +#ifndef BOARD_HAS_1BIT_SDMMC + _pin_d1 = SDMMC_D1; + _pin_d2 = SDMMC_D2; + _pin_d3 = SDMMC_D3; +#endif // BOARD_HAS_1BIT_SDMMC + +#elif SOC_SDMMC_USE_IOMUX + _pin_clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK; + _pin_cmd = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD; + _pin_d0 = SDMMC_SLOT1_IOMUX_PIN_NUM_D0; +#ifndef BOARD_HAS_1BIT_SDMMC + _pin_d1 = SDMMC_SLOT1_IOMUX_PIN_NUM_D1; + _pin_d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2; + _pin_d3 = SDMMC_SLOT1_IOMUX_PIN_NUM_D3; +#endif // BOARD_HAS_1BIT_SDMMC +#endif +} + +bool SDMMCFS::sdmmcDetachBus(void * bus_pointer){ + SDMMCFS *bus = (SDMMCFS *) bus_pointer; + if(bus->_card) { + bus->end(); + } + return true; +} + +bool SDMMCFS::setPins(int clk, int cmd, int d0) +{ + return setPins(clk, cmd, d0, GPIO_NUM_NC, GPIO_NUM_NC, GPIO_NUM_NC); +} + +bool SDMMCFS::setPins(int clk, int cmd, int d0, int d1, int d2, int d3) +{ + if (_card != nullptr) { + log_e("SD_MMC.setPins must be called before SD_MMC.begin"); + return false; + } +#ifdef SOC_SDMMC_USE_GPIO_MATRIX + // SoC supports SDMMC pin configuration via GPIO matrix. Save the pins for later use in SDMMCFS::begin. + _pin_clk = (int8_t) clk; + _pin_cmd = (int8_t) cmd; + _pin_d0 = (int8_t) d0; + _pin_d1 = (int8_t) d1; + _pin_d2 = (int8_t) d2; + _pin_d3 = (int8_t) d3; + return true; +#elif CONFIG_IDF_TARGET_ESP32 + // ESP32 doesn't support SDMMC pin configuration via GPIO matrix. + // Since SDMMCFS::begin hardcodes the usage of slot 1, only check if + // the pins match slot 1 pins. + bool pins_ok = (clk == (int)SDMMC_SLOT1_IOMUX_PIN_NUM_CLK) && + (cmd == (int)SDMMC_SLOT1_IOMUX_PIN_NUM_CMD) && + (d0 == (int)SDMMC_SLOT1_IOMUX_PIN_NUM_D0) && + (((d1 == -1) && (d2 == -1) && (d3 == -1)) || + ((d1 == (int)SDMMC_SLOT1_IOMUX_PIN_NUM_D1) && + (d2 == (int)SDMMC_SLOT1_IOMUX_PIN_NUM_D2) && + (d3 == (int)SDMMC_SLOT1_IOMUX_PIN_NUM_D3))); + if (!pins_ok) { + log_e("SDMMCFS: specified pins are not supported by this chip."); + return false; + } + return true; +#else +#error SoC not supported +#endif +} + +bool SDMMCFS::begin(const char * mountpoint, bool mode1bit, bool format_if_mount_failed, int sdmmc_frequency, uint8_t maxOpenFiles) +{ + if(_card) { + return true; + } + perimanSetBusDeinit(ESP32_BUS_TYPE_SDMMC, SDMMCFS::sdmmcDetachBus); + + //mount + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); +#ifdef SOC_SDMMC_USE_GPIO_MATRIX + // SoC supports SDMMC pin configuration via GPIO matrix. + // Check that the pins have been set either in the constructor or setPins function. + if (_pin_cmd == -1 || _pin_clk == -1 || _pin_d0 == -1 + || (!mode1bit && (_pin_d1 == -1 || _pin_d2 == -1 || _pin_d3 == -1))) { + log_e("SDMMCFS: some SD pins are not set"); + return false; + } + + slot_config.clk = (gpio_num_t) _pin_clk; + slot_config.cmd = (gpio_num_t) _pin_cmd; + slot_config.d0 = (gpio_num_t) _pin_d0; + slot_config.d1 = (gpio_num_t) _pin_d1; + slot_config.d2 = (gpio_num_t) _pin_d2; + slot_config.d3 = (gpio_num_t) _pin_d3; + slot_config.width = 4; +#endif // SOC_SDMMC_USE_GPIO_MATRIX + + if(!perimanSetPinBus(_pin_cmd, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(_pin_clk, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(_pin_d0, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!mode1bit) { + if(!perimanSetPinBus(_pin_d1, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(_pin_d2, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + if(!perimanSetPinBus(_pin_d3, ESP32_BUS_TYPE_INIT, NULL)){ return false; } + } + + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + host.flags = SDMMC_HOST_FLAG_4BIT; + host.slot = SDMMC_HOST_SLOT_1; + host.max_freq_khz = sdmmc_frequency; +#ifdef BOARD_HAS_1BIT_SDMMC + mode1bit = true; +#endif + if(mode1bit) { + host.flags = SDMMC_HOST_FLAG_1BIT; //use 1-line SD mode + slot_config.width = 1; + } + _mode1bit = mode1bit; + + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = format_if_mount_failed, + .max_files = maxOpenFiles, + .allocation_unit_size = 0, + .disk_status_check_enable = false + }; + + esp_err_t ret = esp_vfs_fat_sdmmc_mount(mountpoint, &host, &slot_config, &mount_config, &_card); + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + log_e("Failed to mount filesystem. If you want the card to be formatted, set format_if_mount_failed = true."); + } else if (ret == ESP_ERR_INVALID_STATE) { + _impl->mountpoint(mountpoint); + log_w("SD Already mounted"); + return true; + } else { + log_e("Failed to initialize the card (0x%x). Make sure SD card lines have pull-up resistors in place.", ret); + } + _card = NULL; + return false; + } + _impl->mountpoint(mountpoint); + + if(!perimanSetPinBus(_pin_cmd, ESP32_BUS_TYPE_SDMMC, (void *)(this))){ goto err; } + if(!perimanSetPinBus(_pin_clk, ESP32_BUS_TYPE_SDMMC, (void *)(this))){ goto err; } + if(!perimanSetPinBus(_pin_d0, ESP32_BUS_TYPE_SDMMC, (void *)(this))){ goto err; } + if(!mode1bit) { + if(!perimanSetPinBus(_pin_d1, ESP32_BUS_TYPE_SDMMC, (void *)(this))){ goto err; } + if(!perimanSetPinBus(_pin_d2, ESP32_BUS_TYPE_SDMMC, (void *)(this))){ goto err; } + if(!perimanSetPinBus(_pin_d3, ESP32_BUS_TYPE_SDMMC, (void *)(this))){ goto err; } + } + return true; + +err: + log_e("Failed to set all pins bus to SDMMC"); + SDMMCFS::sdmmcDetachBus((void *)(this)); + return false; +} + +void SDMMCFS::end() +{ + if(_card) { + esp_vfs_fat_sdcard_unmount(_impl->mountpoint(), _card); + _impl->mountpoint(NULL); + _card = NULL; + perimanSetPinBus(_pin_cmd, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_clk, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_d0, ESP32_BUS_TYPE_INIT, NULL); + if(!_mode1bit) { + perimanSetPinBus(_pin_d1, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_d2, ESP32_BUS_TYPE_INIT, NULL); + perimanSetPinBus(_pin_d3, ESP32_BUS_TYPE_INIT, NULL); + } + } +} + +sdcard_type_t SDMMCFS::cardType() +{ + if(!_card) { + return CARD_NONE; + } + return (_card->ocr & SD_OCR_SDHC_CAP)?CARD_SDHC:CARD_SD; +} + +uint64_t SDMMCFS::cardSize() +{ + if(!_card) { + return 0; + } + return (uint64_t)_card->csd.capacity * _card->csd.sector_size; +} + +uint64_t SDMMCFS::totalBytes() +{ + FATFS* fsinfo; + DWORD fre_clust; + if(f_getfree("0:",&fre_clust,&fsinfo)!= 0) return 0; + uint64_t size = ((uint64_t)(fsinfo->csize))*(fsinfo->n_fatent - 2) +#if _MAX_SS != 512 + *(fsinfo->ssize); +#else + *512; +#endif + return size; +} + +uint64_t SDMMCFS::usedBytes() +{ + FATFS* fsinfo; + DWORD fre_clust; + if(f_getfree("0:",&fre_clust,&fsinfo)!= 0) return 0; + uint64_t size = ((uint64_t)(fsinfo->csize))*((fsinfo->n_fatent - 2) - (fsinfo->free_clst)) +#if _MAX_SS != 512 + *(fsinfo->ssize); +#else + *512; +#endif + return size; +} + +SDMMCFS SD_MMC = SDMMCFS(FSImplPtr(new VFSImpl())); +#endif /* SOC_SDMMC_HOST_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/SD_MMC.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/SD_MMC.h new file mode 100644 index 0000000..ed0165d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/SD_MMC.h @@ -0,0 +1,67 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SDMMC_H_ +#define _SDMMC_H_ + +#include "sdkconfig.h" +#include "soc/soc_caps.h" +#ifdef SOC_SDMMC_HOST_SUPPORTED + +#include "FS.h" +#include "driver/sdmmc_types.h" +#include "sd_defines.h" + +// If reading/writing to the SD card is unstable, +// you can define BOARD_MAX_SDMMC_FREQ with lower value (Ex. SDMMC_FREQ_DEFAULT) +// in pins_arduino.h for your board variant. +#ifndef BOARD_MAX_SDMMC_FREQ +#define BOARD_MAX_SDMMC_FREQ SDMMC_FREQ_HIGHSPEED +#endif + +namespace fs +{ + +class SDMMCFS : public FS +{ +protected: + sdmmc_card_t* _card; + int8_t _pin_clk = -1; + int8_t _pin_cmd = -1; + int8_t _pin_d0 = -1; + int8_t _pin_d1 = -1; + int8_t _pin_d2 = -1; + int8_t _pin_d3 = -1; + bool _mode1bit = false; + +public: + SDMMCFS(FSImplPtr impl); + bool setPins(int clk, int cmd, int d0); + bool setPins(int clk, int cmd, int d0, int d1, int d2, int d3); + bool begin(const char * mountpoint="/sdcard", bool mode1bit=false, bool format_if_mount_failed=false, int sdmmc_frequency=BOARD_MAX_SDMMC_FREQ, uint8_t maxOpenFiles = 5); + void end(); + sdcard_type_t cardType(); + uint64_t cardSize(); + uint64_t totalBytes(); + uint64_t usedBytes(); + +private: + static bool sdmmcDetachBus(void * bus_pointer); +}; + +} + +extern fs::SDMMCFS SD_MMC; + +#endif /* SOC_SDMMC_HOST_SUPPORTED */ +#endif /* _SDMMC_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/sd_defines.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/sd_defines.h new file mode 100644 index 0000000..6e42855 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SD_MMC/src/sd_defines.h @@ -0,0 +1,25 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SD_DEFINES_H_ +#define _SD_DEFINES_H_ + +typedef enum { + CARD_NONE, + CARD_MMC, + CARD_SD, + CARD_SDHC, + CARD_UNKNOWN +} sdcard_type_t; + +#endif /* _SD_DISKIO_H_ */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/.skip.esp32c6 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/.skip.esp32c6 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino new file mode 100644 index 0000000..b0991d5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/SPI_Multiple_Buses.ino @@ -0,0 +1,99 @@ + + +/* The ESP32 has four SPi buses, however as of right now only two of + * them are available to use, HSPI and VSPI. Simply using the SPI API + * as illustrated in Arduino examples will use VSPI, leaving HSPI unused. + * + * However if we simply intialise two instance of the SPI class for both + * of these buses both can be used. However when just using these the Arduino + * way only will actually be outputting at a time. + * + * Logic analyser capture is in the same folder as this example as + * "multiple_bus_output.png" + * + * created 30/04/2018 by Alistair Symonds + */ +#include + +// Define ALTERNATE_PINS to use non-standard GPIO pins for SPI bus + +#ifdef ALTERNATE_PINS + #define VSPI_MISO 2 + #define VSPI_MOSI 4 + #define VSPI_SCLK 0 + #define VSPI_SS 33 + + #define HSPI_MISO 26 + #define HSPI_MOSI 27 + #define HSPI_SCLK 25 + #define HSPI_SS 32 +#else + #define VSPI_MISO MISO + #define VSPI_MOSI MOSI + #define VSPI_SCLK SCK + #define VSPI_SS SS + + #define HSPI_MISO 12 + #define HSPI_MOSI 13 + #define HSPI_SCLK 14 + #define HSPI_SS 15 +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#define VSPI FSPI +#endif + +static const int spiClk = 1000000; // 1 MHz + +//uninitalised pointers to SPI objects +SPIClass * vspi = NULL; +SPIClass * hspi = NULL; + +void setup() { + //initialise two instances of the SPIClass attached to VSPI and HSPI respectively + vspi = new SPIClass(VSPI); + hspi = new SPIClass(HSPI); + + //clock miso mosi ss + +#ifndef ALTERNATE_PINS + //initialise vspi with default pins + //SCLK = 18, MISO = 19, MOSI = 23, SS = 5 + vspi->begin(); +#else + //alternatively route through GPIO pins of your choice + vspi->begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_SS); //SCLK, MISO, MOSI, SS +#endif + +#ifndef ALTERNATE_PINS + //initialise hspi with default pins + //SCLK = 14, MISO = 12, MOSI = 13, SS = 15 + hspi->begin(); +#else + //alternatively route through GPIO pins + hspi->begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_SS); //SCLK, MISO, MOSI, SS +#endif + + //set up slave select pins as outputs as the Arduino API + //doesn't handle automatically pulling SS low + pinMode(vspi->pinSS(), OUTPUT); //VSPI SS + pinMode(hspi->pinSS(), OUTPUT); //HSPI SS + +} + +// the loop function runs over and over again until power down or reset +void loop() { + //use the SPI buses + spiCommand(vspi, 0b01010101); // junk data to illustrate usage + spiCommand(hspi, 0b11001100); + delay(100); +} + +void spiCommand(SPIClass *spi, byte data) { + //use it as you would the regular arduino SPI API + spi->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0)); + digitalWrite(spi->pinSS(), LOW); //pull SS slow to prep other end for transfer + spi->transfer(data); + digitalWrite(spi->pinSS(), HIGH); //pull ss high to signify end of data transfer + spi->endTransaction(); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/multiple_bus_output.PNG b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/multiple_bus_output.PNG new file mode 100644 index 0000000..02b89f6 Binary files /dev/null and b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/examples/SPI_Multiple_Buses/multiple_bus_output.PNG differ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/keywords.txt b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/library.properties new file mode 100644 index 0000000..cf6458f --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/library.properties @@ -0,0 +1,9 @@ +name=SPI +version=2.0.0 +author=Hristo Gochkov +maintainer=Hristo Gochkov +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE. +paragraph= +category=Signal Input/Output +url=http://arduino.cc/en/Reference/SPI +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/src/SPI.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/src/SPI.cpp new file mode 100644 index 0000000..dbea4f8 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/src/SPI.cpp @@ -0,0 +1,365 @@ +/* + SPI.cpp - SPI library for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "SPI.h" +#if SOC_GPSPI_SUPPORTED + +#include "esp32-hal-log.h" + +#if !CONFIG_DISABLE_HAL_LOCKS +#define SPI_PARAM_LOCK() do {} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS) +#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock) +#else +#define SPI_PARAM_LOCK() +#define SPI_PARAM_UNLOCK() +#endif + +SPIClass::SPIClass(uint8_t spi_bus) + :_spi_num(spi_bus) + ,_spi(NULL) + ,_use_hw_ss(false) + ,_sck(-1) + ,_miso(-1) + ,_mosi(-1) + ,_ss(-1) + ,_div(0) + ,_freq(1000000) + ,_inTransaction(false) +#if !CONFIG_DISABLE_HAL_LOCKS + ,paramLock(NULL) +{ + if(paramLock==NULL){ + paramLock = xSemaphoreCreateMutex(); + if(paramLock==NULL){ + log_e("xSemaphoreCreateMutex failed"); + return; + } + } +} +#else +{} +#endif + +SPIClass::~SPIClass() +{ + end(); +#if !CONFIG_DISABLE_HAL_LOCKS + if(paramLock!=NULL){ + vSemaphoreDelete(paramLock); + paramLock = NULL; + } +#endif +} + +void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) +{ + if(_spi) { + return; + } + + if(!_div) { + _div = spiFrequencyToClockDiv(_freq); + } + + _spi = spiStartBus(_spi_num, _div, SPI_MODE0, SPI_MSBFIRST); + if(!_spi) { + return; + } + + if(sck == -1 && miso == -1 && mosi == -1 && ss == -1) { +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + _sck = (_spi_num == FSPI) ? SCK : -1; + _miso = (_spi_num == FSPI) ? MISO : -1; + _mosi = (_spi_num == FSPI) ? MOSI : -1; + _ss = (_spi_num == FSPI) ? SS : -1; +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + _sck = SCK; + _miso = MISO; + _mosi = MOSI; + _ss = SS; +#else + _sck = (_spi_num == VSPI) ? SCK : 14; + _miso = (_spi_num == VSPI) ? MISO : 12; + _mosi = (_spi_num == VSPI) ? MOSI : 13; + _ss = (_spi_num == VSPI) ? SS : 15; +#endif + } else { + _sck = sck; + _miso = miso; + _mosi = mosi; + _ss = ss; + } + + if(!spiAttachSCK(_spi, _sck)){ goto err; } + if(_miso >= 0 && !spiAttachMISO(_spi, _miso)){ goto err; } + if(_mosi >= 0 && !spiAttachMOSI(_spi, _mosi)){ goto err; } + return; + +err: + log_e("Attaching pins to SPI failed."); + +} + +void SPIClass::end() +{ + if(!_spi) { + return; + } + spiDetachSCK(_spi, _sck); + if(_miso >= 0){ + spiDetachMISO(_spi, _miso); + } + if(_mosi >= 0){ + spiDetachMOSI(_spi, _mosi); + } + setHwCs(false); + spiStopBus(_spi); + _spi = NULL; +} + +void SPIClass::setHwCs(bool use) +{ + if(_ss < 0){ + return; + } + if(use && !_use_hw_ss) { + spiAttachSS(_spi, 0, _ss); + spiSSEnable(_spi); + } else if(!use && _use_hw_ss) { + spiSSDisable(_spi); + spiDetachSS(_spi, _ss); + } + _use_hw_ss = use; +} + +void SPIClass::setFrequency(uint32_t freq) +{ + SPI_PARAM_LOCK(); + //check if last freq changed + uint32_t cdiv = spiGetClockDiv(_spi); + if(_freq != freq || _div != cdiv) { + _freq = freq; + _div = spiFrequencyToClockDiv(_freq); + spiSetClockDiv(_spi, _div); + } + SPI_PARAM_UNLOCK(); +} + +void SPIClass::setClockDivider(uint32_t clockDiv) +{ + SPI_PARAM_LOCK(); + _div = clockDiv; + spiSetClockDiv(_spi, _div); + SPI_PARAM_UNLOCK(); +} + +uint32_t SPIClass::getClockDivider() +{ + return spiGetClockDiv(_spi); +} + +void SPIClass::setDataMode(uint8_t dataMode) +{ + spiSetDataMode(_spi, dataMode); +} + +void SPIClass::setBitOrder(uint8_t bitOrder) +{ + spiSetBitOrder(_spi, bitOrder); +} + +void SPIClass::beginTransaction(SPISettings settings) +{ + SPI_PARAM_LOCK(); + //check if last freq changed + uint32_t cdiv = spiGetClockDiv(_spi); + if(_freq != settings._clock || _div != cdiv) { + _freq = settings._clock; + _div = spiFrequencyToClockDiv(_freq); + } + spiTransaction(_spi, _div, settings._dataMode, settings._bitOrder); + _inTransaction = true; +} + +void SPIClass::endTransaction() +{ + if(_inTransaction){ + _inTransaction = false; + spiEndTransaction(_spi); + SPI_PARAM_UNLOCK(); // <-- Im not sure should it be here or right after spiTransaction() + } +} + +void SPIClass::write(uint8_t data) +{ + if(_inTransaction){ + return spiWriteByteNL(_spi, data); + } + spiWriteByte(_spi, data); +} + +uint8_t SPIClass::transfer(uint8_t data) +{ + if(_inTransaction){ + return spiTransferByteNL(_spi, data); + } + return spiTransferByte(_spi, data); +} + +void SPIClass::write16(uint16_t data) +{ + if(_inTransaction){ + return spiWriteShortNL(_spi, data); + } + spiWriteWord(_spi, data); +} + +uint16_t SPIClass::transfer16(uint16_t data) +{ + if(_inTransaction){ + return spiTransferShortNL(_spi, data); + } + return spiTransferWord(_spi, data); +} + +void SPIClass::write32(uint32_t data) +{ + if(_inTransaction){ + return spiWriteLongNL(_spi, data); + } + spiWriteLong(_spi, data); +} + +uint32_t SPIClass::transfer32(uint32_t data) +{ + if(_inTransaction){ + return spiTransferLongNL(_spi, data); + } + return spiTransferLong(_spi, data); +} + +void SPIClass::transferBits(uint32_t data, uint32_t * out, uint8_t bits) +{ + if(_inTransaction){ + return spiTransferBitsNL(_spi, data, out, bits); + } + spiTransferBits(_spi, data, out, bits); +} + +/** + * @param data uint8_t * + * @param size uint32_t + */ +void SPIClass::writeBytes(const uint8_t * data, uint32_t size) +{ + if(_inTransaction){ + return spiWriteNL(_spi, data, size); + } + spiSimpleTransaction(_spi); + spiWriteNL(_spi, data, size); + spiEndTransaction(_spi); +} + +void SPIClass::transfer(void * data, uint32_t size) +{ + transferBytes((const uint8_t *)data, (uint8_t *)data, size); +} + +/** + * @param data void * + * @param size uint32_t + */ +void SPIClass::writePixels(const void * data, uint32_t size) +{ + if(_inTransaction){ + return spiWritePixelsNL(_spi, data, size); + } + spiSimpleTransaction(_spi); + spiWritePixelsNL(_spi, data, size); + spiEndTransaction(_spi); +} + +/** + * @param data uint8_t * data buffer. can be NULL for Read Only operation + * @param out uint8_t * output buffer. can be NULL for Write Only operation + * @param size uint32_t + */ +void SPIClass::transferBytes(const uint8_t * data, uint8_t * out, uint32_t size) +{ + if(_inTransaction){ + return spiTransferBytesNL(_spi, data, out, size); + } + spiTransferBytes(_spi, data, out, size); +} + +/** + * @param data uint8_t * + * @param size uint8_t max for size is 64Byte + * @param repeat uint32_t + */ +void SPIClass::writePattern(const uint8_t * data, uint8_t size, uint32_t repeat) +{ + if(size > 64) { + return; //max Hardware FIFO + } + + uint32_t byte = (size * repeat); + uint8_t r = (64 / size); + const uint8_t max_bytes_FIFO = r * size; // Max number of whole patterns (in bytes) that can fit into the hardware FIFO + + while(byte) { + if(byte > max_bytes_FIFO) { + writePattern_(data, size, r); + byte -= max_bytes_FIFO; + } else { + writePattern_(data, size, (byte / size)); + byte = 0; + } + } +} + +void SPIClass::writePattern_(const uint8_t * data, uint8_t size, uint8_t repeat) +{ + uint8_t bytes = (size * repeat); + uint8_t buffer[64]; + uint8_t * bufferPtr = &buffer[0]; + const uint8_t * dataPtr; + uint8_t dataSize = bytes; + for(uint8_t i = 0; i < repeat; i++) { + dataSize = size; + dataPtr = data; + while(dataSize--) { + *bufferPtr = *dataPtr; + dataPtr++; + bufferPtr++; + } + } + + writeBytes(&buffer[0], bytes); +} + +#if CONFIG_IDF_TARGET_ESP32 +SPIClass SPI(VSPI); +#else +SPIClass SPI(FSPI); +#endif + +#endif /* SOC_GPSPI_SUPPORTED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/src/SPI.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/src/SPI.h new file mode 100644 index 0000000..70cc28a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPI/src/SPI.h @@ -0,0 +1,101 @@ +/* + SPI.h - SPI library for esp32 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include "soc/soc_caps.h" +#if SOC_GPSPI_SUPPORTED + +#include +#include "pins_arduino.h" +#include "esp32-hal-spi.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#define SPI_HAS_TRANSACTION + +class SPISettings +{ +public: + SPISettings() :_clock(1000000), _bitOrder(SPI_MSBFIRST), _dataMode(SPI_MODE0) {} + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) :_clock(clock), _bitOrder(bitOrder), _dataMode(dataMode) {} + uint32_t _clock; + uint8_t _bitOrder; + uint8_t _dataMode; +}; + +class SPIClass +{ +private: + int8_t _spi_num; + spi_t * _spi; + bool _use_hw_ss; + int8_t _sck; + int8_t _miso; + int8_t _mosi; + int8_t _ss; + uint32_t _div; + uint32_t _freq; + bool _inTransaction; +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t paramLock=NULL; +#endif + void writePattern_(const uint8_t * data, uint8_t size, uint8_t repeat); + +public: + SPIClass(uint8_t spi_bus=HSPI); + ~SPIClass(); + void begin(int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1); + void end(); + + void setHwCs(bool use); + void setBitOrder(uint8_t bitOrder); + void setDataMode(uint8_t dataMode); + void setFrequency(uint32_t freq); + void setClockDivider(uint32_t clockDiv); + + uint32_t getClockDivider(); + + void beginTransaction(SPISettings settings); + void endTransaction(void); + void transfer(void * data, uint32_t size); + uint8_t transfer(uint8_t data); + uint16_t transfer16(uint16_t data); + uint32_t transfer32(uint32_t data); + + void transferBytes(const uint8_t * data, uint8_t * out, uint32_t size); + void transferBits(uint32_t data, uint32_t * out, uint8_t bits); + + void write(uint8_t data); + void write16(uint16_t data); + void write32(uint32_t data); + void writeBytes(const uint8_t * data, uint32_t size); + void writePixels(const void * data, uint32_t size);//ili9341 compatible + void writePattern(const uint8_t * data, uint8_t size, uint32_t repeat); + + spi_t * bus(){ return _spi; } + int8_t pinSS() { return _ss; } +}; + +extern SPIClass SPI; + +#endif /* SOC_GPSPI_SUPPORTED */ +#endif /* _SPI_H_INCLUDED */ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_Test/SPIFFS_Test.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_Test/SPIFFS_Test.ino new file mode 100644 index 0000000..3b19be5 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_Test/SPIFFS_Test.ino @@ -0,0 +1,181 @@ +#include "FS.h" +#include "SPIFFS.h" + +/* You only need to format SPIFFS the first time you run a + test or else use the SPIFFS plugin to create a partition + https://github.com/me-no-dev/arduino-esp32fs-plugin */ +#define FORMAT_SPIFFS_IF_FAILED true + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\r\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("- failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println(" - not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.println(file.name()); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print("\tSIZE: "); + Serial.println(file.size()); + } + file = root.openNextFile(); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\r\n", path); + + File file = fs.open(path); + if(!file || file.isDirectory()){ + Serial.println("- failed to open file for reading"); + return; + } + + Serial.println("- read from file:"); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\r\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("- file written"); + } else { + Serial.println("- write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\r\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("- failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("- message appended"); + } else { + Serial.println("- append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\r\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("- file renamed"); + } else { + Serial.println("- rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\r\n", path); + if(fs.remove(path)){ + Serial.println("- file deleted"); + } else { + Serial.println("- delete failed"); + } +} + +void testFileIO(fs::FS &fs, const char * path){ + Serial.printf("Testing file I/O with %s\r\n", path); + + static uint8_t buf[512]; + size_t len = 0; + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("- failed to open file for writing"); + return; + } + + size_t i; + Serial.print("- writing" ); + uint32_t start = millis(); + for(i=0; i<2048; i++){ + if ((i & 0x001F) == 0x001F){ + Serial.print("."); + } + file.write(buf, 512); + } + Serial.println(""); + uint32_t end = millis() - start; + Serial.printf(" - %u bytes written in %lu ms\r\n", 2048 * 512, end); + file.close(); + + file = fs.open(path); + start = millis(); + end = start; + i = 0; + if(file && !file.isDirectory()){ + len = file.size(); + size_t flen = len; + start = millis(); + Serial.print("- reading" ); + while(len){ + size_t toRead = len; + if(toRead > 512){ + toRead = 512; + } + file.read(buf, toRead); + if ((i++ & 0x001F) == 0x001F){ + Serial.print("."); + } + len -= toRead; + } + Serial.println(""); + end = millis() - start; + Serial.printf("- %u bytes read in %lu ms\r\n", flen, end); + file.close(); + } else { + Serial.println("- failed to open file for reading"); + } +} + +void setup(){ + Serial.begin(115200); + if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){ + Serial.println("SPIFFS Mount Failed"); + return; + } + + listDir(SPIFFS, "/", 0); + writeFile(SPIFFS, "/hello.txt", "Hello "); + appendFile(SPIFFS, "/hello.txt", "World!\r\n"); + readFile(SPIFFS, "/hello.txt"); + renameFile(SPIFFS, "/hello.txt", "/foo.txt"); + readFile(SPIFFS, "/foo.txt"); + deleteFile(SPIFFS, "/foo.txt"); + testFileIO(SPIFFS, "/test.txt"); + deleteFile(SPIFFS, "/test.txt"); + Serial.println( "Test complete" ); +} + +void loop(){ + +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_time/.skip.esp32h2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_time/.skip.esp32h2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_time/SPIFFS_time.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_time/SPIFFS_time.ino new file mode 100644 index 0000000..a867596 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/examples/SPIFFS_time/SPIFFS_time.ino @@ -0,0 +1,177 @@ +#include "FS.h" +#include "SPIFFS.h" +#include +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +long timezone = 1; +byte daysavetime = 1; + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ + Serial.printf("Listing directory: %s\n", dirname); + + File root = fs.open(dirname); + if(!root){ + Serial.println("Failed to open directory"); + return; + } + if(!root.isDirectory()){ + Serial.println("Not a directory"); + return; + } + + File file = root.openNextFile(); + while(file){ + if(file.isDirectory()){ + Serial.print(" DIR : "); + Serial.print (file.name()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + if(levels){ + listDir(fs, file.path(), levels -1); + } + } else { + Serial.print(" FILE: "); + Serial.print(file.name()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t t= file.getLastWrite(); + struct tm * tmstruct = localtime(&t); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); + } + file = root.openNextFile(); + } +} + +void createDir(fs::FS &fs, const char * path){ + Serial.printf("Creating Dir: %s\n", path); + if(fs.mkdir(path)){ + Serial.println("Dir created"); + } else { + Serial.println("mkdir failed"); + } +} + +void removeDir(fs::FS &fs, const char * path){ + Serial.printf("Removing Dir: %s\n", path); + if(fs.rmdir(path)){ + Serial.println("Dir removed"); + } else { + Serial.println("rmdir failed"); + } +} + +void readFile(fs::FS &fs, const char * path){ + Serial.printf("Reading file: %s\n", path); + + File file = fs.open(path); + if(!file){ + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while(file.available()){ + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Writing file: %s\n", path); + + File file = fs.open(path, FILE_WRITE); + if(!file){ + Serial.println("Failed to open file for writing"); + return; + } + if(file.print(message)){ + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + file.close(); +} + +void appendFile(fs::FS &fs, const char * path, const char * message){ + Serial.printf("Appending to file: %s\n", path); + + File file = fs.open(path, FILE_APPEND); + if(!file){ + Serial.println("Failed to open file for appending"); + return; + } + if(file.print(message)){ + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(fs::FS &fs, const char * path1, const char * path2){ + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (fs.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(fs::FS &fs, const char * path){ + Serial.printf("Deleting file: %s\n", path); + if(fs.remove(path)){ + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void setup(){ + Serial.begin(115200); + // We start by connecting to a WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("Contacting Time Server"); + configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); + struct tm tmstruct ; + delay(2000); + tmstruct.tm_year = 0; + getLocalTime(&tmstruct, 5000); + Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); + Serial.println(""); + + if(!SPIFFS.begin()){ + Serial.println("Card Mount Failed"); + return; + } + + listDir(SPIFFS, "/", 0); + removeDir(SPIFFS, "/mydir"); + createDir(SPIFFS, "/mydir"); + deleteFile(SPIFFS, "/hello.txt"); + writeFile(SPIFFS, "/hello.txt", "Hello "); + appendFile(SPIFFS, "/hello.txt", "World!\n"); + listDir(SPIFFS, "/", 0); +} + +void loop(){ + +} + + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/library.properties new file mode 100644 index 0000000..a59fbc7 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/library.properties @@ -0,0 +1,9 @@ +name=SPIFFS +version=2.0.0 +author=Hristo Gochkov, Ivan Grokhtkov +maintainer=Hristo Gochkov +sentence=ESP32 SPIFFS File System +paragraph= +category=Data Storage +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/src/SPIFFS.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/src/SPIFFS.cpp new file mode 100644 index 0000000..0fb2eff --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/src/SPIFFS.cpp @@ -0,0 +1,139 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "vfs_api.h" + +extern "C" { +#include +#include +#include +#include "esp_spiffs.h" +} + +#include "SPIFFS.h" + +using namespace fs; + +class SPIFFSImpl : public VFSImpl +{ +public: + SPIFFSImpl(); + virtual ~SPIFFSImpl() { } + virtual bool exists(const char* path); +}; + +SPIFFSImpl::SPIFFSImpl() +{ +} + +bool SPIFFSImpl::exists(const char* path) +{ + File f = open(path, "r",false); + return (f == true) && !f.isDirectory(); +} + +SPIFFSFS::SPIFFSFS() : FS(FSImplPtr(new SPIFFSImpl())), partitionLabel_(NULL) +{ + +} + +SPIFFSFS::~SPIFFSFS() +{ + if (partitionLabel_){ + free(partitionLabel_); + partitionLabel_ = NULL; + } +} + +bool SPIFFSFS::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFiles, const char * partitionLabel) +{ + if (partitionLabel_){ + free(partitionLabel_); + partitionLabel_ = NULL; + } + + if (partitionLabel){ + partitionLabel_ = strdup(partitionLabel); + } + + if(esp_spiffs_mounted(partitionLabel_)){ + log_w("SPIFFS Already Mounted!"); + return true; + } + + esp_vfs_spiffs_conf_t conf = { + .base_path = basePath, + .partition_label = partitionLabel_, + .max_files = maxOpenFiles, + .format_if_mount_failed = false + }; + + esp_err_t err = esp_vfs_spiffs_register(&conf); + if(err == ESP_FAIL && formatOnFail){ + if(format()){ + err = esp_vfs_spiffs_register(&conf); + } + } + if(err != ESP_OK){ + log_e("Mounting SPIFFS failed! Error: %d", err); + return false; + } + _impl->mountpoint(basePath); + return true; +} + +void SPIFFSFS::end() +{ + if(esp_spiffs_mounted(partitionLabel_)){ + esp_err_t err = esp_vfs_spiffs_unregister(partitionLabel_); + if(err){ + log_e("Unmounting SPIFFS failed! Error: %d", err); + return; + } + _impl->mountpoint(NULL); + } +} + +bool SPIFFSFS::format() +{ + disableCore0WDT(); + esp_err_t err = esp_spiffs_format(partitionLabel_); + enableCore0WDT(); + if(err){ + log_e("Formatting SPIFFS failed! Error: %d", err); + return false; + } + return true; +} + +size_t SPIFFSFS::totalBytes() +{ + size_t total,used; + if(esp_spiffs_info(partitionLabel_, &total, &used)){ + return 0; + } + return total; +} + +size_t SPIFFSFS::usedBytes() +{ + size_t total,used; + if(esp_spiffs_info(partitionLabel_, &total, &used)){ + return 0; + } + return used; +} + +SPIFFSFS SPIFFS; + diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/src/SPIFFS.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/src/SPIFFS.h new file mode 100644 index 0000000..4d7eb5d --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SPIFFS/src/SPIFFS.h @@ -0,0 +1,42 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef _SPIFFS_H_ +#define _SPIFFS_H_ + +#include "FS.h" + +namespace fs +{ + +class SPIFFSFS : public FS +{ +public: + SPIFFSFS(); + ~SPIFFSFS(); + bool begin(bool formatOnFail=false, const char * basePath="/spiffs", uint8_t maxOpenFiles=10, const char * partitionLabel=NULL); + bool format(); + size_t totalBytes(); + size_t usedBytes(); + void end(); + +private: + char * partitionLabel_; +}; + +} + +extern fs::SPIFFSFS SPIFFS; + + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/.skip.esp32c3 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/.skip.esp32c3 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/.skip.esp32s2 b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/.skip.esp32s2 new file mode 100644 index 0000000..e69de29 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/SimpleBleDevice.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/SimpleBleDevice.ino new file mode 100644 index 0000000..3a9825a --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/examples/SimpleBleDevice/SimpleBleDevice.ino @@ -0,0 +1,52 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Sketch shows how to use SimpleBLE to advertise the name of the device and change it on the press of a button +// Useful if you want to advertise some sort of message +// Button is attached between GPIO 0 and GND, and the device name changes each time the button is pressed + +#include "SimpleBLE.h" + +#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) +#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it +#endif + +SimpleBLE ble; + +void onButton(){ + String out = "BLE32 name: "; + out += String(millis() / 1000); + Serial.println(out); + ble.begin(out); +} + +void setup() { + Serial.begin(115200); + Serial.setDebugOutput(true); + pinMode(0, INPUT_PULLUP); + Serial.print("ESP32 SDK: "); + Serial.println(ESP.getSdkVersion()); + ble.begin("ESP32 SimpleBLE"); + Serial.println("Press the button to change the device's name"); +} + +void loop() { + static uint8_t lastPinState = 1; + uint8_t pinState = digitalRead(0); + if(!pinState && lastPinState){ + onButton(); + } + lastPinState = pinState; + while(Serial.available()) Serial.write(Serial.read()); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/library.properties b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/library.properties new file mode 100644 index 0000000..b2d3294 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/library.properties @@ -0,0 +1,9 @@ +name=SimpleBLE +version=2.0.0 +author=Hristo Gochkov +maintainer=Hristo Gochkov +sentence=Provides really simple BLE advertizer with just on and off +paragraph= +category=Communication +url= +architectures=esp32 diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/src/SimpleBLE.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/src/SimpleBLE.cpp new file mode 100644 index 0000000..d30a177 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/src/SimpleBLE.cpp @@ -0,0 +1,132 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" + +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) + +#include "SimpleBLE.h" +#include "esp32-hal-log.h" + +#include "esp_bt.h" +#include "esp_gap_ble_api.h" +#include "esp_gatts_api.h" +#include "esp_bt_defs.h" +#include "esp_bt_main.h" + +static esp_ble_adv_data_t _adv_config = { + .set_scan_rsp = false, + .include_name = true, + .include_txpower = true, + .min_interval = 512, + .max_interval = 1024, + .appearance = 0, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, + .service_data_len = 0, + .p_service_data = NULL, + .service_uuid_len = 0, + .p_service_uuid = NULL, + .flag = (ESP_BLE_ADV_FLAG_GEN_DISC|ESP_BLE_ADV_FLAG_BREDR_NOT_SPT) +}; + +static esp_ble_adv_params_t _adv_params = { + .adv_int_min = 512, + .adv_int_max = 1024, + .adv_type = ADV_TYPE_NONCONN_IND, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .peer_addr = {0x00, }, + .peer_addr_type = BLE_ADDR_TYPE_PUBLIC, + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +static void _on_gap(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){ + if(event == ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT){ + esp_ble_gap_start_advertising(&_adv_params); + } +} + +static bool _init_gap(const char * name){ + if(!btStarted() && !btStart()){ + log_e("btStart failed"); + return false; + } + esp_bluedroid_status_t bt_state = esp_bluedroid_get_status(); + if(bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){ + if (esp_bluedroid_init()) { + log_e("esp_bluedroid_init failed"); + return false; + } + } + if(bt_state != ESP_BLUEDROID_STATUS_ENABLED){ + if (esp_bluedroid_enable()) { + log_e("esp_bluedroid_enable failed"); + return false; + } + } + if(esp_ble_gap_set_device_name(name)){ + log_e("gap_set_device_name failed"); + return false; + } + if(esp_ble_gap_config_adv_data(&_adv_config)){ + log_e("gap_config_adv_data failed"); + return false; + } + if(esp_ble_gap_register_callback(_on_gap)){ + log_e("gap_register_callback failed"); + return false; + } + return true; +} + +static bool _stop_gap() +{ + if(btStarted()){ + esp_bluedroid_disable(); + esp_bluedroid_deinit(); + btStop(); + } + return true; +} + +/* + * BLE Arduino + * + * */ + +SimpleBLE::SimpleBLE() +{ + local_name = "esp32"; +} + +SimpleBLE::~SimpleBLE(void) +{ + _stop_gap(); +} + +bool SimpleBLE::begin(String localName) +{ + if(localName.length()){ + local_name = localName; + } + return _init_gap(local_name.c_str()); +} + +void SimpleBLE::end() +{ + _stop_gap(); +} + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/src/SimpleBLE.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/src/SimpleBLE.h new file mode 100644 index 0000000..6e7b702 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/SimpleBLE/src/SimpleBLE.h @@ -0,0 +1,65 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _SIMPLE_BLE_H_ +#define _SIMPLE_BLE_H_ + +#include "sdkconfig.h" + +#if defined(CONFIG_BT_ENABLED) && defined(CONFIG_BLUEDROID_ENABLED) + +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_bt.h" + +#include "Arduino.h" + +struct ble_gap_adv_params_s; + +class SimpleBLE { + public: + + SimpleBLE(void); + ~SimpleBLE(void); + + /** + * Start BLE Advertising + * + * @param[in] localName local name to advertise + * + * @return true on success + * + */ + bool begin(String localName=String()); + + /** + * Stop BLE Advertising + * + * @return none + */ + void end(void); + + private: + String local_name; + private: + +}; + +#endif + +#endif diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/README.md new file mode 100644 index 0000000..6fadc59 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/README.md @@ -0,0 +1,18 @@ +# Hello World Example + +This example is designed to demonstrate the absolute basics of using [TensorFlow +Lite for Microcontrollers](https://www.tensorflow.org/lite/microcontrollers). +It includes the full end-to-end workflow of training a model, converting it for +use with TensorFlow Lite for Microcontrollers for running inference on a +microcontroller. + +The model is trained to replicate a `sine` function and generates a pattern of +data to either blink LEDs or control an animation, depending on the capabilities +of the device. + +## Deploy to ESP32 + +The sample has been tested on ESP-IDF version `release/v4.2` and `release/v4.4` with the following devices: +- [ESP32-DevKitC](http://esp-idf.readthedocs.io/en/latest/get-started/get-started-devkitc.html) +- [ESP32-S3-DevKitC](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html) +- [ESP-EYE](https://github.com/espressif/esp-who/blob/master/docs/en/get-started/ESP-EYE_Getting_Started_Guide.md) diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/constants.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/constants.cpp new file mode 100644 index 0000000..bc32fc3 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/constants.cpp @@ -0,0 +1,19 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "constants.h" + +// This is a small number so that it's easy to read the logs +const int kInferencesPerCycle = 20; diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/constants.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/constants.h new file mode 100644 index 0000000..f452893 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/constants.h @@ -0,0 +1,32 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_CONSTANTS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_CONSTANTS_H_ + +// This constant represents the range of x values our model was trained on, +// which is from 0 to (2 * Pi). We approximate Pi to avoid requiring additional +// libraries. +const float kXrange = 2.f * 3.14159265359f; + +// This constant determines the number of inferences to perform across the range +// of x values defined above. Since each inference takes time, the higher this +// number, the more time it will take to run through the entire range. The value +// of this constant can be tuned so that one full cycle takes a desired amount +// of time. Since different devices take different amounts of time to perform +// inference, this value should be defined per-device. +extern const int kInferencesPerCycle; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_CONSTANTS_H_ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/hello_world.ino b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/hello_world.ino new file mode 100644 index 0000000..04fdd06 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/hello_world.ino @@ -0,0 +1,111 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + + +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +#include "model.h" +#include "constants.h" +#include "output_handler.h" + +// Globals, used for compatibility with Arduino-style sketches. +namespace { +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* input = nullptr; +TfLiteTensor* output = nullptr; +int inference_count = 0; + +constexpr int kTensorArenaSize = 2000; +uint8_t tensor_arena[kTensorArenaSize]; +} // namespace + +// The name of this function is important for Arduino compatibility. +void setup() { + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + model = tflite::GetModel(g_model); + if (model->version() != TFLITE_SCHEMA_VERSION) { + MicroPrintf("Model provided is schema version %d not equal to supported " + "version %d.", model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // Pull in only the operation implementations we need. + static tflite::MicroMutableOpResolver<1> resolver; + if (resolver.AddFullyConnected() != kTfLiteOk) { + return; + } + + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, resolver, tensor_arena, kTensorArenaSize); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + TfLiteStatus allocate_status = interpreter->AllocateTensors(); + if (allocate_status != kTfLiteOk) { + MicroPrintf("AllocateTensors() failed"); + return; + } + + // Obtain pointers to the model's input and output tensors. + input = interpreter->input(0); + output = interpreter->output(0); + + // Keep track of how many inferences we have performed. + inference_count = 0; +} + +// The name of this function is important for Arduino compatibility. +void loop() { + // Calculate an x value to feed into the model. We compare the current + // inference_count to the number of inferences per cycle to determine + // our position within the range of possible x values the model was + // trained on, and use this to calculate a value. + float position = static_cast(inference_count) / + static_cast(kInferencesPerCycle); + float x = position * kXrange; + + // Quantize the input from floating-point to integer + int8_t x_quantized = x / input->params.scale + input->params.zero_point; + // Place the quantized input in the model's input tensor + input->data.int8[0] = x_quantized; + + // Run inference, and report any error + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) { + MicroPrintf("Invoke failed on x: %f\n", + static_cast(x)); + return; + } + + // Obtain the quantized output from model's output tensor + int8_t y_quantized = output->data.int8[0]; + // Dequantize the output from integer to floating-point + float y = (y_quantized - output->params.zero_point) * output->params.scale; + + // Output the results. A custom HandleOutput function can be implemented + // for each supported hardware target. + HandleOutput(x, y); + + // Increment the inference_counter, and reset it if we have reached + // the total number per cycle + inference_count += 1; + if (inference_count >= kInferencesPerCycle) inference_count = 0; +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/model.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/model.cpp new file mode 100644 index 0000000..f04a9f6 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/model.cpp @@ -0,0 +1,237 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +// Automatically created from a TensorFlow Lite flatbuffer using the command: +// xxd -i model.tflite > model.cc + +// This is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. + +// See train/README.md for a full description of the creation process. + +#include "model.h" + +// Keep model aligned to 8 bytes to guarantee aligned 64-bit accesses. +alignas(8) const unsigned char g_model[] = { + 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00, + 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, + 0x2c, 0x03, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x60, 0xf7, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0xff, 0xff, 0xff, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x34, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x76, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x34, 0x02, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, + 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xfa, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xfd, 0xff, 0xff, + 0x88, 0xfd, 0xff, 0xff, 0x8c, 0xfd, 0xff, 0xff, 0x22, 0xfe, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0xa5, 0x8b, 0xca, + 0x5e, 0x1d, 0xce, 0x42, 0x9d, 0xce, 0x1f, 0xb0, 0xdf, 0x54, 0x2f, 0x81, + 0x3e, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0xee, 0xfc, 0x00, 0xec, 0x05, 0x17, 0xef, 0xec, 0xe6, 0xf8, 0x03, 0x01, + 0x00, 0xfa, 0xf8, 0xf5, 0xdc, 0xeb, 0x27, 0x14, 0xf1, 0xde, 0xe2, 0xdb, + 0xf0, 0xde, 0x31, 0x06, 0x02, 0xe6, 0xee, 0xf9, 0x00, 0x16, 0x07, 0xe0, + 0xfe, 0xff, 0xe9, 0x06, 0xe7, 0xef, 0x81, 0x1b, 0x18, 0xea, 0xc9, 0x01, + 0x0f, 0x00, 0xda, 0xf7, 0x0e, 0xec, 0x13, 0x1f, 0x04, 0x13, 0xb4, 0xe6, + 0xfd, 0x06, 0xb9, 0xe0, 0x0d, 0xec, 0xf0, 0xde, 0xeb, 0xf7, 0x05, 0x26, + 0x1a, 0xe4, 0x6f, 0x1a, 0xea, 0x1e, 0x35, 0xdf, 0x1a, 0xf3, 0xf1, 0x19, + 0x0f, 0x03, 0x1b, 0xe1, 0xde, 0x13, 0xf6, 0x19, 0xff, 0xf6, 0x1b, 0x18, + 0xf0, 0x1c, 0xda, 0x1b, 0x1b, 0x20, 0xe5, 0x1a, 0xf5, 0xff, 0x96, 0x0b, + 0x00, 0x01, 0xcd, 0xde, 0x0d, 0xf6, 0x16, 0xe3, 0xed, 0xfc, 0x0e, 0xe9, + 0xfa, 0xeb, 0x5c, 0xfc, 0x1d, 0x02, 0x5b, 0xe2, 0xe1, 0xf5, 0x15, 0xec, + 0xf4, 0x00, 0x13, 0x05, 0xec, 0x0c, 0x1d, 0x14, 0x0e, 0xe7, 0x0b, 0xf4, + 0x19, 0x00, 0xd7, 0x05, 0x27, 0x02, 0x15, 0xea, 0xea, 0x02, 0x9b, 0x00, + 0x0c, 0xfa, 0xe8, 0xea, 0xfd, 0x00, 0x14, 0xfd, 0x0b, 0x02, 0xef, 0xee, + 0x06, 0xee, 0x01, 0x0d, 0x06, 0xe6, 0xf7, 0x11, 0xf7, 0x09, 0xf8, 0xf1, + 0x21, 0xff, 0x0e, 0xf3, 0xec, 0x12, 0x26, 0x1d, 0xf2, 0xe9, 0x28, 0x18, + 0xe0, 0xfb, 0xf3, 0xf4, 0x05, 0x1d, 0x1d, 0xfb, 0xfd, 0x1e, 0xfc, 0x11, + 0xe8, 0x07, 0x09, 0x03, 0x12, 0xf2, 0x36, 0xfb, 0xdc, 0x1c, 0xf9, 0xef, + 0xf3, 0xe7, 0x6f, 0x0c, 0x1d, 0x00, 0x45, 0xfd, 0x0e, 0xf0, 0x0b, 0x19, + 0x1a, 0xfa, 0xe0, 0x19, 0x1f, 0x13, 0x36, 0x1c, 0x12, 0xeb, 0x3b, 0x0c, + 0xb4, 0xcb, 0xe6, 0x13, 0xfa, 0xeb, 0xf1, 0x06, 0x1c, 0xfa, 0x18, 0xe5, + 0xeb, 0xcb, 0x0c, 0xf4, 0x4a, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x75, 0x1c, 0x11, 0xe1, 0x0c, 0x81, 0xa5, 0x42, + 0xfe, 0xd5, 0xd4, 0xb2, 0x61, 0x78, 0x19, 0xdf, 0x66, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x77, 0x0b, 0x00, 0x00, 0x53, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x07, 0x00, 0x00, + 0x67, 0xf5, 0xff, 0xff, 0x34, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xb2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb5, 0x04, 0x00, 0x00, 0x78, 0x0a, 0x00, 0x00, + 0x2d, 0x06, 0x00, 0x00, 0x71, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x0a, 0x00, 0x00, 0xfe, 0xf7, 0xff, 0xff, 0x0e, 0x05, 0x00, 0x00, + 0xd4, 0x09, 0x00, 0x00, 0x47, 0xfe, 0xff, 0xff, 0xb6, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xac, 0xf7, 0xff, 0xff, 0x4b, 0xf9, 0xff, 0xff, + 0x4a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x8c, 0xef, 0xff, 0xff, 0x84, 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c, 0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x96, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0xba, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00, + 0xd0, 0x03, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, + 0x98, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf0, 0xfb, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0xdc, 0xfb, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x4a, 0xce, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x34, 0x84, 0x85, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xc5, 0x02, 0x8f, 0xbf, + 0x1e, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, + 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x6c, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x93, 0xd0, 0xc0, 0x3b, 0x01, 0x00, 0x00, 0x00, + 0xc2, 0x0f, 0xc0, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x74, 0x66, 0x6c, 0x2e, 0x66, 0x75, 0x6c, 0x6c, + 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x08, 0xfd, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xf4, 0xfc, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xe0, 0xdb, 0x47, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x04, 0x14, 0x47, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x74, 0x66, 0x6c, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x5f, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x6c, 0xfd, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfb, 0x4b, 0x0b, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x84, 0x4b, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x63, 0x35, 0x8a, 0xbf, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x32, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x72, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, + 0xdc, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x60, 0x01, 0x4f, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x47, 0x6d, 0xb3, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x5d, 0x63, 0xcd, 0xbf, 0x0d, 0x00, 0x00, 0x00, + 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, + 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xe2, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x50, 0x00, 0x00, 0x00, 0x4c, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xd5, 0x6b, 0x8a, 0x3b, 0x01, 0x00, 0x00, 0x00, + 0xab, 0x49, 0x01, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xfd, 0x56, 0x09, 0xbf, + 0x0c, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x28, 0xb3, 0xd9, 0x38, 0x0c, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xaa, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00, 0x00, + 0x9c, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xdd, 0x9b, 0x21, 0x39, 0x0c, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x33, 0x2f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x48, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xf4, 0xd4, 0x51, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, + 0x65, 0x5f, 0x34, 0x2f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x1c, 0x00, + 0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x5d, 0x4f, 0xc9, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x86, 0xc8, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, + 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09}; +const int g_model_len = 2488; diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/model.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/model.h new file mode 100644 index 0000000..488f47b --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/model.h @@ -0,0 +1,31 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +// Automatically created from a TensorFlow Lite flatbuffer using the command: +// xxd -i model.tflite > model.cc + +// This is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. + +// See train/README.md for a full description of the creation process. + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MODEL_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MODEL_H_ + +extern const unsigned char g_model[]; +extern const int g_model_len; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MODEL_H_ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/output_handler.cpp b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/output_handler.cpp new file mode 100644 index 0000000..0d5f80e --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/output_handler.cpp @@ -0,0 +1,23 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include "output_handler.h" +#include "tensorflow/lite/micro/micro_log.h" + +void HandleOutput(float x_value, float y_value) { + // Log the current X and Y values + MicroPrintf("x_value: %f, y_value: %f\n", static_cast(x_value), + static_cast(y_value)); +} diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/output_handler.h b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/output_handler.h new file mode 100644 index 0000000..a168460 --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/hello_world/output_handler.h @@ -0,0 +1,24 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_OUTPUT_HANDLER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_OUTPUT_HANDLER_H_ + +#include "tensorflow/lite/c/common.h" + +// Called by the main loop to produce some output based on the x and y values +void HandleOutput(float x_value, float y_value); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_OUTPUT_HANDLER_H_ diff --git a/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/micro_speech/README.md b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/micro_speech/README.md new file mode 100644 index 0000000..ed293bf --- /dev/null +++ b/maddius/maddius_matrix_control/components/espressif__arduino-esp32/libraries/TFLiteMicro/examples/micro_speech/README.md @@ -0,0 +1,22 @@ +# Micro Speech Example + +This example shows how to run a 20 kB model that can recognize 2 keywords, +"yes" and "no", from speech data. + +The application listens to its surroundings with a microphone and indicates +when it has detected a word by displaying data on a screen. + +## Deploy to ESP32 + +The sample has been tested on ESP-IDF version `release/v4.2` and `release/v4.4` with the following devices: +- [ESP32-DevKitC](http://esp-idf.readthedocs.io/en/latest/get-started/get-started-devkitc.html) +- [ESP32-S3-DevKitC](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitc-1.html) +- [ESP-EYE](https://github.com/espressif/esp-who/blob/master/docs/en/get-started/ESP-EYE_Getting_Started_Guide.md) + +### Sample output + + * When a keyword is detected you will see following output sample output on the log screen: + +``` +Heard yes () at