diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b262f55c0..cedfb289a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -125,6 +125,7 @@ jobs: arduino --pref "custom_xtal=nodemcuv2_80" --save-prefs ; cd $HOME/.arduino15/packages/esp8266/hardware/esp8266/2.7.0 ; sed -i '52 a #define isFlashInterfacePin(p) ((p) == 6 || (p) == 7 || (p) == 8 || (p) == 9 || (p) == 11)' variants/nodemcu/pins_arduino.h ; + sed -i '57 a \ unsigned long getTimeout () const { return _timeout; }' cores/esp8266/Stream.h ; cd $GITHUB_WORKSPACE ; fi if [[ "$BOARD" =~ "esp32:esp32:esp32:" ]]; then diff --git a/software/firmware/source/SoftRF/src/driver/WiFi.cpp b/software/firmware/source/SoftRF/src/driver/WiFi.cpp index c1f461874..3af5d16fe 100644 --- a/software/firmware/source/SoftRF/src/driver/WiFi.cpp +++ b/software/firmware/source/SoftRF/src/driver/WiFi.cpp @@ -106,8 +106,6 @@ void Raw_Transmit_UDP() } #if defined(USE_ARDUINO_WIFI) -#include - void WiFi_setup() { // Set Hostname. diff --git a/software/firmware/source/SoftRF/src/platform/ESP32.cpp b/software/firmware/source/SoftRF/src/platform/ESP32.cpp index a1e6141c8..0feed58ea 100644 --- a/software/firmware/source/SoftRF/src/platform/ESP32.cpp +++ b/software/firmware/source/SoftRF/src/platform/ESP32.cpp @@ -80,8 +80,6 @@ lmic_pinmap lmic_pins = { .tcxo = LMIC_UNUSED_PIN, }; -WebServer server ( 80 ); - #if !defined(EXCLUDE_LED_RING) #if defined(USE_NEOPIXELBUS_LIBRARY) NeoPixelBus strip(PIX_NUM, SOC_GPIO_PIN_LED); diff --git a/software/firmware/source/SoftRF/src/platform/ESP32.h b/software/firmware/source/SoftRF/src/platform/ESP32.h index 8bf5e4b19..98d2892dc 100644 --- a/software/firmware/source/SoftRF/src/platform/ESP32.h +++ b/software/firmware/source/SoftRF/src/platform/ESP32.h @@ -22,8 +22,10 @@ #include "sdkconfig.h" +#define USE_WIFI_NINA false +#define USE_WIFI_CUSTOM true #include -#include + #include #include #include @@ -238,8 +240,6 @@ extern Adafruit_NeoPixel strip; #include "iomap/WT0132C6.h" #include "iomap/LilyGO_T3C6.h" -extern WebServer server; - enum rst_reason { REASON_DEFAULT_RST = 0, /* normal startup by power on */ REASON_WDT_RST = 1, /* hardware watch dog reset */ diff --git a/software/firmware/source/SoftRF/src/platform/ESP8266.cpp b/software/firmware/source/SoftRF/src/platform/ESP8266.cpp index 68c823e79..6e7601a0c 100644 --- a/software/firmware/source/SoftRF/src/platform/ESP8266.cpp +++ b/software/firmware/source/SoftRF/src/platform/ESP8266.cpp @@ -52,8 +52,6 @@ Exp_SoftwareSerial swSer(SOC_GPIO_PIN_GNSS_RX, SOC_GPIO_PIN_GNSS_TX, false, 256) SoftwareSerial swSer; #endif -ESP8266WebServer server ( 80 ); - // Parameter 1 = number of pixels in strip // Parameter 2 = Arduino pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: diff --git a/software/firmware/source/SoftRF/src/platform/ESP8266.h b/software/firmware/source/SoftRF/src/platform/ESP8266.h index 32f780cad..23b0d23ea 100644 --- a/software/firmware/source/SoftRF/src/platform/ESP8266.h +++ b/software/firmware/source/SoftRF/src/platform/ESP8266.h @@ -20,10 +20,12 @@ #ifndef PLATFORM_ESP8266_H #define PLATFORM_ESP8266_H +#define USE_WIFI_NINA false +#define USE_WIFI_CUSTOM true #include + #include #include -#include #define USE_EXP_SW_SERIAL @@ -92,7 +94,6 @@ extern "C" { #include } -extern ESP8266WebServer server; #if defined(USE_EXP_SW_SERIAL) extern Exp_SoftwareSerial swSer; #else diff --git a/software/firmware/source/SoftRF/src/platform/RA4M1.h b/software/firmware/source/SoftRF/src/platform/RA4M1.h index 82b6c4b9f..952d17f6b 100644 --- a/software/firmware/source/SoftRF/src/platform/RA4M1.h +++ b/software/firmware/source/SoftRF/src/platform/RA4M1.h @@ -133,7 +133,9 @@ struct rst_info { #elif defined(ARDUINO_UNOR4_WIFI) #define USE_ARDUINO_WIFI #define EXCLUDE_OTA -#define EXCLUDE_WEBUI /* TODO */ +#define USE_WIFI_NINA false +#define USE_WIFI_CUSTOM true +#include #define Serial_setDebugOutput(x) ({}) #endif @@ -160,7 +162,7 @@ struct rst_info { #define EXCLUDE_NRF905 // - kb #define EXCLUDE_UATM // - kb #define EXCLUDE_MAVLINK // - kb -//#define EXCLUDE_EGM96 // - kb +#define EXCLUDE_EGM96 // - kb #define EXCLUDE_LED_RING // - kb #define EXCLUDE_SOUND diff --git a/software/firmware/source/SoftRF/src/platform/RP2040.cpp b/software/firmware/source/SoftRF/src/platform/RP2040.cpp index 99299935a..389439dd0 100644 --- a/software/firmware/source/SoftRF/src/platform/RP2040.cpp +++ b/software/firmware/source/SoftRF/src/platform/RP2040.cpp @@ -122,7 +122,6 @@ Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIX_NUM, SOC_GPIO_PIN_LED, char UDPpacketBuffer[4]; // Dummy definition to satisfy build sequence #else #include "../driver/WiFi.h" -WebServer server ( 80 ); #define isTimeToAP() (millis() - AP_clients_TimeMarker > 1000) static unsigned long AP_clients_TimeMarker = 0; diff --git a/software/firmware/source/SoftRF/src/platform/RP2040.h b/software/firmware/source/SoftRF/src/platform/RP2040.h index cb61630d6..ea91947ba 100644 --- a/software/firmware/source/SoftRF/src/platform/RP2040.h +++ b/software/firmware/source/SoftRF/src/platform/RP2040.h @@ -225,11 +225,12 @@ struct rst_info { #endif #if defined(ARDUINO_RASPBERRY_PI_PICO_W) -#include -#include +#define USE_WIFI_NINA false +#define USE_WIFI_CUSTOM true +#include #define Serial_setDebugOutput(x) ({}) #define WIFI_STA_TIMEOUT 20000 -extern WebServer server; + /* Experimental */ #define ENABLE_PROL //#define ENABLE_BT_VOICE diff --git a/software/firmware/source/SoftRF/src/ui/Web.cpp b/software/firmware/source/SoftRF/src/ui/Web.cpp index 83d838d33..340d740a1 100644 --- a/software/firmware/source/SoftRF/src/ui/Web.cpp +++ b/software/firmware/source/SoftRF/src/ui/Web.cpp @@ -55,6 +55,9 @@ static const char Logo[] PROGMEM = { #include "jquery_min_js.h" +#include +WiFiWebServer server ( 80 ); + byte getVal(char c) { if(c >= '0' && c <= '9') @@ -800,7 +803,7 @@ void handleRoot() { #endif /* ENABLE_RECORDER */ /* SoC specific part 1 */ - if (SoC->id != SOC_RP2040) { + if (SoC->id != SOC_RP2040 && SoC->id != SOC_RA4M1) { snprintf_P ( offset, size, PSTR("\ ")); len = strlen(offset); @@ -1164,6 +1167,10 @@ void Web_setup() server.on ( "/inline", []() { server.send ( 200, "text/plain", "this works as well" ); } ); + + server.onNotFound ( handleNotFound ); + +#if !defined(EXCLUDE_OTA) server.on("/firmware", HTTP_GET, [](){ SoC->swSer_enableRx(false); server.sendHeader(String(F("Connection")), String(F("close"))); @@ -1226,7 +1233,6 @@ void Web_setup() ); SoC->swSer_enableRx(true); }); - server.onNotFound ( handleNotFound ); server.on("/update", HTTP_POST, [](){ SoC->swSer_enableRx(false); @@ -1263,15 +1269,19 @@ void Web_setup() } yield(); }); +#endif /* EXCLUDE_OTA */ /* FLASH memory usage optimization */ -#if !defined(ARDUINO_ARCH_RP2040) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(ARDUINO_ARCH_RP2040) && \ + !defined(CONFIG_IDF_TARGET_ESP32C6) && \ + !defined(ARDUINO_ARCH_RENESAS) + server.on ( "/logo.png", []() { server.send_P ( 200, "image/png", Logo, sizeof(Logo) ); } ); -#endif /* ARDUINO_ARCH_RP2040 CONFIG_IDF_TARGET_ESP32C6 */ +#endif /* ARDUINO_ARCH_RP2040 CONFIG_IDF_TARGET_ESP32C6 ARDUINO_ARCH_RENESAS */ -#if !defined(ARDUINO_ARCH_RP2040) +#if !defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_ARCH_RENESAS) server.on ( "/jquery.min.js", []() { PGM_P content = jquery_min_js_gz; @@ -1290,7 +1300,7 @@ void Web_setup() } while (bytes_left > 0) ; } ); -#endif /* ARDUINO_ARCH_RP2040 */ +#endif /* ARDUINO_ARCH_RP2040 ARDUINO_ARCH_RENESAS */ #if defined(ENABLE_RECORDER) server.on("/flights", HTTP_GET, Handle_Flight_Download); diff --git a/software/firmware/source/libraries/WiFiWebServer/.codespellrc b/software/firmware/source/libraries/WiFiWebServer/.codespellrc new file mode 100644 index 000000000..00fe36261 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.codespellrc @@ -0,0 +1,7 @@ +# See: https://github.com/codespell-project/codespell#using-a-config-file +[codespell] +# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: +ignore-words-list = , +check-filenames = +check-hidden = +skip = ./.git,./src,./examples,./Packages_Patches,./LibraryPatches diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/ISSUE_TEMPLATE/bug_report.md b/software/firmware/source/libraries/WiFiWebServer/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..c8cdfff68 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,97 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +### Describe the bug + +A clear and concise description of what the bug is. + +### Steps to Reproduce + +Steps to reproduce the behavior. Including the [MRE](https://stackoverflow.com/help/minimal-reproducible-example) sketches + +### Expected behavior + +A clear and concise description of what you expected to happen. + +### Actual behavior + +A clear and concise description of what you expected to happen. + +### Debug and AT-command log (if applicable) + +A clear and concise description of what you expected to happen. + +### Screenshots + +If applicable, add screenshots to help explain your problem. + +### Information + +Please ensure to specify the following: + +* Arduino IDE version (e.g. 1.8.19) or Platform.io version +* Board Core Version (e.g. Arduino SAMDUE core v1.6.12, ESP8266 core v3.0.2, ArduinoCore-mbed v3.4.1, etc.) +* Contextual information (e.g. what you were trying to achieve) +* Simplest possible steps to reproduce +* Anything that might be relevant in your opinion, such as: + * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` + * Network configuration + + +### Example + +``` +Arduino IDE version: 1.8.19 +RASPBERRY_PI_PICO board +ArduinoCore-mbed v3.4.1 +OS: Ubuntu 20.04 LTS +Linux xy-Inspiron-3593 5.15.0-53-generic #59~20.04.1-Ubuntu SMP Thu Oct 20 15:10:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux + +Context: +I encountered a crash while using this library +Steps to reproduce: +1. ... +2. ... +3. ... +4. ... +``` + +### Additional context + +Add any other context about the problem here. + +--- + +### Sending Feature Requests + +Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. + +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/WiFiWebServer/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. + +--- + +### Sending Pull Requests + +Pull Requests with changes and fixes are also welcome! + +Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) + +1. Change directory to the library GitHub + +``` +xy@xy-Inspiron-3593:~$ cd Arduino/xy/WiFiWebServer_GitHub/ +xy@xy-Inspiron-3593:~/Arduino/xy/WiFiWebServer_GitHub$ +``` + +2. Issue astyle command + +``` +xy@xy-Inspiron-3593:~/Arduino/xy/WiFiWebServer_GitHub$ bash utils/restyle.sh +``` + diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/ISSUE_TEMPLATE/feature_request.md b/software/firmware/source/libraries/WiFiWebServer/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..bbcbbe7d6 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/dependabot.yml b/software/firmware/source/libraries/WiFiWebServer/.github/dependabot.yml new file mode 100644 index 000000000..03600dd7d --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/dependabot.yml @@ -0,0 +1,10 @@ +# See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file +version: 2 + +updates: + # Configure check for outdated GitHub Actions actions in workflows. + # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot + - package-ecosystem: github-actions + directory: / # Check the repository's workflows under /.github/workflows/ + schedule: + interval: daily diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/stale.yml b/software/firmware/source/libraries/WiFiWebServer/.github/stale.yml new file mode 100644 index 000000000..7d1411351 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/stale.yml @@ -0,0 +1,31 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +daysUntilStale: 60 +daysUntilClose: 14 +limitPerRun: 30 +staleLabel: stale +exemptLabels: + - pinned + - security + - "to be implemented" + - "for reference" + - "move to PR" + - "enhancement" + +only: issues +onlyLabels: [] +exemptProjects: false +exemptMilestones: false +exemptAssignees: false + +markComment: > + [STALE_SET] This issue has been automatically marked as stale because it has not had + recent activity. It will be closed in 14 days if no further activity occurs. Thank you + for your contributions. + +unmarkComment: > + [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it opening the future. + +closeComment: > + [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions. + diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/workflows/auto-github-actions.yml b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/auto-github-actions.yml new file mode 100644 index 000000000..9d0fc4ed4 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/auto-github-actions.yml @@ -0,0 +1,12 @@ +name: auto-github-actions +on: [push] +jobs: + check-bats-version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '14' + - run: npm install -g bats + - run: bats -v diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/workflows/check-arduino.yml b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/check-arduino.yml new file mode 100644 index 000000000..3e0d26c9c --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/check-arduino.yml @@ -0,0 +1,28 @@ +name: Check Arduino + +# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows +on: + push: + pull_request: + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Arduino Lint + uses: arduino/arduino-lint-action@v1 + with: + compliance: specification + library-manager: update + # Always use this setting for official repositories. Remove for 3rd party projects. + official: true + project-type: library diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/workflows/report-size-deltas.yml b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/report-size-deltas.yml new file mode 100644 index 000000000..827a89ed1 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/report-size-deltas.yml @@ -0,0 +1,16 @@ +name: Report Size Deltas + +on: + schedule: + - cron: '*/5 * * * *' + +jobs: + report: + runs-on: ubuntu-latest + + steps: + - name: Comment size deltas reports to PRs + uses: arduino/report-size-deltas@v1 + with: + # The name of the workflow artifact created by the "Compile Examples" workflow + sketches-reports-source: sketches-reports diff --git a/software/firmware/source/libraries/WiFiWebServer/.github/workflows/spell-check.yml b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/spell-check.yml new file mode 100644 index 000000000..6ad2f61fa --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.github/workflows/spell-check.yml @@ -0,0 +1,22 @@ +name: Spell Check + +on: + pull_request: + push: + schedule: + # run every Tuesday at 3 AM UTC + - cron: "0 3 * * 2" + workflow_dispatch: + repository_dispatch: + +jobs: + spellcheck: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + # See: https://github.com/codespell-project/actions-codespell/blob/master/README.md + - name: Spell check + uses: codespell-project/actions-codespell@master diff --git a/software/firmware/source/libraries/WiFiWebServer/.gitignore b/software/firmware/source/libraries/WiFiWebServer/.gitignore new file mode 100644 index 000000000..259148fa1 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/software/firmware/source/libraries/WiFiWebServer/CONTRIBUTING.md b/software/firmware/source/libraries/WiFiWebServer/CONTRIBUTING.md new file mode 100644 index 000000000..2e96e98a8 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/CONTRIBUTING.md @@ -0,0 +1,78 @@ +## Contributing to WiFiWebServer + +### Reporting Bugs + +Please report bugs in [WiFiWebServer](https://github.com/khoih-prog/WiFiWebServer/issues/new) if you find them. + +However, before reporting a bug please check through the following: + +* [Existing Open Issues](https://github.com/khoih-prog/WiFiWebServer/issues) - someone might have already encountered this. + +If you don't find anything, please [open a new issue](https://github.com/khoih-prog/WiFiWebServer/issues/new). + +### How to submit a bug report + +Please ensure to specify the following: + +* Arduino IDE version (e.g. 1.8.19) or Platform.io version +* Board Core Version (e.g. Arduino SAMDUE core v1.6.12, ESP8266 core v3.0.2, ArduinoCore-mbed v3.4.1, etc.) +* Contextual information (e.g. what you were trying to achieve) +* Simplest possible steps to reproduce +* Anything that might be relevant in your opinion, such as: + * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` + * Network configuration + + +### Example + +``` +Arduino IDE version: 1.8.19 +RASPBERRY_PI_PICO board +ArduinoCore-mbed v3.4.1 +OS: Ubuntu 20.04 LTS +Linux xy-Inspiron-3593 5.15.0-53-generic #59~20.04.1-Ubuntu SMP Thu Oct 20 15:10:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux + +Context: +I encountered a crash while using this library +Steps to reproduce: +1. ... +2. ... +3. ... +4. ... +``` + +### Additional context + +Add any other context about the problem here. + +--- + +### Sending Feature Requests + +Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. + +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/WiFiWebServer/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. + +--- + +### Sending Pull Requests + +Pull Requests with changes and fixes are also welcome! + +Please use the `astyle` to reformat the updated library code as follows (demo for Ubuntu Linux) + +1. Change directory to the library GitHub + +``` +xy@xy-Inspiron-3593:~$ cd Arduino/xy/WiFiWebServer_GitHub/ +xy@xy-Inspiron-3593:~/Arduino/xy/WiFiWebServer_GitHub$ +``` + +2. Issue astyle command + +``` +xy@xy-Inspiron-3593:~/Arduino/xy/WiFiWebServer_GitHub$ bash utils/restyle.sh +``` + + + diff --git a/software/firmware/source/libraries/WiFiWebServer/LICENSE b/software/firmware/source/libraries/WiFiWebServer/LICENSE new file mode 100644 index 000000000..4a9150f70 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Khoi Hoang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/software/firmware/source/libraries/WiFiWebServer/README.md b/software/firmware/source/libraries/WiFiWebServer/README.md new file mode 100644 index 000000000..6bda42800 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/README.md @@ -0,0 +1,1903 @@ +## WiFiWebServer + +[![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiWebServer.svg?)](https://www.ardu-badge.com/WiFiWebServer) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/WiFiWebServer.svg)](https://github.com/khoih-prog/WiFiWebServer/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/WiFiWebServer/blob/master/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/WiFiWebServer.svg)](http://github.com/khoih-prog/WiFiWebServer/issues) + +Donate to my libraries using BuyMeACoffee + + + + +--- +--- + +## Table of Contents + +* [Why do we need this WiFiWebServer library](#why-do-we-need-this-wifiwebserver-library) + * [Features](#features) + * [Currently Supported Boards](#currently-supported-boards) + * [Currently supported WiFi shields/modules](#currently-supported-wifi-shieldsmodules) +* [Changelog](changelog.md) +* [Prerequisites](#prerequisites) +* [Installation](#installation) + * [Use Arduino Library Manager](#use-arduino-library-manager) + * [Manual Install](#manual-install) + * [VS Code & PlatformIO](#vs-code--platformio) +* [Packages' Patches](#packages-patches) + * [1. For Adafruit nRF52840 and nRF52832 boards](#1-for-adafruit-nRF52840-and-nRF52832-boards) + * [2. For Teensy boards](#2-for-teensy-boards) + * [3. For Arduino SAM DUE boards](#3-for-arduino-sam-due-boards) + * [4. For Arduino SAMD boards](#4-for-arduino-samd-boards) + * [For core version v1.8.10+](#for-core-version-v1810) + * [For core version v1.8.9-](#for-core-version-v189-) + * [5. For Adafruit SAMD boards](#5-for-adafruit-samd-boards) + * [6. For Seeeduino SAMD boards](#6-for-seeeduino-samd-boards) + * [7. For STM32 boards](#7-for-stm32-boards) + * [7.1. For STM32 boards to use LAN8720](#71-for-stm32-boards-to-use-lan8720) + * [7.2. For STM32 boards to use Serial1](#72-for-stm32-boards-to-use-serial1) + * [8. For RP2040-based boards using Earle Philhower arduino-pico core](#8-for-rp2040-based-boards-using-earle-philhower-arduino-pico-core) + * [8.1. To use BOARD_NAME](#81-to-use-board_name) + * [8.2. To avoid compile error relating to microsecondsToClockCycles](#82-to-avoid-compile-error-relating-to-microsecondstoclockcycles) + * [9. For Portenta_H7 boards using Arduino IDE in Linux](#9-for-portenta_h7-boards-using-arduino-ide-in-linux) + * [10. For RTL8720DN boards using AmebaD core](#10-for-rtl8720dn-boards-using-amebad-core) + * [11. For SAMD21 and SAMD51 boards using ArduinoCore-fab-sam core](#11-For-SAMD21-and-SAMD51-boards-using-ArduinoCore-fab-sam-core) + * [12. For Seeeduino RP2040 boards](#12-For-Seeeduino-RP2040-boards) + * [13. For Seeeduino nRF52840 boards](#13-For-Seeeduino-nRF52840-boards) +* [How to configure to use different WiFi Libraries](#how-to-configure-to-use-different-wifi-libraries) + * [1. Modify pin-to-pin connection in WiFiNINA_Generic library](#1-modify-pin-to-pin-connection-in-wifinina_generic-library) + * [2. How to select which built-in WiFi or shield to use](#2-how-to-select-which-built-in-wifi-or-shield-to-use) + * [3. Important](#3-important) +* [Usage](#usage) + * [Class Constructor](#class-constructor) + * [Basic Operations](#basic-operations) + * [Advanced Options](#advanced-options) + * [Other Function Calls](#other-function-calls) +* [Examples](#examples) + * [Original Examples](#original-examples) + * [ 1. AdvancedWebServer](examples/AdvancedWebServer) + * [ 2. AP_SimpleWebServer](examples/AP_SimpleWebServer) + * [ 3. HelloServer](examples/HelloServer) + * [ 4. HelloServer2](examples/HelloServer2) + * [ 5. HttpBasicAuth](examples/HttpBasicAuth) + * [ 6. **MQTTClient_Auth**](examples/MQTTClient_Auth) + * [ 7. **MQTTClient_Basic**](examples/MQTTClient_Basic) + * [ 8. **MQTT_ThingStream**](examples/MQTT_ThingStream) + * [ 9. PostServer](examples/PostServer) + * [10. ScanNetworks](examples/ScanNetworks) + * [11. SimpleAuthentication](examples/SimpleAuthentication) + * [12. UdpNTPClient](examples/UdpNTPClient) + * [13. UdpSendReceive](examples/UdpSendReceive) + * [14. WebClient](examples/WebClient) + * [15. WebClientRepeating](examples/WebClientRepeating) + * [16. WebServer](examples/WebServer) + * [17. WiFiUdpNtpClient](examples/WiFiUdpNtpClient) + * [18. multiFileProject](examples/multiFileProject) **New** + * [HTTP and WebSocket Client New Examples](#http-and-websocket-client-new-examples) + * [ 1. BasicAuthGet](examples/HTTPClient/BasicAuthGet) + * [ 2. CustomHeader](examples/HTTPClient/CustomHeader) + * [ 3. DweetGet](examples/HTTPClient/DweetGet) + * [ 4. DweetPost](examples/HTTPClient/DweetPost) + * [ 5. HueBlink](examples/HTTPClient/HueBlink) + * [ 6. node_test_server](examples/HTTPClient/node_test_server) + * [ 7. PostWithHeaders](examples/HTTPClient/PostWithHeaders) + * [ 8. SimpleDelete](examples/HTTPClient/SimpleDelete) + * [ 9. SimpleGet](examples/HTTPClient/SimpleGet) + * [10. SimpleHTTPExample](examples/HTTPClient/SimpleHTTPExample) + * [11. SimplePost](examples/HTTPClient/SimplePost) + * [12. SimplePut](examples/HTTPClient/SimplePut) + * [13. SimpleWebSocket](examples/HTTPClient/SimpleWebSocket) + * [WiFiMulti Examples](#WiFiMulti-examples) **New** + * [ 1. AdvancedWebServer_WiFiMulti](examples/WiFiMulti/AdvancedWebServer_WiFiMulti) + * [ 2. MQTTClient_Auth_WiFiMulti](examples/WiFiMulti/MQTTClient_Auth_WiFiMulti) + * [ 3. MQTTClient_Basic_WiFiMulti](examples/WiFiMulti/MQTTClient_Basic_WiFiMulti) + * [ 4. MQTT_ThingStream_WiFiMulti](examples/WiFiMulti/MQTT_ThingStream_WiFiMulti) + * [ 5. WiFiUdpNtpClient_WiFiMulti](examples/WiFiMulti/WiFiUdpNtpClient_WiFiMulti) + * [ 6. WebClient_WiFiMulti](examples/WiFiMulti/WebClient_WiFiMulti) + * [ 7. WebClientRepeating_WiFiMulti](examples/WiFiMulti/WebClientRepeating_WiFiMulti) + * [ 8. WebServer_WiFiMulti](examples/WiFiMulti/WebServer_WiFiMulti) +* [Example AdvancedWebServer](#example-advancedwebserver) + * [1. File AdvancedWebServer.ino](#1-file-advancedwebserverino) + * [2. File defines.h](#2-file-definesh) +* [Debug Terminal Output Samples](#debug-terminal-output-samples) + * [1. AdvancedWebServer on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#1-advancedwebserver-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [2. SimpleWebSocket on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#2-simplewebsocket-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [3. SimpleHTTPExample on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#3-simplehttpexample-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [4. DweetPost on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#4-dweetpost-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [5. DweetGet on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#5-dweetget-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [6. MQTTClient_Auth on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#6-mqttclient_auth-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [7. MQTT_ThingStream on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library](#7-mqtt_thingstream-on-arduino-samd_nano_33_iot-using-wifinina_generic-library) + * [8. WebClientRepeating on RASPBERRY_PI_PICO with Custom WiFi using Custom WiFi Library](#8-webclientrepeating-on-raspberry_pi_pico-with-custom-wifi-using-custom-wifi-library) + * [9. AdvancedWebServer on Arduino Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library](#9-advancedwebserver-on-arduino-nano-rp2040-connect-with-wifinina-using-wifinina_generic-library) + * [10. SimpleHTTPExample on ESP32_DEV](#10-simplehttpexample-on-esp32_dev) + * [11. AdvancedWebServer on PORTENTA_H7_M7 with Portenta_H7 WiFi](#11-advancedwebserver-on-portenta_h7_m7-with-portenta_h7-wifi) + * [12. MQTTClient_Auth on ESP32_DEV](#12-mqttclient_auth-on-portenta_h7_m7-with-portenta_h7-wifi) + * [13. WebClientRepeating on ESP32_DEV](#13-webclientrepeating-on-portenta_h7_m7-with-portenta_h7-wifi) + * [14. AdvancedWebServer on ESP32C3_DEV with ESP WiFi](#14-AdvancedWebServer-on-ESP32C3_DEV-with-ESP-WiFi) + * [15. AdvancedWebServer on ESP32S3_DEV with ESP WiFi](#15-AdvancedWebServer-on-ESP32S3_DEV-with-ESP-WiFi) + * [16. AdvancedWebServer_WiFiMulti on Nano RP2040 Connect with WiFiNINA](#16-AdvancedWebServer_WiFiMulti-on-Nano-RP2040-Connect-with-WiFiNINA) + * [17. MQTTClient_Auth_WiFiMulti on Nano RP2040 Connect with WiFiNINA](#17-MQTTClient_Auth_WiFiMulti-on-Nano-RP2040-Connect-with-WiFiNINA) + * [18. WiFiUdpNTPClient_WiFiMulti on Nano RP2040 Connect with WiFiNINA](#18-WiFiUdpNTPClient_WiFiMulti-on-Nano-RP2040-Connect-with-WiFiNINA) + * [19. AdvancedWebServer_WiFiMulti on RASPBERRY_PI_PICO_W](#19-AdvancedWebServer_WiFiMulti-on-RASPBERRY_PI_PICO_W) +* [Debug](#debug) +* [Troubleshooting](#troubleshooting) +* [Issues](#issues) +* [TO DO](#to-do) +* [DONE](#done) +* [Contributions and Thanks](#contributions-and-thanks) +* [Contributing](#contributing) +* [License](#license) +* [Copyright](#copyright) + +--- +--- + +### Why do we need this [WiFiWebServer library](https://github.com/khoih-prog/WiFiWebServer) + +#### Features + +This [WiFiWebServer library](https://github.com/khoih-prog/WiFiWebServer) is a simple yet complete WebServer library for **AVR, Portenta_H7, Teensy, SAM DUE, Arduino SAMD21, Adafruit SAMD21/SAMD51, Adafruit nRF52, ESP32/ESP8266, STM32F/L/H/G/WB/MP1, etc. boards, using WiFi modules/shields (WiFiNINA, WiFi101, U-Blox W101, W102, ESP8266/ESP32-AT, etc.)**. + +The functions are similar and compatible to those of [`ESP32 WebServer`](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) and [`ESP8266WebServer`](https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer) libraries to make life much easier to port sketches from ESP8266/ESP32. + +This [**WiFiWebServer library**](https://github.com/khoih-prog/WiFiWebServer), from v1.1.0, also provides high-level **HTTP and WebSocket Client** with the functions are similar and compatible to those of [**ArduinoHttpClient Library**](https://github.com/arduino-libraries/ArduinoHttpClient) + +The library provides supports to: + +1. WiFi Client, STA and AP mode +2. TCP Server and Client +3. UDP Server and Client +4. HTTP Server and Client +5. HTTP GET and POST requests, provides argument parsing, handles one client at a time. +6. **High-level HTTP (GET, POST, PUT, PATCH, DELETE) and WebSocket Client**. From v1.1.0. + +It is based on and modified from: + +1. [Ivan Grokhotkov's ESP8266WebServer](https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer) +2. [Ivan Grokhotkov's ESP32 WebServer](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) +3. [ArduinoHttpClient Library](https://github.com/arduino-libraries/ArduinoHttpClient) + +The WiFiWebServer class found in `WiFiWebServer.h` header, is a simple web server that knows how to handle HTTP requests such as GET and POST and can only support one client at a time. + +The newly-created WiFiMulti-related examples in [WiFiMulti](https://github.com/khoih-prog/WiFiWebServer/tree/master/examples/WiFiMulti) demonstrate how to use the new [WiFiMulti_Generic](https://github.com/khoih-prog/WiFiMulti_Generic) library to connect to the best of **multi-WiFi APs**, with **auto-checking / auto-reconnecting** features when WiFi connection is lost. + +--- + +#### Currently Supported Boards + +This [**WiFiWebServer library**](https://github.com/khoih-prog/WiFiWebServer) currently supports these following boards: + + 1. SAM DUE + + 2. SAMD21 + + - Arduino: ZERO, MKR, NANO_33_IOT, etc. + - Adafruit SAMD21 (M0) : ItsyBitsy M0, Feather M0, Feather M0 Express, Metro M0 Express, Circuit Playground Express, Trinket M0, PIRkey, HalloWing M0, Crickit M0, etc. + - Seeeduino: LoRaWAN, Zero, Femto M0, XIAO M0, Wio GPS Board, etc. + + 3. SAMD51 + + - Adafruit SAMD51 (M4) : Metro M4, Grand Central M4, ItsyBitsy M4, Feather M44 Express, Trellis M4, Metro M4 AirLift lite, MONSTER M4SK Express, Hallowing EM4 xpress, etc. + - Seeeduino: Wio Terminal, Grove UI Wireless + + 4. Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0, LC) + 5. All STM32F/L/H/G/WB/MP1 with more than 32KB flash memory. + 6. AVR Mega1280, 2560, ADK, 32U4, 16U4, etc. using Arduino, Adafruit or Sparkfun core. To use patch for `ArduinoSTL` library. + + 7. RP2040-based boards, such as **Nano RP2040 Connect**, or **RASPBERRY_PI_PICO_W with CYW43439 WiFi**, using [**Arduino-mbed RP2040** core](https://github.com/arduino/ArduinoCore-mbed) or [**Earle Philhower's arduino-pico** core](https://github.com/earlephilhower/arduino-pico) + + 8. RP2040-based boards, such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, using [**Arduino-mbed RP2040** core](https://github.com/arduino/ArduinoCore-mbed) or [**Earle Philhower's arduino-pico** core](https://github.com/earlephilhower/arduino-pico). + + 9. **ESP32** + + - ESP32 boards, such as `ESP32_DEV`, etc. + - ESP32S2-based boards, such as `ESP32S2_DEV`, `ESP32_S2 Saola`, etc. + - ESP32C3-based boards, such as `ESP32C3_DEV`, etc. **New** + - ESP32_S3 (ESP32S3_DEV, ESP32_S3_BOX, UM TINYS3, UM PROS3, UM FEATHERS3, etc.) **New** + +10. **ESP8266** + +11. **Portenta_H7** + +12. **nRF52 boards**, such as **AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B302_ublox, NINA_B112_ublox, etc.** + +13. Arduino `megaAVR` boards using Arduino core + + - UNO WiFi Rev2 : `WiFi101` **New** + - Nano Every : `WiFiEspAT` **New** + +14. CO2 Ampel + + - SAMD : `WiFi101` **New** + +15. STM32 using `STM32duino Maple` core. **New** + +16. Sparkfun SAMD + +- SAMD21, SAMD51 : `WiFiEspAT` **New** + +17. Industruino SAMD + + - D21G : WiFiEspAT **New** + +18. Tlera Corp STM32WB boards + + - Firefly-WB55RG, Nucleo-WB55RG, etc. : `WiFiEspAT` **New** + +19. Maixduino boards + + - Sipeed Maixduino, etc. : `WiFiEspAT` **New** + +20. `RTL8720DN` using Realtek `AmebaD` core **New** + +21. Arduino, Sparkfun, Adafruit, etc. AVR boards (Mega, 32U4, etc.). To use patch for `ArduinoSTL` library **New** + + - Arduino Uno / Mega / Duemilanove / Diecimila / LilyPad / Mini / Fio / Nano, etc. + - **Arduino ATMega 16U4, 32U4** such as AVR Leonardo, Leonardo ETH, YUN, Esplora, LILYPAD_USB, AVR_ROBOT_CONTROL, AVR_ROBOT_MOTOR, AVR_INDUSTRIAL101, etc. + - **Adafruit ATMega 32U4** such as AVR_FLORA8, AVR_FEATHER32U4, AVR_CIRCUITPLAY, AVR_ITSYBITSY32U4_5V, AVR_ITSYBITSY32U4_3V, AVR_BLUEFRUITMICRO, AVR_ADAFRUIT32U4, etc. + - **Adafruit ATMega 328(P)** such as AVR_METRO, AVR_FEATHER328P, AVR_PROTRINKET5, AVR_PROTRINKET3, AVR_PROTRINKET5FTDI, AVR_PROTRINKET3FTDI, etc. + - **Generic or Sparkfun AVR ATmega_32U4** such as **AVR_MAKEYMAKEY, AVR_PROMICRO, etc.** + - **Generic or Sparkfun AVR ATmega_328(P)** such as **ARDUINO_REDBOT, ARDUINO_AVR_DIGITAL_SANDBOX, etc.** + - **Generic or Sparkfun AVR ATmega128RFA1** such as **ATMEGA128RFA1_DEV_BOARD, etc.** + +--- + +#### Currently supported WiFi shields/modules + +1. WiFiNINA using [`WiFiNINA_Generic library`](https://github.com/khoih-prog/WiFiNINA_Generic) +2. WiFi101 using [`WiFi101_Generic library`](https://github.com/khoih-prog/WiFi101_Generic) **New** +3. u-blox W101, W102 using [`WiFiNINA_Generic library`](https://github.com/khoih-prog/WiFiNINA_Generic) +4. ESP8266-AT command using [`WiFiEspAT library`](https://github.com/jandrassy/WiFiEspAT) +5. ESP8266/ESP32-AT command using [`ESP_AT_Lib library`](https://github.com/khoih-prog/ESP_AT_Lib) +6. Built-in WiFi of ESP32, ESP8266 +7. Built-in WiFi of Portenta_H7 +8. Built-in CYW43439 WiFi of RASPBERRY_PI_PICO_W **New** + +---- +--- + +## Prerequisites + + 1. [`Arduino IDE 1.8.19+` for Arduino](https://github.com/arduino/Arduino). [![GitHub release](https://img.shields.io/github/release/arduino/Arduino.svg)](https://github.com/arduino/Arduino/releases/latest) + 2. [`ESP32 Core 2.0.5+`](https://github.com/espressif/arduino-esp32) for ESP32-based boards. [![Latest release](https://img.shields.io/github/release/espressif/arduino-esp32.svg)](https://github.com/espressif/arduino-esp32/releases/latest/) + 3. [`ESP8266 Core 3.0.2+`](https://github.com/esp8266/Arduino) for ESP8266-based boards. [![Latest release](https://img.shields.io/github/release/esp8266/Arduino.svg)](https://github.com/esp8266/Arduino/releases/latest/). + 4. [`Arduino AVR core 1.8.6+`](https://github.com/arduino/ArduinoCore-avr) for Arduino (Use Arduino Board Manager) for AVR boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-avr.svg)](https://github.com/arduino/ArduinoCore-avr/releases/latest) + 5. [`Teensy core v1.57+`](https://www.pjrc.com/teensy/td_download.html) for Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0) boards. + 6. [`Arduino SAM DUE core v1.6.12+`](https://github.com/arduino/ArduinoCore-sam) for SAM DUE ARM Cortex-M3 boards. + 7. [`Arduino SAMD core 1.8.13+`](https://github.com/arduino/ArduinoCore-samd) for SAMD ARM Cortex-M0+ boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-samd.svg)](https://github.com/arduino/ArduinoCore-samd/releases/latest) + 8. [`Adafruit SAMD core 1.7.11+`](https://github.com/adafruit/ArduinoCore-samd) for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). [![GitHub release](https://img.shields.io/github/release/adafruit/ArduinoCore-samd.svg)](https://github.com/adafruit/ArduinoCore-samd/releases/latest) + 9. [`Seeeduino SAMD core 1.8.3+`](https://github.com/Seeed-Studio/ArduinoCore-samd) for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). [![Latest release](https://img.shields.io/github/release/Seeed-Studio/ArduinoCore-samd.svg)](https://github.com/Seeed-Studio/ArduinoCore-samd/releases/latest/) +10. [`Adafruit nRF52 v1.3.0+`](https://github.com/adafruit/Adafruit_nRF52_Arduino) for nRF52 boards such as Adafruit NRF52840_FEATHER, NRF52832_FEATHER, NRF52840_FEATHER_SENSE, NRF52840_ITSYBITSY, NRF52840_CIRCUITPLAY, NRF52840_CLUE, NRF52840_METRO, NRF52840_PCA10056, PARTICLE_XENON, **NINA_B302_ublox**, etc. [![GitHub release](https://img.shields.io/github/release/adafruit/Adafruit_nRF52_Arduino.svg)](https://github.com/adafruit/Adafruit_nRF52_Arduino/releases/latest) +11. [`Arduino Core for STM32 v2.3.0+`](https://github.com/stm32duino/Arduino_Core_STM32) for STM32F/L/H/G/WB/MP1 boards. [![GitHub release](https://img.shields.io/github/release/stm32duino/Arduino_Core_STM32.svg)](https://github.com/stm32duino/Arduino_Core_STM32/releases/latest) +12. [`Earle Philhower's arduino-pico core v2.6.3+`](https://github.com/earlephilhower/arduino-pico) for RP2040-based boards such as **RASPBERRY_PI_PICO, RASPBERRY_PI_PICO_W, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, etc. [![GitHub release](https://img.shields.io/github/release/earlephilhower/arduino-pico.svg)](https://github.com/earlephilhower/arduino-pico/releases/latest) +13. [`ArduinoCore-mbed mbed_rp2040, mbed_nano, mbed_portenta core 3.4.1+`](https://github.com/arduino/ArduinoCore-mbed) for Arduino (Use Arduino Board Manager) **Portenta_H7, RP2040-based boards, such as Nano_RP2040_Connect, RASPBERRY_PI_PICO**. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-mbed.svg)](https://github.com/arduino/ArduinoCore-mbed/releases/latest) +14. [`Arduino megaAVR core 1.8.7+`](https://github.com/arduino/ArduinoCore-megaavr/releases) for Arduino megaAVR boards such as **UNO_WIFI_REV2, NANO_EVERY** + +15. [`Functional-Vlpp library v1.0.2+`](https://github.com/khoih-prog/functional-vlpp) to use server's lambda function. To install, check [![arduino-library-badge](https://www.ardu-badge.com/badge/Functional-Vlpp.svg?)](https://www.ardu-badge.com/Functional-Vlpp) +16. [`WiFiNINA_Generic library v1.8.15-1+`](https://github.com/khoih-prog/WiFiNINA_Generic) if using WiFiNINA. To install, check [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiNINA_Generic.svg?)](https://www.ardu-badge.com/WiFiNINA_Generic). +17. [`ESP_AT_Lib library v1.4.1+`](https://github.com/khoih-prog/ESP_AT_Lib) if using ESP8288/ESP32-AT shields. To install, check [![arduino-library-badge](https://www.ardu-badge.com/badge/ESP_AT_Lib.svg?)](https://www.ardu-badge.com/ESP_AT_Lib). +18. [`WiFi101_Generic library v1.0.0+`](https://github.com/khoih-prog/WiFi101_Generic) to use SAMD MKR1000, etc. boards with WiFi101 for sending larger data. To install, check [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFi101_Generic.svg?)](https://www.ardu-badge.com/WiFi101_Generic). +19. [`WiFiEspAT library v1.4.1+`](https://github.com/jandrassy/WiFiEspAT) if using ESP8288/ESP32-AT shields. [![GitHub release](https://img.shields.io/github/release/jandrassy/WiFiEspAT.svg)](https://github.com/jandrassy/WiFiEspAT/releases/latest) +20. [`WiFiMulti_Generic library v1.2.2+`](https://github.com/khoih-prog/WiFiMulti_Generic) to use WiFiMulti function. To install, check [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiMulti_Generic.svg?)](https://www.ardu-badge.com/WiFiMulti_Generic). **New** + + +--- + +## Installation + +### Use Arduino Library Manager +The best and easiest way is to use `Arduino Library Manager`. Search for [**WiFiWebServer**](https://github.com/khoih-prog/WiFiWebServer), then select / install the latest version. +You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiWebServer.svg?)](https://www.ardu-badge.com/WiFiWebServer) for more detailed instructions. + +### Manual Install + +1. Navigate to [**WiFiWebServer**](https://github.com/khoih-prog/WiFiWebServer) page. +2. Download the latest release `WiFiWebServer-master.zip`. +3. Extract the zip file to `WiFiWebServer-master` directory +4. Copy the whole `WiFiWebServer-master` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. + +### VS Code & PlatformIO: + +1. Install [VS Code](https://code.visualstudio.com/) +2. Install [PlatformIO](https://platformio.org/platformio-ide) +3. Install [**WiFiWebServer** library](https://registry.platformio.org/libraries/khoih-prog/WiFiWebServer) by using [Library Manager](https://registry.platformio.org/libraries/khoih-prog/WiFiWebServer/installation). Search for **WiFiWebServer** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) +4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html) + +--- +--- + +### Packages' Patches + +#### 1. For Adafruit nRF52840 and nRF52832 boards + +**To be able to compile, run and automatically detect and display BOARD_NAME on nRF52840/nRF52832 boards**, you have to copy the whole [nRF52 Packages_Patches](Packages_Patches/adafruit/hardware/nrf52/1.3.0) directory into Adafruit nRF52 directory (~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0). + +Supposing the Adafruit nRF52 version is 1.3.0. These files must be copied into the directory: +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/boards.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/cores/nRF5/Udp.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/cores/nRF5/Print.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/cores/nRF5/Print.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/variants/NINA_B302_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/variants/NINA_B302_ublox/variant.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/variants/NINA_B112_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/variants/NINA_B112_ublox/variant.cpp` +- **`~/.arduino15/packages/adafruit/hardware/nrf52/1.3.0/cores/nRF5/Udp.h`** + +Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z +These files must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/boards.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/cores/nRF5/Udp.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/cores/nRF5/Print.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/cores/nRF5/Print.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B302_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B302_ublox/variant.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B112_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B112_ublox/variant.cpp` +- **`~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/cores/nRF5/Udp.h`** + +#### 2. For Teensy boards + + **To be able to compile and run on Teensy boards**, you have to copy the files in [**Packages_Patches for Teensy directory**](Packages_Patches/hardware/teensy/avr) into Teensy hardware directory (./arduino-1.8.19/hardware/teensy/avr/boards.txt). + +Supposing the Arduino version is 1.8.19. These files must be copied into the directory: + +- `./arduino-1.8.19/hardware/teensy/avr/boards.txt` +- `./arduino-1.8.19/hardware/teensy/avr/cores/teensy/Stream.h` +- `./arduino-1.8.19/hardware/teensy/avr/cores/teensy3/Stream.h` +- `./arduino-1.8.19/hardware/teensy/avr/cores/teensy4/Stream.h` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +These files must be copied into the directory: + +- `./arduino-x.yy.zz/hardware/teensy/avr/boards.txt` +- `./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy/Stream.h` +- `./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy3/Stream.h` +- `./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy4/Stream.h` + +#### 3. For Arduino SAM DUE boards + + **To be able to compile and run on SAM DUE boards**, you have to copy the whole [SAM DUE](Packages_Patches/arduino/hardware/sam/1.6.12) directory into Arduino sam directory (~/.arduino15/packages/arduino/hardware/sam/1.6.12). + +Supposing the Arduino SAM core version is 1.6.12. This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/sam/1.6.12/platform.txt` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/sam/x.yy.zz/platform.txt` + +#### 4. For Arduino SAMD boards + + ***To be able to compile, run and automatically detect and display BOARD_NAME on Arduino SAMD (Nano-33-IoT, etc) boards***, you have to copy the whole [Arduino SAMD Packages_Patches](Packages_Patches/arduino/hardware/samd/1.8.13) directory into Arduino SAMD directory (~/.arduino15/packages/arduino/hardware/samd/1.8.13). + +#### For core version v1.8.10+ + +Supposing the Arduino SAMD version is 1.8.13. Now only one file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/1.8.13/platform.txt` + +Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz + +This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/x.yy.zz/platform.txt` + +#### For core version v1.8.9- + +Supposing the Arduino SAMD version is 1.8.9. These files must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/1.8.9/platform.txt` +- ***`~/.arduino15/packages/arduino/hardware/samd/1.8.9/cores/arduino/Arduino.h`*** + +Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z + +These files must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/x.yy.z/platform.txt` +- ***`~/.arduino15/packages/arduino/hardware/samd/x.yy.z/cores/arduino/Arduino.h`*** + + This is mandatory to fix the ***notorious Arduino SAMD compiler error***. See [Improve Arduino compatibility with the STL (min and max macro)](https://github.com/arduino/ArduinoCore-samd/pull/399) + +``` + ...\arm-none-eabi\include\c++\7.2.1\bits\stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2 + min(const _Tp& __a, const _Tp& __b, _Compare __comp) +``` + +Whenever the above-mentioned compiler error issue is fixed with the new Arduino SAMD release, you don't need to copy the `Arduino.h` file anymore. + +#### 5. For Adafruit SAMD boards + + ***To be able to compile, run and automatically detect and display BOARD_NAME on Adafruit SAMD (Itsy-Bitsy M4, etc) boards***, you have to copy the whole [Adafruit SAMD Packages_Patches](Packages_Patches/adafruit/hardware/samd/1.7.11) directory into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.11). + +Supposing the Adafruit SAMD core version is 1.7.11. These files must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/samd/1.7.11/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.h` +- `~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.cpp` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +These files must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.h` +- `~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.cpp` + +#### 6. For Seeeduino SAMD boards + + ***To be able to compile, run and automatically detect and display BOARD_NAME on Seeeduino SAMD (XIAO M0, Wio Terminal, etc) boards***, you have to copy the whole [Seeeduino SAMD Packages_Patches](Packages_Patches/Seeeduino/hardware/samd/1.8.3) directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3). + +Supposing the Seeeduino SAMD core version is 1.8.3. These files must be copied into the directory: + +- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/platform.txt` +- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Arduino.h` +- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.h` +- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.cpp` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +These files must be copied into the directory: + +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/platform.txt` +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Arduino.h` +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.h` +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.cpp` + +#### 7. For STM32 boards + +#### 7.1 For STM32 boards to use LAN8720 + +For `Generic STM32F4 series` boards, such as `STM32F407VE`, using `LAN8720`, please use STM32 core `v2.2.0` as breaking core `v2.3.0` creates the compile error. + +--- + +To use LAN8720 on some STM32 boards + +- **Nucleo-144 (F429ZI, NUCLEO_F746NG, NUCLEO_F746ZG, NUCLEO_F756ZG)** +- **Discovery (DISCO_F746NG)** +- **STM32F4 boards (BLACK_F407VE, BLACK_F407VG, BLACK_F407ZE, BLACK_F407ZG, BLACK_F407VE_Mini, DIYMORE_F407VGT, FK407M1)** + +you have to copy the files [stm32f4xx_hal_conf_default.h](Packages_Patches/STM32/hardware/stm32/2.2.0/system/STM32F4xx) and [stm32f7xx_hal_conf_default.h](Packages_Patches/STM32/hardware/stm32/2.2.0/system/STM32F7xx) into STM32 stm32 directory (~/.arduino15/packages/STM32/hardware/stm32/2.2.0/system) to overwrite the old files. + +Supposing the STM32 stm32 core version is 2.2.0. These files must be copied into the directory: + +- `~/.arduino15/packages/STM32/hardware/stm32/2.2.0/system/STM32F4xx/stm32f4xx_hal_conf_default.h` for STM32F4. +- `~/.arduino15/packages/STM32/hardware/stm32/2.2.0/system/STM32F7xx/stm32f7xx_hal_conf_default.h` for Nucleo-144 STM32F7. + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz, +these files must be copied into the corresponding directory: + +- `~/.arduino15/packages/STM32/hardware/stm32/x.yy.zz/system/STM32F4xx/stm32f4xx_hal_conf_default.h` +- `~/.arduino15/packages/STM32/hardware/stm32/x.yy.zz/system/STM32F7xx/stm32f7xx_hal_conf_default.h` + + +#### 7.2 For STM32 boards to use Serial1 + +**To use Serial1 on some STM32 boards without Serial1 definition (Nucleo-144 NUCLEO_F767ZI, Nucleo-64 NUCLEO_L053R8, etc.) boards**, you have to copy the files [STM32 variant.h](Packages_Patches/STM32/hardware/stm32/2.3.0) into STM32 stm32 directory (~/.arduino15/packages/STM32/hardware/stm32/2.3.0). You have to modify the files corresponding to your boards, this is just an illustration how to do. + +Supposing the STM32 stm32 core version is 2.3.0. These files must be copied into the directory: + +- `~/.arduino15/packages/STM32/hardware/stm32/2.3.0/variants/STM32F7xx/F765Z(G-I)T_F767Z(G-I)T_F777ZIT/NUCLEO_F767ZI/variant.h` for Nucleo-144 NUCLEO_F767ZI. +- `~/.arduino15/packages/STM32/hardware/stm32/2.3.0/variants/STM32L0xx/L052R(6-8)T_L053R(6-8)T_L063R8T/NUCLEO_L053R8/variant.h` for Nucleo-64 NUCLEO_L053R8. + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz, +these files must be copied into the corresponding directory: + +- `~/.arduino15/packages/STM32/hardware/stm32/x.yy.zz/variants/STM32F7xx/F765Z(G-I)T_F767Z(G-I)T_F777ZIT/NUCLEO_F767ZI/variant.h` +- `~/.arduino15/packages/STM32/hardware/stm32/x.yy.zz/variants/STM32L0xx/L052R(6-8)T_L053R(6-8)T_L063R8T/NUCLEO_L053R8/variant.h` + +#### 8. For RP2040-based boards using [Earle Philhower arduino-pico core](https://github.com/earlephilhower/arduino-pico) + +#### 8.1 To use BOARD_NAME + + **To be able to automatically detect and display BOARD_NAME on RP2040-based boards (RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040, GENERIC_RP2040, etc) boards**, you have to copy the file [RP2040 platform.txt](Packages_Patches/rp2040/hardware/rp2040/1.4.0) into rp2040 directory (~/.arduino15/packages/rp2040/hardware/rp2040/1.4.0). + +Supposing the rp2040 core version is 1.4.0. This file must be copied into the directory: + +- `~/.arduino15/packages/rp2040/hardware/rp2040/1.4.0/platform.txt` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/rp2040/hardware/rp2040/x.yy.zz/platform.txt` + +With core after v1.5.0, this step is not necessary anymore thanks to the PR [Add -DBOARD_NAME="{build.board}" #136](https://github.com/earlephilhower/arduino-pico/pull/136). + +#### 8.2 To avoid compile error relating to microsecondsToClockCycles + +Some libraries, such as [Adafruit DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library), require the definition of microsecondsToClockCycles(). **To be able to compile and run on RP2040-based boards**, you have to copy the files in [**RP2040 Arduino.h**](Packages_Patches/rp2040/hardware/rp2040/1.4.0/cores/rp2040/Arduino.h) into rp2040 directory (~/.arduino15/packages/rp2040/hardware/rp2040/1.4.0). + +Supposing the rp2040 core version is 1.4.0. This file must be copied to replace: + +- `~/.arduino15/packages/rp2040/hardware/rp2040/1.4.0/cores/rp2040/Arduino.h` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied to replace: + +- `~/.arduino15/packages/rp2040/hardware/rp2040/x.yy.zz/cores/rp2040/Arduino.h` + +With core after v1.5.0, this step is not necessary anymore thanks to the PR [Add defs for compatibility #142](https://github.com/earlephilhower/arduino-pico/pull/142). + + +#### 9. For Portenta_H7 boards using Arduino IDE in Linux + + **To be able to upload firmware to Portenta_H7 using Arduino IDE in Linux (Ubuntu, etc.)**, you have to copy the file [portenta_post_install.sh](Packages_Patches/arduino/hardware/mbed_portenta/3.4.1/portenta_post_install.sh) into mbed_portenta directory (~/.arduino15/packages/arduino/hardware/mbed_portenta/3.4.1/portenta_post_install.sh). + + Then run the following command using `sudo` + +``` +$ cd ~/.arduino15/packages/arduino/hardware/mbed_portenta/3.4.1 +$ chmod 755 portenta_post_install.sh +$ sudo ./portenta_post_install.sh +``` + +This will create the file `/etc/udev/rules.d/49-portenta_h7.rules` as follows: + +``` +# Portenta H7 bootloader mode UDEV rules + +SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="035b", GROUP="plugdev", MODE="0666" +``` + +Supposing the ArduinoCore-mbed core version is 3.4.1. Now only one file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/mbed_portenta/3.4.1/portenta_post_install.sh` + +Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz + +This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/mbed_portenta/x.yy.zz/portenta_post_install.sh` + + +#### 10. For RTL8720DN boards using AmebaD core + + To avoid compile error relating to PROGMEM, you have to copy the file [Realtek AmebaD core pgmspace.h](Packages_Patches/realtek/hardware/AmebaD/3.1.4/cores/ambd/avr/pgmspace.h) into Realtek AmebaD directory (~/.arduino15/packages/realtek/hardware/AmebaD/3.1.4/cores/ambd/avr/pgmspace.h). + +Supposing the Realtek AmebaD core version is 3.1.4. This file must be copied into the directory: + +- `~/.arduino15/packages/realtek/hardware/AmebaD/3.1.4/cores/ambd/avr/pgmspace.h` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/realtek/hardware/AmebaD/x.yy.zz/cores/ambd/avr/pgmspace.h` + + +#### 11. For SAMD21 and SAMD51 boards using ArduinoCore-fab-sam core + + To avoid compile error relating to SAMD21/SAMD51, you have to copy the file [ArduinoCore-fab-sam core pgmspace.h](Packages_Patches/Fab_SAM_Arduino/hardware/samd/1.9.0/boards.txt) into `ArduinoCore-fab-sam` samd directory (~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.9.0/boards.txt). + +Supposing the `ArduinoCore-fab-sam` samd core version is 1.9.0. This file must be copied into the directory: + +- `~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/1.9.0/boards.txt` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/Fab_SAM_Arduino/hardware/samd/x.yy.zz/boards.txt` + + +#### 12. For Seeeduino RP2040 boards + + ***To be able to compile, run and automatically detect and display BOARD_NAME on Seeeduino RP2040 (XIAO RP2040, Wio RP2040 Mini) boards***, you have to copy the whole [Seeeduino RP2040 Packages_Patches](Packages_Patches/Seeeduino/hardware/rp2040/2.7.2) directory into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2). + +Supposing the Seeeduino RP2040 core version is 2.7.2. These files must be copied into the directory: + +- `~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2/boards.txt` +- `~/.arduino15/packages/Seeeduino/hardware/rp2040/2.7.2/variants/Seeed_XIAO_RP2040/pins_arduino.h` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +These files must be copied into the directory: + +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/boards.txt` +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/variants/Seeed_XIAO_RP2040/pins_arduino.h` + + +--- + +#### 13. For Seeeduino nRF52840 boards + +**To be able to compile and run on Xiao nRF52840 boards**, you have to copy the whole [nRF52 1.0.0](Packages_Patches/Seeeduino/hardware/nrf52/1.0.0) directory into Seeeduino nRF52 directory (~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0). + +Supposing the Seeeduino nRF52 version is 1.0.0. These files must be copied into the directory: + +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/platform.txt`** +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/cores/nRF5/Print.h`** +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/cores/nRF5/Print.cpp`** +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/1.0.0/cores/nRF5/Udp.h`** + +Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z +These files must be copied into the directory: + +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/platform.txt`** +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/cores/nRF5/Print.h`** +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/cores/nRF5/Print.cpp`** +- **`~/.arduino15/packages/Seeeduino/hardware/nrf52/x.yy.z/cores/nRF5/Udp.h`** + + +--- +--- + +### How to configure to use different WiFi Libraries + +#### 1. Modify pin-to-pin connection in WiFiNINA_Generic library + +Please change the pin-to-pin connection in `~/Arduino/libraries/src/WiFiNINA_Pinout_Generic.h` to match actual connection if using WiFiNINA with [`WiFiNINA_Generic library`](https://github.com/khoih-prog/WiFiNINA_Generic). + +For example + +```cpp +#elif ( defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || defined(NRF52840_CLUE) || \ + defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + + #warning You have to modify pin usage according to actual connection for NRF528XX + // To define pin out for WiFiNINA here + + //#define PINS_COUNT (60u) + //NINA + #define NINA_GPIO0 (26u) //26 + #define NINA_RESETN (27u) + #define NINA_ACK (28u) + + #define SPIWIFI_SS 24 //PIN_SPI1_SS //24 + #define SPIWIFI_ACK 28 //NINA_ACK //28 + #define SPIWIFI_RESET 27 //NINA_RESETN //27 +``` + +#### 2. How to select which built-in WiFi or shield to use + +- To use W102-based WiFiNINA, define in the sketch: + +```cpp +#define USE_WIFI_NINA true +``` + +- To use built-in WiFi101 or shield: + +```cpp +#define USE_WIFI_NINA false +#define USE_WIFI101 true +``` + +- To use MKR1000 with built-in WiFi101: + +```cpp +// Don't care false or true +#define USE_WIFI_NINA false +``` + +- For boards other than MKR1000, to use another WiFi library with the standard **WiFi.h**, such as [`WiFiEspAT library`](https://github.com/jandrassy/WiFiEspAT) library + +```cpp +#define USE_WIFI_NINA false +``` + +- To use another WiFi library without the standard **WiFi.h** + +For example, WiFi_XYZ library uses **WiFi_XYZ.h** + +```cpp +#define USE_WIFI_NINA false +#define USE_WIFI_CUSTOM true + +... +//Must be placed before #include +#include +#include +``` + +#### 3. Important + +- The **WiFiEsp, WiFi_Link libraries are not supported**. Don't use unless you know how to modify those libraries. +- Requests to support for any custom WiFi library will be ignored. **Use at your own risk**. + +--- +--- + +### Usage + +#### Class Constructor + +```cpp + WiFiWebServer server(80); +``` + +Creates the WiFiWebServer class object. + +*Parameters:* + +host port number: ``int port`` (default is the standard HTTP port 80) + +--- + +#### Basic Operations + +**Starting the server** + +```cpp + void begin(); +``` + +**Handling incoming client requests** + +```cpp + void handleClient(); +``` + +**Disabling the server** + +```cpp + void close(); + void stop(); +``` + +Both methods function the same + +**Client request handlers** + +```cpp + void on(); + void addHandler(); + void onNotFound(); + void onFileUpload(); +``` + +Example: + +```cpp + server.on("/", handlerFunction); + server.onNotFound(handlerFunction); // called when handler is not assigned + server.onFileUpload(handlerFunction); // handle file uploads +``` + +**Sending responses to the client** + +```cpp + void send(); + void send_P(); +``` + +`Parameters:` + +`code` - HTTP response code, can be `200` or `404`, etc. + +`content_type` - HTTP content type, like `"text/plain"` or `"image/png"`, etc. + +`content` - actual content body + +--- + +#### Advanced Options + +**Getting information about request arguments** + +```cpp + const String & arg(); + const String & argName(); + int args(); + bool hasArg(); +``` + +`Function usage:` + +`arg` - get request argument value, use `arg("plain")` to get POST body + +`argName` - get request argument name + +`args` - get arguments count + +`hasArg` - check if argument exist + +**Getting information about request headers** + +```cpp + const String & header(); + const String & headerName(); + const String & hostHeader(); + int headers(); + bool hasHeader(); +``` + +`Function usage:` + +`header` - get request header value + +`headerName` - get request header name + +`hostHeader` - get request host header if available, else empty string + +`headers` - get header count + +`hasHeader` - check if header exist + +**Authentication** + +```cpp + bool authenticate(); + void requestAuthentication(); +``` + +`Function usage:` + +`authenticate` - server authentication, returns true if client is authenticated else false + +`requestAuthentication` - sends authentication failure response to the client + +`Example Usage:` + +```cpp + + if(!server.authenticate(username, password)) + { + server.requestAuthentication(); + } +``` + +--- + +#### Other Function Calls + +```cpp + const String& uri(); // get the current uri + HTTPMethod method(); // get the current method + WiFiClient client(); // get the current client + HTTPUpload& upload(); // get the current upload + + void setContentLength(); // set content length + void sendHeader(); // send HTTP header + void sendContent(); // send content + void sendContent_P(); + void collectHeaders(); // set the request headers to collect + void serveStatic(); + + size_t streamFile(); +``` + +--- +--- + +### Examples: + +#### Original Examples + + 1. [AdvancedWebServer](examples/AdvancedWebServer) + 2. [AP_SimpleWebServer](examples/AP_SimpleWebServer) + 3. [HelloServer](examples/HelloServer) + 4. [HelloServer2](examples/HelloServer2) + 5. [HttpBasicAuth](examples/HttpBasicAuth) + 6. [MQTTClient_Auth](examples/MQTTClient_Auth) + 7. [MQTTClient_Basic](examples/MQTTClient_Basic) + 8. [MQTT_ThingStream](examples/MQTT_ThingStream) + 9. [PostServer](examples/PostServer) +10. [ScanNetworks](examples/ScanNetworks) +11. [SimpleAuthentication](examples/SimpleAuthentication) +12. [UdpNTPClient](examples/UdpNTPClient) +13. [UdpSendReceive](examples/UdpSendReceive) +14. [WebClient](examples/WebClient) +15. [WebClientRepeating](examples/WebClientRepeating) +16. [WebServer](examples/WebServer) +17. [WiFiUdpNtpClient](examples/WiFiUdpNtpClient) +18. [multiFileProject](examples/multiFileProject) **New** + +#### HTTP and WebSocket Client New Examples + + 1. [BasicAuthGet](examples/HTTPClient/BasicAuthGet) + 2. [CustomHeader](examples/HTTPClient/CustomHeader) + 3. [DweetGet](examples/HTTPClient/DweetGet) + 4. [DweetPost](examples/HTTPClient/DweetPost) + 5. [HueBlink](examples/HTTPClient/HueBlink) + 6. [node_test_server](examples/HTTPClient/node_test_server) + 7. [PostWithHeaders](examples/HTTPClient/PostWithHeaders) + 8. [SimpleDelete](examples/HTTPClient/SimpleDelete) + 9. [SimpleGet](examples/HTTPClient/SimpleGet) +10. [SimpleHTTPExample](examples/HTTPClient/SimpleHTTPExample) +11. [SimplePost](examples/HTTPClient/SimplePost) +12. [SimplePut](examples/HTTPClient/SimplePut) +13. [SimpleWebSocket](examples/HTTPClient/SimpleWebSocket) + +#### WiFiMulti Examples + + 1. [AdvancedWebServer_WiFiMulti](examples/WiFiMulti/AdvancedWebServer_WiFiMulti) + 2. [MQTTClient_Auth_WiFiMulti](examples/WiFiMulti/MQTTClient_Auth_WiFiMulti) + 3. [MQTTClient_Basic_WiFiMulti](examples/WiFiMulti/MQTTClient_Basic_WiFiMulti) + 4. [MQTT_ThingStream_WiFiMulti](examples/WiFiMulti/MQTT_ThingStream_WiFiMulti) + 5. [WiFiUdpNtpClient_WiFiMulti](examples/WiFiMulti/WiFiUdpNtpClient_WiFiMulti) + 6. [WebClient_WiFiMulti](examples/WiFiMulti/WebClient_WiFiMulti) + 7. [WebClientRepeating_WiFiMulti](examples/WiFiMulti/WebClientRepeating_WiFiMulti) + 8. [WebServer_WiFiMulti](examples/WiFiMulti/WebServer_WiFiMulti) + +--- + +### Example [AdvancedWebServer](examples/AdvancedWebServer) + +#### 1. File [AdvancedWebServer.ino](examples/AdvancedWebServer/AdvancedWebServer.ino) + + +https://github.com/khoih-prog/WiFiWebServer/blob/9094e545cd4da8007fd321212a27a36edd2d3da2/examples/AdvancedWebServer/AdvancedWebServer.ino#L40-L327 + +#### 2. File [defines.h](examples/AdvancedWebServer/defines.h) + + +https://github.com/khoih-prog/WiFiWebServer/blob/9094e545cd4da8007fd321212a27a36edd2d3da2/examples/AdvancedWebServer/defines.h#L12-L409 + +--- +--- + +### Debug Terminal Output Samples + +#### 1. AdvancedWebServer on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer**](examples/AdvancedWebServer) on **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** + +

+ +

+ +```cpp +Starting AdvancedServer on SAMD_NANO_33_IOT +WiFiWebServer v1.10.1 +[NN] =============================== +[NN] +Used/default SPI pinout: +[NN] MOSI: 11 +[NN] MISO: 12 +[NN] SCK: 13 +[NN] SS: 10 +[NN] =============================== +[NN] +Used/default NINA pinout: +[NN] NINA_GPIO0: 26 +[NN] NINA_RESETN/SPIWIFI_RESET: 27 +[NN] NINA_ACK: 28 +[NN] SS: 10 +[NN] =============================== +[NN] +Actual final pinout to used: +[NN] SPIWIFI_SS: 24 +[NN] SLAVESELECT/SPIWIFI_SS: 24 +[NN] SLAVEREADY/SPIWIFI_ACK/NINA_ACK: 28 +[NN] SLAVERESET/SPIWIFI_RESET/NINA_RESETN: 27 +[NN] =============================== +Connecting to WPA SSID: HueNet1 +HTTP server started @ 192.168.2.118 +H[WIFI] String Len = 0, extend to 2048 +WiFiWebServer::handleClient: New Client +method: GET +url: / +search: +headerName: Host +headerValue: 192.168.2.118 +headerName: Connection +headerValue: keep-alive +headerName: Cache-Control +headerValue: max-age=0 +headerName: DNT +headerValue: 1 +headerName: Upgrade-Insecure-Requests +headerValue: 1 +headerName: User-Agent +headerValue: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 +headerName: Accept +headerValue: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 +headerName: Accept-Encoding +headerValue: gzip, deflate +headerName: Accept-Language +headerValue: en-GB,en-US;q=0.9,en;q=0.8 +headerName: Cookie +headerValue: NINASESSIONID=0 +args: +args count: 0 +args: +args count: 0 +Request: / +Arguments: +Final list of key/value pairs: +WiFiWebServer::_handleRequest handle +WiFiWebServer::send1: len = 330 +content = WiFiNINA SAMD_NANO_33_IOT

Hello from WiFiNINA

on SAMD_NANO_33_IOT

Uptime: 00:00:20

+WiFiWebServer::_prepareHeader sendHeader Conn close +WiFiWebServer::send1: write header = HTTP/1.1 200 OK +Content-Type: text/html +Content-Length: 330 +Connection: close + + +WiFiWebServer::sendContent: Client.write content: WiFiNINA SAMD_NANO_33_IOT

Hello from WiFiNINA

on SAMD_NANO_33_IOT

Uptime: 00:00:20

+WiFiWebServer::_handleRequest OK +WiFiWebServer::handleClient: Client disconnected +WiFiWebServer::handleClient: Don't keepCurrentClient +WiFiWebServer::handleClient: Client disconnected +WiFiWebServer::handleClient: New Client +method: GET +url: /test.svg +search: +headerName: Host +headerValue: 192.168.2.118 +headerName: Connection +headerValue: keep-alive +headerName: User-Agent +headerValue: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 +headerName: DNT +headerValue: 1 +headerName: Accept +headerValue: image/webp,image/apng,image/*,*/*;q=0.8 +headerName: Referer +headerValue: http://192.168.2.118/ +headerName: Accept-Encoding +headerValue: gzip, deflate +headerName: Accept-Language +headerValue: en-GB,en-US;q=0.9,en;q=0.8 +headerName: Cookie +headerValue: NINASESSIONID=0 +args: +args count: 0 +args: +args count: 0 +Request: /test.svg +Arguments: +Final list of key/value pairs: +WiFiWebServer::_handleRequest handle +WiFiWebServer::send1: len = 1946 +content = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +WiFiWebServer::_prepareHeader sendHeader Conn close +WiFiWebServer::send1: write header = HTTP/1.1 200 OK +Content-Type: image/svg+xml +Content-Length: 1946 +Connection: close +``` + +--- + +#### 2. SimpleWebSocket on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The terminal output of **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** running [SimpleWebSocket example](examples/HTTPClient/SimpleWebSocket) to demonstrate newly-added WebSocket Client feature. + +```cpp +Starting SimpleWebSocket on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.98 +SSID: HueNet1, Signal strength (RSSI):-24 dBm +starting WebSocket client +Sending Hello 0 +Sending Hello 1 +Received a message: +0 => Hello from SimpleWebSocket on SAMD_NANO_33_IOT, millis = 6642 +Sending Hello 2 +Received a message: +1 => Hello from SimpleWebSocket on SAMD_NANO_33_IOT, millis = 11648 +Sending Hello 3 +Received a message: +2 => Hello from SimpleWebSocket on SAMD_NANO_33_IOT, millis = 16655 +Sending Hello 4 +Received a message: +3 => Hello from SimpleWebSocket on SAMD_NANO_33_IOT, millis = 21661 +Sending Hello 5 +Received a message: +4 => Hello from SimpleWebSocket on SAMD_NANO_33_IOT, millis = 26668 +Sending Hello 6 +Received a message: +5 => Hello from SimpleWebSocket on SAMD_NANO_33_IOT, millis = 31675 +``` + +--- + +#### 3. SimpleHTTPExample on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The terminal output of **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** running [SimpleHTTPExample example](examples/HTTPClient/SimpleHTTPExample) to demonstrate newly-added HTTP Client feature. + +```cpp +Starting SimpleHTTPExample on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.98 +SSID: HueNet1, Signal strength (RSSI):-21 dBm +startedRequest ok +Got status code: 200 +Content length is: 2263 +Body returned follows: + + `:;;;,` .:;;:. + .;;;;;;;;;;;` :;;;;;;;;;;: TM + `;;;;;;;;;;;;;;;` :;;;;;;;;;;;;;;; + :;;;;;;;;;;;;;;;;;; `;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;;;;;; .;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;:` `;;;;;;;;; ,;;;;;;;;.` .;;;;;;;; + .;;;;;;, :;;;;;;; .;;;;;;; ;;;;;;; + ;;;;;; ;;;;;;; ;;;;;;, ;;;;;;. + ,;;;;; ;;;;;;.;;;;;;` ;;;;;; + ;;;;;. ;;;;;;;;;;;` ``` ;;;;;` + ;;;;; ;;;;;;;;;, ;;; .;;;;; +`;;;;: `;;;;;;;; ;;; ;;;;; +,;;;;` `,,,,,,,, ;;;;;;; .,,;;;,,, ;;;;; +:;;;;` .;;;;;;;; ;;;;;, :;;;;;;;; ;;;;; +:;;;;` .;;;;;;;; `;;;;;; :;;;;;;;; ;;;;; +.;;;;. ;;;;;;;. ;;; ;;;;; + ;;;;; ;;;;;;;;; ;;; ;;;;; + ;;;;; .;;;;;;;;;; ;;; ;;;;;, + ;;;;;; `;;;;;;;;;;;; ;;;;; + `;;;;;, .;;;;;; ;;;;;;; ;;;;;; + ;;;;;;: :;;;;;;. ;;;;;;; ;;;;;; + ;;;;;;;` .;;;;;;;, ;;;;;;;; ;;;;;;;: + ;;;;;;;;;:,:;;;;;;;;;: ;;;;;;;;;;:,;;;;;;;;;; + `;;;;;;;;;;;;;;;;;;;. ;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;; :;;;;;;;;;;;;;;;;: + ,;;;;;;;;;;;;;, ;;;;;;;;;;;;;; + .;;;;;;;;;` ,;;;;;;;;: + + + + + ;;; ;;;;;` ;;;;: .;; ;; ,;;;;;, ;;. `;, ;;;; + ;;; ;;:;;; ;;;;;; .;; ;; ,;;;;;: ;;; `;, ;;;:;; + ,;:; ;; ;; ;; ;; .;; ;; ,;, ;;;,`;, ;; ;; + ;; ;: ;; ;; ;; ;; .;; ;; ,;, ;;;;`;, ;; ;;. + ;: ;; ;;;;;: ;; ;; .;; ;; ,;, ;;`;;;, ;; ;;` + ,;;;;; ;;`;; ;; ;; .;; ;; ,;, ;; ;;;, ;; ;; + ;; ,;, ;; .;; ;;;;;: ;;;;;: ,;;;;;: ;; ;;, ;;;;;; + ;; ;; ;; ;;` ;;;;. `;;;: ,;;;;;, ;; ;;, ;;;; + +``` + +--- + +#### 4. DweetPost on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The terminal output of **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** running [DweetPost example](examples/HTTPClient/DweetPost) to demonstrate newly-added HTTP Client feature. + +```cpp +Starting DweetPost on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.98 +SSID: HueNet1, Signal strength (RSSI):-22 dBm +making POST request +Status code: 200 +Response: {"this":"succeeded","by":"dweeting","the":"dweet","with":{"thing":"Hello-from-SAMD_NANO_33_IOT","created":"2020-11-17T19:55:37.378Z","content":{"sensorValue":581},"transaction":"f968ee5f-35b5-4984-ac3d-34d93fdaddbe"}} +Wait ten seconds + +making POST request +Status code: 200 +Response: {"this":"succeeded","by":"dweeting","the":"dweet","with":{"thing":"Hello-from-SAMD_NANO_33_IOT","created":"2020-11-17T19:55:48.925Z","content":{"sensorValue":570},"transaction":"68ee52e0-22a3-4af2-96cd-aaa53587b314"}} +Wait ten seconds +``` + +--- + +#### 5. DweetGet on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The terminal output of **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** running [DweetGet example](examples/HTTPClient/DweetGet) to demonstrate newly-added HTTP Client feature. + +```cpp +Starting DweetGet on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.98 +SSID: HueNet1, Signal strength (RSSI):-25 dBm +Making GET request +Status code: 200 +Response: {"this":"succeeded","by":"getting","the":"dweets","with":[{"thing":"Hello-from-SAMD_NANO_33_IOT","created":"2020-11-17T20:06:18.905Z","content":{"sensorValue":567}}]} +"sensorValue":567 +Value string: 567 +Actual value: 567 +Wait ten seconds +Making GET request +Status code: 200 +Response: {"this":"succeeded","by":"getting","the":"dweets","with":[{"thing":"Hello-from-SAMD_NANO_33_IOT","created":"2020-11-17T20:06:18.905Z","content":{"sensorValue":567}}]} +"sensorValue":567 +Value string: 567 +Actual value: 567 +Wait ten seconds +``` + +--- + +#### 6. MQTTClient_Auth on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The terminal output of **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** running [MQTTClient_Auth example](examples/MQTTClient_Auth) to demonstrate newly-added MQTT Client feature. + + +```cpp +Starting MQTTClient_Auth on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Please upgrade the firmware +Connecting to WPA SSID: HueNet1 +Connected! IP address: 192.168.2.98 +Attempting MQTT connection to broker.emqx.io...connected +Message Send : MQTT_Pub => Hello from MQTTClient_Auth on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +Message arrived [MQTT_Pub] Hello from MQTTClient_Auth on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +Message Send : MQTT_Pub => Hello from MQTTClient_Auth on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +Message arrived [MQTT_Pub] Hello from MQTTClient_Auth on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +``` + +--- + +#### 7. MQTT_ThingStream on Arduino SAMD_NANO_33_IOT using WiFiNINA_Generic Library + +The terminal output of **SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library** running [MQTT_ThingStream example](examples/MQTT_ThingStream) to demonstrate newly-added MQTT Client feature. + + +```cpp +Start MQTT_ThingStream on SAMD_NANO_33_IOT +Starting MQTTClient_Auth on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Please upgrade the firmware +Connecting to WPA SSID: HueNet1 +Connected! IP address: 192.168.2.98 +*************************************** +STM32_Pub +*************************************** +Attempting MQTT connection to broker.emqx.io +...connected +Published connection message successfully! +Subscribed to: STM32_Sub +MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +MQTT Message Send : STM32_Pub => Hello from MQTT_ThingStream on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library +MQTT Message receive [STM32_Pub] Hello from MQTT_ThingStream on SAMD_NANO_33_IOT with WiFiNINA using WiFiNINA_Generic Library + +``` + +--- + +#### 8. WebClientRepeating on RASPBERRY_PI_PICO with Custom WiFi using Custom WiFi Library + +The terminal output of **RASPBERRY_PI_PICO with Custom WiFi (ESP8266-AT) using Custom WiFi (WiFiEspAT) Library** running [WebClientRepeating example](examples/WebClientRepeating) to demonstrate new RP2040-based board using [**Earle Philhower's arduino-pico** core](https://github.com/earlephilhower/arduino-pico) + +```cpp +Starting WebClientRepeating on RASPBERRY_PI_PICO with Custom WiFi using Custom WiFi Library +WiFiWebServer v1.10.1 +WiFi shield init done +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.76 +SSID: HueNet1, Signal strength (RSSI):-29 dBm +Connecting... +HTTP/1.1 200 OK +Server: nginx/1.4.2 +Date: Wed, 26 May 2021 03:56:08 GMT +Content-Type: text/plain +Content-Length: 2263 +Last-Modified: Wed, 02 Oct 2013 13:46:47 GMT +Connection: close +Vary: Accept-Encoding +ETag: "524c23c7-8d7" +Accept-Ranges: bytes + + + `:;;;,` .:;;:. + .;;;;;;;;;;;` :;;;;;;;;;;: TM + `;;;;;;;;;;;;;;;` :;;;;;;;;;;;;;;; + :;;;;;;;;;;;;;;;;;; `;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;;;;;; .;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;:` `;;;;;;;;; ,;;;;;;;;.` .;;;;;;;; + .;;;;;;, :;;;;;;; .;;;;;;; ;;;;;;; + ;;;;;; ;;;;;;; ;;;;;;, ;;;;;;. + ,;;;;; ;;;;;;.;;;;;;` ;;;;;; + ;;;;;. ;;;;;;;;;;;` ``` ;;;;;` + ;;;;; ;;;;;;;;;, ;;; .;;;;; +`;;;;: `;;;;;;;; ;;; ;;;;; +,;;;;` `,,,,,,,, ;;;;;;; .,,;;;,,, ;;;;; +:;;;;` .;;;;;;;; ;;;;;, :;;;;;;;; ;;;;; +:;;;;` .;;;;;;;; `;;;;;; :;;;;;;;; ;;;;; +.;;;;. ;;;;;;;. ;;; ;;;;; + ;;;;; ;;;;;;;;; ;;; ;;;;; + ;;;;; .;;;;;;;;;; ;;; ;;;;;, + ;;;;;; `;;;;;;;;;;;; ;;;;; + `;;;;;, .;;;;;; ;;;;;;; ;;;;;; + ;;;;;;: :;;;;;;. ;;;;;;; ;;;;;; + ;;;;;;;` .;;;;;;;, ;;;;;;;; ;;;;;;;: + ;;;;;;;;;:,:;;;;;;;;;: ;;;;;;;;;;:,;;;;;;;;;; + `;;;;;;;;;;;;;;;;;;;. ;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;; :;;;;;;;;;;;;;;;;: + ,;;;;;;;;;;;;;, ;;;;;;;;;;;;;; + .;;;;;;;;;` ,;;;;;;;;: + + + + + ;;; ;;;;;` ;;;;: .;; ;; ,;;;;;, ;;. `;, ;;;; + ;;; ;;:;;; ;;;;;; .;; ;; ,;;;;;: ;;; `;, ;;;:;; + ,;:; ;; ;; ;; ;; .;; ;; ,;, ;;;,`;, ;; ;; + ;; ;: ;; ;; ;; ;; .;; ;; ,;, ;;;;`;, ;; ;;. + ;: ;; ;;;;;: ;; ;; .;; ;; ,;, ;;`;;;, ;; ;;` + ,;;;;; ;;`;; ;; ;; .;; ;; ,;, ;; ;;;, ;; ;; + ;; ,;, ;; .;; ;;;;;: ;;;;;: ,;;;;;: ;; ;;, ;;;;;; + ;; ;; ;; ;;` ;;;;. `;;;: ,;;;;;, ;; ;;, ;;;; +``` + +--- + +#### 9. AdvancedWebServer on Arduino Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer**](examples/AdvancedWebServer) on **Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library** + +

+ +

+ + +```cpp +Starting AdvancedServer on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +WiFiWebServer v1.10.1 +Connecting to WPA SSID: HueNet1 +HTTP server started @ 192.168.2.130 +H[WIFI] handleClient: New Client +[WIFI] method: GET +[WIFI] url: / +[WIFI] search: +[WIFI] headerName: Host +[WIFI] headerValue: 192.168.2.130 +[WIFI] headerName: Connection +[WIFI] headerValue: keep-alive +[WIFI] headerName: Cache-Control +[WIFI] headerValue: max-age=0 +[WIFI] headerName: Upgrade-Insecure-Requests +[WIFI] headerValue: 1 +[WIFI] headerName: DNT +[WIFI] headerValue: 1 +[WIFI] headerName: User-Agent +[WIFI] headerValue: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 +[WIFI] headerName: Accept +[WIFI] headerValue: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 +[WIFI] headerName: Referer +[WIFI] headerValue: http://192.168.2.130/ +[WIFI] headerName: Accept-Encoding +[WIFI] headerValue: gzip, deflate +[WIFI] headerName: Accept-Language +[WIFI] headerValue: en-GB,en-US;q=0.9,en;q=0.8,vi;q=0.7 +[WIFI] args: +[WIFI] args count: 0 +[WIFI] args: +[WIFI] args count: 0 +[WIFI] Request: / +[WIFI] Arguments: +[WIFI] Final list of key/value pairs: +[WIFI] _handleRequest handle +[WIFI] send1: len = 392 +[WIFI] content = Nano RP2040 Connect

Hello from Nano RP2040 Connect

running WiFiWebServer

on WiFiNINA using WiFiNINA_Generic Library

Uptime: 0 d 00:00:12

+[WIFI] _prepareHeader sendHeader Conn close +[WIFI] send1: write header = HTTP/1.1 200 OK +Content-Type: text/html +Content-Length: 392 +Connection: close +[WIFI] sendContent: Client.write content: Nano RP2040 Connect

Hello from Nano RP2040 Connect

running WiFiWebServer

on WiFiNINA using WiFiNINA_Generic Library

Uptime: 0 d 00:00:12

+[WIFI] _handleRequest OK +[WIFI] handleClient: Client disconnected +[WIFI] handleClient: Don't keepCurrentClient +[WIFI] handleClient: Client disconnected +[WIFI] handleClient: New Client +[WIFI] method: GET +[WIFI] url: /test.svg +[WIFI] search: +[WIFI] headerName: Host +[WIFI] headerValue: 192.168.2.130 +[WIFI] headerName: Connection +[WIFI] headerValue: keep-alive +[WIFI] headerName: User-Agent +[WIFI] headerValue: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 +[WIFI] headerName: DNT +[WIFI] headerValue: 1 +[WIFI] headerName: Accept +[WIFI] headerValue: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8 +[WIFI] headerName: Referer +[WIFI] headerValue: http://192.168.2.130/ +[WIFI] headerName: Accept-Encoding +[WIFI] headerValue: gzip, deflate +[WIFI] headerName: Accept-Language +[WIFI] headerValue: en-GB,en-US;q=0.9,en;q=0.8,vi;q=0.7 +[WIFI] args: +[WIFI] args count: 0 +[WIFI] args: +[WIFI] args count: 0 +[WIFI] Request: /test.svg +[WIFI] Arguments: +[WIFI] Final list of key/value pairs: +[WIFI] _handleRequest handle +[WIFI] send1: len = 1954 +[WIFI] content = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +[WIFI] _prepareHeader sendHeader Conn close +[WIFI] send1: write header = HTTP/1.1 200 OK +Content-Type: image/svg+xml +Content-Length: 1954 +Connection: close + +``` + +--- + +#### 10. SimpleHTTPExample on ESP32_DEV + +The terminal output of **ESP32_DEV** running [SimpleHTTPExample example](examples/HTTPClient/SimpleHTTPExample) to demonstrate newly-added HTTP Client feature. + +```cpp +Starting SimpleHTTPExample on ESP32_DEV with ESP WiFi using WiFi Library +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.80 +SSID: HueNet1, Signal strength (RSSI):-23 dBm +startedRequest ok +Got status code: 200 +Content length is: 2263 +Body returned follows: + + `:;;;,` .:;;:. + .;;;;;;;;;;;` :;;;;;;;;;;: TM + `;;;;;;;;;;;;;;;` :;;;;;;;;;;;;;;; + :;;;;;;;;;;;;;;;;;; `;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;;;;;; .;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;:` `;;;;;;;;; ,;;;;;;;;.` .;;;;;;;; + .;;;;;;, :;;;;;;; .;;;;;;; ;;;;;;; + ;;;;;; ;;;;;;; ;;;;;;, ;;;;;;. + ,;;;;; ;;;;;;.;;;;;;` ;;;;;; + ;;;;;. ;;;;;;;;;;;` ``` ;;;;;` + ;;;;; ;;;;;;;;;, ;;; .;;;;; +`;;;;: `;;;;;;;; ;;; ;;;;; +,;;;;` `,,,,,,,, ;;;;;;; .,,;;;,,, ;;;;; +:;;;;` .;;;;;;;; ;;;;;, :;;;;;;;; ;;;;; +:;;;;` .;;;;;;;; `;;;;;; :;;;;;;;; ;;;;; +.;;;;. ;;;;;;;. ;;; ;;;;; + ;;;;; ;;;;;;;;; ;;; ;;;;; + ;;;;; .;;;;;;;;;; ;;; ;;;;;, + ;;;;;; `;;;;;;;;;;;; ;;;;; + `;;;;;, .;;;;;; ;;;;;;; ;;;;;; + ;;;;;;: :;;;;;;. ;;;;;;; ;;;;;; + ;;;;;;;` .;;;;;;;, ;;;;;;;; ;;;;;;;: + ;;;;;;;;;:,:;;;;;;;;;: ;;;;;;;;;;:,;;;;;;;;;; + `;;;;;;;;;;;;;;;;;;;. ;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;; :;;;;;;;;;;;;;;;;: + ,;;;;;;;;;;;;;, ;;;;;;;;;;;;;; + .;;;;;;;;;` ,;;;;;;;;: + + + + + ;;; ;;;;;` ;;;;: .;; ;; ,;;;;;, ;;. `;, ;;;; + ;;; ;;:;;; ;;;;;; .;; ;; ,;;;;;: ;;; `;, ;;;:;; + ,;:; ;; ;; ;; ;; .;; ;; ,;, ;;;,`;, ;; ;; + ;; ;: ;; ;; ;; ;; .;; ;; ,;, ;;;;`;, ;; ;;. + ;: ;; ;;;;;: ;; ;; .;; ;; ,;, ;;`;;;, ;; ;;` + ,;;;;; ;;`;; ;; ;; .;; ;; ,;, ;; ;;;, ;; ;; + ;; ,;, ;; .;; ;;;;;: ;;;;;: ,;;;;;: ;; ;;, ;;;;;; + ;; ;; ;; ;;` ;;;;. `;;;: ,;;;;;, ;; ;;, ;;;; +Got status code: 200 +Content length is: 2263 +``` + +--- + + +#### 11. AdvancedWebServer on PORTENTA_H7_M7 with Portenta_H7 WiFi + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer**](examples/AdvancedWebServer) on **PORTENTA_H7_M7 with Portenta_H7 WiFi** + +

+ +

+ + +```cpp +Starting AdvancedServer on PORTENTA_H7_M7 with Portenta_H7 WiFi +WiFiWebServer v1.10.1 +Connecting to WPA SSID: HueNet1 +HTTP server started @ 192.168.2.138 +H[WIFI] String Len = 0, extend to 2048 +HHHHHHHHH HHHHHHH +``` + +--- + +#### 12. MQTTClient_Auth on PORTENTA_H7_M7 with Portenta_H7 WiFi + +The terminal output of **PORTENTA_H7_M7 with Portenta_H7 WiFi** running [MQTTClient_Auth example](examples/MQTTClient_Auth) to demonstrate MQTT Client feature. + + +```cpp +Starting MQTTClient_Auth on PORTENTA_H7_M7 with Portenta_H7 WiFi +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +Connected! IP address: 192.168.2.130 +Attempting MQTT connection to broker.emqx.io...connected +Message Send : MQTT_Pub => Hello from MQTTClient_Auth on PORTENTA_H7_M7 with Portenta_H7 WiFi +Message arrived [MQTT_Pub] Hello from MQTTClient_Auth on PORTENTA_H7_M7 with Portenta_H7 WiFi +Message Send : MQTT_Pub => Hello from MQTTClient_Auth on PORTENTA_H7_M7 with Portenta_H7 WiFi +Message arrived [MQTT_Pub] Hello from MQTTClient_Auth on PORTENTA_H7_M7 with Portenta_H7 WiFi +``` + +--- + + +#### 13. WebClientRepeating on PORTENTA_H7_M7 with Portenta_H7 WiFi + +The terminal output of **PORTENTA_H7_M7 with Portenta_H7 WiFi** running [WebClientRepeating example](examples/WebClientRepeating). + + +```cpp +Starting WebClientRepeating on PORTENTA_H7_M7 with Portenta_H7 WiFi +WiFiWebServer v1.10.1 +Connecting to SSID: HueNet1 +You're connected to the network, IP = 192.168.2.130 +SSID: HueNet1, Signal strength (RSSI):-33 dBm +Connecting... +HTTP/1.1 200 OK +Server: nginx/1.4.2 +Date: Wed, 08 Sep 2021 01:29:41 GMT +Content-Type: text/plain +Content-Length: 2263 +Last-Modified: Wed, 02 Oct 2013 13:46:47 GMT +Connection: close +Vary: Accept-Encoding +ETag: "524c23c7-8d7" +Accept-Ranges: bytes + + + `:;;;,` .:;;:. + .;;;;;;;;;;;` :;;;;;;;;;;: TM + `;;;;;;;;;;;;;;;` :;;;;;;;;;;;;;;; + :;;;;;;;;;;;;;;;;;; `;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;;;;;; .;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;:` `;;;;;;;;; ,;;;;;;;;.` .;;;;;;;; + .;;;;;;, :;;;;;;; .;;;;;;; ;;;;;;; + ;;;;;; ;;;;;;; ;;;;;;, ;;;;;;. + ,;;;;; ;;;;;;.;;;;;;` ;;;;;; + ;;;;;. ;;;;;;;;;;;` ``` ;;;;;` + ;;;;; ;;;;;;;;;, ;;; .;;;;; +`;;;;: `;;;;;;;; ;;; ;;;;; +,;;;;` `,,,,,,,, ;;;;;;; .,,;;;,,, ;;;;; +:;;;;` .;;;;;;;; ;;;;;, :;;;;;;;; ;;;;; +:;;;;` .;;;;;;;; `;;;;;; :;;;;;;;; ;;;;; +.;;;;. ;;;;;;;. ;;; ;;;;; + ;;;;; ;;;;;;;;; ;;; ;;;;; + ;;;;; .;;;;;;;;;; ;;; ;;;;;, + ;;;;;; `;;;;;;;;;;;; ;;;;; + `;;;;;, .;;;;;; ;;;;;;; ;;;;;; + ;;;;;;: :;;;;;;. ;;;;;;; ;;;;;; + ;;;;;;;` .;;;;;;;, ;;;;;;;; ;;;;;;;: + ;;;;;;;;;:,:;;;;;;;;;: ;;;;;;;;;;:,;;;;;;;;;; + `;;;;;;;;;;;;;;;;;;;. ;;;;;;;;;;;;;;;;;;;; + ;;;;;;;;;;;;;;;;; :;;;;;;;;;;;;;;;;: + ,;;;;;;;;;;;;;, ;;;;;;;;;;;;;; + .;;;;;;;;;` ,;;;;;;;;: + + + + + ;;; ;;;;;` ;;;;: .;; ;; ,;;;;;, ;;. `;, ;;;; + ;;; ;;:;;; ;;;;;; .;; ;; ,;;;;;: ;;; `;, ;;;:;; + ,;:; ;; ;; ;; ;; .;; ;; ,;, ;;;,`;, ;; ;; + ;; ;: ;; ;; ;; ;; .;; ;; ,;, ;;;;`;, ;; ;;. + ;: ;; ;;;;;: ;; ;; .;; ;; ,;, ;;`;;;, ;; ;;` + ,;;;;; ;;`;; ;; ;; .;; ;; ,;, ;; ;;;, ;; ;; + ;; ,;, ;; .;; ;;;;;: ;;;;;: ,;;;;;: ;; ;;, ;;;;;; + ;; ;; ;; ;;` ;;;;. `;;;: ,;;;;;, ;; ;;, ;;;; +``` + +--- + + +#### 14. AdvancedWebServer on ESP32C3_DEV with ESP WiFi + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer**](examples/AdvancedWebServer) on **PORTENTA_H7_M7 with Portenta_H7 WiFi** + +

+ +

+ + +```cpp +Starting AdvancedWebServer on ESP32C3_DEV with ESP WiFi using WiFi Library +WiFiWebServer v1.10.1 +Connecting to WPA SSID: HueNet1 +HTTP server started @ 192.168.2.86 +HH +``` + +--- + +#### 15. AdvancedWebServer on ESP32S3_DEV with ESP WiFi + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer**](examples/AdvancedWebServer) on **PORTENTA_H7_M7 with Portenta_H7 WiFi** + +

+ +

+ + +```cpp +Starting AdvancedWebServer on ESP32S3_DEV with ESP WiFi using WiFi Library +WiFiWebServer v1.10.1 +Connecting to WPA SSID: HueNet1 +HTTP server started @ 192.168.2.86 +HH +``` + +--- + +#### 16. AdvancedWebServer_WiFiMulti on Nano RP2040 Connect with WiFiNINA + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer_WiFiMulti**](examples/WiFiMulti/AdvancedWebServer_WiFiMulti) on **Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library** + +

+ +

+ + +```cpp +Starting AdvancedWebServer_WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +WiFiMulti_Generic v1.2.2 +WiFiWebServer v1.10.1 +Connecting WiFi... +WiFi connected, IP address: 192.168.2.113 +You're connected to the network, IP = 192.168.2.113 +SSID: HueNet1, Signal strength (RSSI):-20 dBm +HTTP server started @ 192.168.2.113 +H +``` + +--- + +#### 17. MQTTClient_Auth_WiFiMulti on Nano RP2040 Connect with WiFiNINA + +The following are debug terminal output and screen shot when running example [**MQTTClient_Auth_WiFiMulti**](examples/WiFiMulti/MQTTClient_Auth_WiFiMulti) on **Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library** + +```cpp +Starting MQTTClient_Auth_WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +WiFiMulti_Generic v1.2.2 +WiFiWebServer v1.10.1 +Connecting WiFi... +WiFi connected, IP address: 192.168.2.113 +You're connected to the network, IP = 192.168.2.113 +SSID: HueNet1, Signal strength (RSSI):-18 dBm +Attempting MQTT connection to broker.emqx.io...connected +Published connection message successfully! +Subscribed to: Nano RP2040 ConnectSub +H +MQTT Message Send : Nano RP2040 ConnectPub => Hello from MQTTClient_Auth__WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +Message arrived [Nano RP2040 ConnectPub] Hello from MQTTClient_Auth__WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +HH +MQTT Message Send : Nano RP2040 ConnectPub => Hello from MQTTClient_Auth__WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +H +Message arrived [Nano RP2040 ConnectPub] Hello from MQTTClient_Auth__WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +HH +MQTT Message Send : Nano RP2040 ConnectPub => Hello from MQTTClient_Auth__WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +H +Message arrived [Nano RP2040 ConnectPub] Hello from MQTTClient_Auth__WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +``` + +--- + +#### 18. WiFiUdpNTPClient_WiFiMulti on Nano RP2040 Connect with WiFiNINA + +The following are debug terminal output and screen shot when running example [**WiFiUdpNTPClient_WiFiMulti**](examples/WiFiMulti/WiFiUdpNTPClient_WiFiMulti) on **Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library** + +```cpp +Starting WiFiUdpNTPClient_WiFiMulti on Nano RP2040 Connect with WiFiNINA using WiFiNINA_Generic Library +WiFiMulti_Generic v1.2.2 +WiFiWebServer v1.10.1 +Connecting WiFi... +WiFi connected, IP address: 192.168.2.113 +You're connected to the network, IP = 192.168.2.113 +SSID: HueNet1, Signal strength (RSSI):-17 dBm +Starting connection to server... +Listening on port 2390 +HHH +Packet received +Seconds since Jan 1 1900 = 3869665072 +Unix time = 1660676272 +The UTC time is 18:57:52 +HH +Packet received +Seconds since Jan 1 1900 = 3869665132 +Unix time = 1660676332 +The UTC time is 18:58:52 +HH +``` + +--- + +#### 19. AdvancedWebServer_WiFiMulti on RASPBERRY_PI_PICO_W + +The following are debug terminal output and screen shot when running example [**AdvancedWebServer_WiFiMulti**](examples/WiFiMulti/AdvancedWebServer_WiFiMulti) on **RASPBERRY_PI_PICO_W with CYW43439 WiFi** + +

+ +

+ + +```cpp +Starting AdvancedWebServer_WiFiMulti on RASPBERRY_PI_PICO_W with RP2040W CYW43439 WiFi +WiFiMulti_Generic v1.2.2 +WiFiWebServer v1.10.1 +Connecting WiFi... + +WiFi connected, IP address: 192.168.2.180 +You're connected to the network, IP = 192.168.2.180 +SSID: HueNet1, Signal strength (RSSI):0 dBm +HTTP server started @ 192.168.2.180 +HH +``` + +--- +--- + +### Debug + +Debug is enabled by default on Serial. Debug Level from 0 to 4. To disable, change the _WIFI_LOGLEVEL_ and _WIFININA_LOGLEVEL_ to 0 + +```cpp +// Use this to output debug msgs to Serial +#define DEBUG_WIFI_WEBSERVER_PORT Serial + +// Debug Level from 0 to 4 +#define _WIFI_LOGLEVEL_ 1 +#define _WIFININA_LOGLEVEL_ 1 +``` + +--- + +## Troubleshooting + +If you get compilation errors, more often than not, you may need to install a newer version of the board's core, applying Libraries' Patches, Packages' Patches or this library latest version. + +--- +--- + +### Issues + +Submit issues to: [WiFiWebServer issues](https://github.com/khoih-prog/WiFiWebServer/issues) + +--- + +### TO DO + +1. Bug Searching and Killing +2. Add SSL/TLS Client and Server support +3. Support more types of boards using WiFiNINA and other WiFi shields. +4. Add support to megaAVR boards using [MegaCoreX core](https://github.com/MCUdude/MegaCoreX) + + +### DONE + + 1. Add support to Arduino SAMD21, Adafruit SAMD21/SAMD51, Seeeduino SAMD21/SAMD51. + 2. Add support to nRF52. + 3. Add support to SAM DUE. + 4. Add support to all STM32F/L/H/G/WB/MP1. + 5. Add support to WiFiNINA using [**WiFiNINA_Generic library**](https://github.com/khoih-prog/WiFiNINA_Generic). + 6. Add support to [**ESP_AT_Lib library**](https://github.com/khoih-prog/ESP_AT_Lib). + 7. Add support to [`WiFi101 library`](https://www.arduino.cc/en/Reference/WiFi101). + 8. Add support to [`WiFiEspAT library`](https://github.com/jandrassy/WiFiEspAT). + 9. Add support to PROGMEM-related commands, such as sendContent_P() and send_P() +10. Add **High-level HTTP (GET, POST, PUT, PATCH, DELETE) and WebSocket Client** +11. Add support to **Arduino Nano RP2040 Connect** using [**Arduino mbed OS for Nano boards**](https://github.com/arduino/ArduinoCore-mbed). +12. Add support to RP2040-based boards, such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, using [**Earle Philhower's arduino-pico** core](https://github.com/earlephilhower/arduino-pico). +13. Add support to RP2040-based boards, such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, using [**Arduino-mbed mbed_rp2040** core](https://github.com/arduino/ArduinoCore-mbed). +14. Add support to **Portenta_H7 boards**, using [**Arduino-mbed mbed_portenta** core](https://github.com/arduino/ArduinoCore-mbed). +15. Reduce usage of Arduino String with std::string +16. Optimize library code and examples by using **reference-passing instead of value-passing**. +17. Add support to new **ESP32-S3** and **ESP32_C3** +18. Add support to megaAVR boards (UNO_WIFI_REV2, NANO_EVERY) using [Arduino megaAVR core](https://github.com/arduino/ArduinoCore-megaavr) +19. Rewrite library and add example [multiFileProject](examples/multiFileProject) to demo for multiple-file project to fix `multiple-definitions` linker error +20. Add [WiFiMulti_Generic](https://github.com/khoih-prog/WiFiMulti_Generic) library support +21. Add many WiFiMulti-related examples in [WiFiMulti](https://github.com/khoih-prog/WiFiWebServer/tree/master/examples/WiFiMulti) +22. Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi with [**Earle Philhower's arduino-pico core** v2.4.0+](https://github.com/earlephilhower/arduino-pico) +23. Better workaround for RP2040W `WiFi.status()` bug using `ping()` to local gateway +24. Add new features, such as `CORS` +25. Use `allman astyle` and add `utils` +26. Using new [`WiFi101_Generic library`](https://github.com/khoih-prog/WiFi101_Generic) for sending larger data + +--- +--- + +## Contributions and Thanks + +1. Based on and modified from [**Ivan Grokhotkov's ESP8266WebServer**](https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer) +2. Thanks to good work of [Miguel Alexandre Wisintainer](https://github.com/tcpipchip) for initiating, inspriring, working with, developing, debugging and testing. Without that, support to nRF52, especially **U-Blox B302 running as nRF52840 and U-Blox B112 running as nRF52832**, has never been started and finished. See [u-blox nina b](https://github.com/khoih-prog/WiFiNINA_Generic/issues/1) +3. [Adrian McEwen](https://github.com/amcewen) for [HttpClient Library](https://github.com/amcewen/HttpClient) on which the [ArduinoHttpClient Library](https://github.com/arduino-libraries/ArduinoHttpClient) and this [EthernetWebServer library](https://github.com/khoih-prog/EthernetWebServer) are relied. +4. [RQnet](https://github.com/RQnet) to report issue [Decoding Error. two times called urlDecode in Parsing-impl.h. #17](https://github.com/khoih-prog/WiFiWebServer/issues/17) leading to version v1.6.3 to fix the decoding error bug when using special `&` in data fields. + + + + + + + + +
igrr
⭐️⭐️ Ivan Grokhotkov

amcewen
⭐️ Adrian McEwen

tcpipchip
⭐️ Miguel Wisintainer

RQnet
RQnet

+ +--- + +## Contributing + +If you want to contribute to this project: +- Report bugs and errors +- Ask for enhancements +- Create issues and pull requests +- Tell other people about this library + +--- + +### License + +- The library is licensed under [MIT](https://github.com/khoih-prog/WiFiWebServer/blob/master/LICENSE) + +--- + +## Copyright + +Copyright (c) 2020- Khoi Hoang + + diff --git a/software/firmware/source/libraries/WiFiWebServer/changelog.md b/software/firmware/source/libraries/WiFiWebServer/changelog.md new file mode 100644 index 000000000..68c489a3d --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/changelog.md @@ -0,0 +1,247 @@ +## WiFiWebServer Changelog + +[![arduino-library-badge](https://www.ardu-badge.com/badge/WiFiWebServer.svg?)](https://www.ardu-badge.com/WiFiWebServer) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/WiFiWebServer.svg)](https://github.com/khoih-prog/WiFiWebServer/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/WiFiWebServer/blob/master/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/WiFiWebServer.svg)](http://github.com/khoih-prog/WiFiWebServer/issues) + +Donate to my libraries using BuyMeACoffee + + + + +--- +--- + +## Table of Contents + +* [Changelog](#changelog) + * [Releases v1.10.1](#releases-v1101) + * [Releases v1.10.0](#releases-v1100) + * [Releases v1.9.5](#releases-v195) + * [Releases v1.9.4](#releases-v194) + * [Releases v1.9.3](#releases-v193) + * [Releases v1.9.2](#releases-v192) + * [Releases v1.9.1](#releases-v191) + * [Releases v1.9.0](#releases-v190) + * [Releases v1.8.0](#releases-v180) + * [Releases v1.7.0](#releases-v170) + * [Releases v1.6.3](#releases-v163) + * [Releases v1.6.2](#releases-v162) + * [Releases v1.6.1](#releases-v161) + * [Releases v1.6.0](#releases-v160) + * [Releases v1.5.4](#releases-v154) + * [Releases v1.5.3](#releases-v153) + * [Releases v1.5.2](#releases-v152) + * [Releases v1.5.1](#releases-v151) + * [Major Releases v1.5.0](#major-releases-v150) + * [Releases v1.4.2](#releases-v142) + * [Releases v1.4.1](#releases-v141) + * [Major Releases v1.4.0](#major-releases-v140) + * [Releases v1.3.1](#releases-v131) + * [Releases v1.3.0](#releases-v130) + * [Major Releases v1.2.0](#major-releases-v120) + * [Releases v1.1.1](#releases-v111) + * [Major Releases v1.1.0](#major-releases-v110) + * [Releases v1.0.7](#releases-v107) + * [Releases v1.0.6](#releases-v106) + * [Releases v1.0.5](#releases-v105) + * [Releases v1.0.4](#releases-v104) + * [Releases v1.0.3](#releases-v103) + * [Releases v1.0.2](#releases-v102) + * [Releases v1.0.1](#releases-v101) + * [Initial Releases v1.0.0](#initial-releases-v100) + +--- +--- + +## Changelog + +### Releases v1.10.1 + +1. Using new [`WiFi101_Generic library`](https://github.com/khoih-prog/WiFi101_Generic) for sending larger data +2. Update `Packages' Patches` + +### Releases v1.10.0 + +1. Add new features, such as `CORS`, etc. +2. Update code and examples +3. Use `allman astyle` and add `utils` +4. Update `Packages' Patches` + +### Releases v1.9.5 + +1. Restore support to Teensy, etc. +2. Fix bug in examples + +### Releases v1.9.4 + +1. Restore support to ESP32 and ESP8266. Check [Problem using ESP8266 nodeMCU 1.0 #20](https://github.com/khoih-prog/WiFiWebServer/issues/20) + +### Releases v1.9.3 + +1. Better workaround for RP2040W `WiFi.status()` bug using `ping()` to local gateway +2. Update WiFiMulti-related examples + +### Releases v1.9.2 + +1. Workaround for RP2040W WiFi.status() bug +2. Update WiFiMulti-related examples + +### Releases v1.9.1 + +1. Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW43439 WiFi + +### Releases v1.9.0 + +1. Add support to RASPBERRY_PI_PICO_W using CYW43439 WiFi +2. Update `Packages' Patches` + +### Releases v1.8.0 + +1. Add [WiFiMulti_Generic](https://github.com/khoih-prog/WiFiMulti_Generic) library support +2. Add many WiFiMulti-related examples in [WiFiMulti](https://github.com/khoih-prog/WiFiWebServer/tree/master/examples/WiFiMulti) +3. Update `Packages' Patches` + +### Releases v1.7.0 + +1. Fix issue with Portenta_H7 core v2.7.2+. Check [[Portenta_H7] WiFi WebServer extremely slow from core v2.7.2 - v3.0.1 #441](https://github.com/arduino/ArduinoCore-mbed/issues/441) +2. Rewrite to avoid `multiple-definitions` linker error for multiple-file project +3. Add example [multiFileProject](examples/multiFileProject) to demo how to avoid `multiple-definitions` linker error for multiple-file project +4. Update `Packages' Patches` + +### Releases v1.6.3 + +1. Fix decoding error bug when using special `&` in data fields. Check [Decoding Error. two times called urlDecode in Parsing-impl.h. #17](https://github.com/khoih-prog/WiFiWebServer/issues/17) +2. Update `Packages' Patches` + + +### Releases v1.6.2 + +1. Add support to megaAVR boards (UNO_WIFI_REV2, NANO_EVERY) using [Arduino megaAVR core](https://github.com/arduino/ArduinoCore-megaavr) +2. Update `Packages' Patches` + +### Releases v1.6.1 + +1. Fix issue in v1.6.0 + +### Releases v1.6.0 + +1. Add support to new ESP32-S3 and ESP32_C3 +2. Update `Packages' Patches` + +### Releases v1.5.4 + +1. Fix libb64 `fallthrough` compile warning +2. Fix bug not supporting ESP32/ESP8266 boards. +3. Fix bug for WiFi other than WiFiNINA + +### Releases v1.5.3 + +1. Fix authenticate issue caused by libb64 + +### Releases v1.5.2 + +1. Fix wrong http status header bug. Check [fix for wrong http status header #42](https://github.com/khoih-prog/EthernetWebServer/pull/42) + +### Releases v1.5.1 + +1. Fix bug related to String in library and examples + +### Major Releases v1.5.0 + +1. Reduce usage of Arduino String with std::string +2. Optimize library code and examples by using **reference-passing instead of value-passing**. +3. Update `Packages' Patches` +4. Add more ESP32/ESP8266 supporting code + +### Releases v1.4.2 + +1. Update `platform.ini` and `library.json` to use original `khoih-prog` instead of `khoih.prog` after PIO fix +2. Update `Packages' Patches` + +### Releases v1.4.1 + +1. Change option for PIO `lib_compat_mode` from default `soft` to `strict` to minimize compile error in crosss-platform +2. Update `Packages' Patches` for many boards + +### Major Releases v1.4.0 + +1. Add support to **Portenta_H7** using [**Arduino mbed_portenta core**](https://github.com/arduino/ArduinoCore-mbed). +2. Update `Packages' Patches` for **Portenta_H7** + +### Releases v1.3.1 + +1. Add support to ESP32/ESP8266 to use in some rare use-cases +2. Update `Packages' Patches` +3. Split `changelog.md` from `README.md` + +### Releases v1.3.0 + +1. Add support to Adafruit nRF52 core v0.22.0+ +2. Add support to Raytac MDBT50Q_RX Dongle +3. Update `Packages' Patches` + +### Major Releases v1.2.0 + +1. Add support to **Arduino Nano RP2040 Connect** using [**Arduino mbed OS for Nano boards**](https://github.com/arduino/ArduinoCore-mbed). +2. Add support to RP2040-based boards, such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, using [**Earle Philhower's arduino-pico** v1.5.1+ core](https://github.com/earlephilhower/arduino-pico). +3. Add support to RP2040-based boards, such as **RASPBERRY_PI_PICO, ADAFRUIT_FEATHER_RP2040 and GENERIC_RP2040**, using [**Arduino-mbed RP2040** v2.1.0+ core](https://github.com/arduino/ArduinoCore-mbed). +4. Add to examples the support to ESP32-AT/ESP8266-AT WiFi, using [`WiFiEspAT library`](https://github.com/jandrassy/WiFiEspAT) +5. Fix bugs +6. Update `Packages' Patches` + +### Releases v1.1.1 + +1. Clean-up all compiler warnings possible. +2. Add MQTT examples +3. Add Version String + +### Major Releases v1.1.0 + +1. Add high-level **HTTP and WebSockets Client** by merging [ArduinoHttpClient Library](https://github.com/arduino-libraries/ArduinoHttpClient) +2. Add many more examples for HTTP and WebSockets Client. + +### Releases v1.0.7 + +1. Add support to **PROGMEM-related commands, such as sendContent_P() and send_P()** +2. Update Platform.ini to support **PlatformIO 5.x owner-based dependency declaration.** +3. Clean up code. +4. Update examples. + +#### Releases v1.0.6 + +1. Add support to all **STM32F/L/H/G/WB/MP1** boards. +2. Add support to **Seeeduino SAMD21/SAMD51** boards. +3. Restructure examples. Clean-up code. + +#### Releases v1.0.5 + +1. Fix bug not closing client and releasing socket exposed in NINA Firmware v1.4.0. +2. Enhance examples. + +#### Releases v1.0.4 + +1. Add support to boards using **WiFi101 built-in or shield**. For example MKR1000, Teensy, Mega, etc.. +2. Support any future custom WiFi library that meets the no-compiling-error requirements. + +#### Releases v1.0.3 + +1. Add support to **nRF52** boards, such as **AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B302_ublox, etc.** + +#### Releases v1.0.2 + +1. Add support to **SAM51 (Itsy-Bitsy M4, Metro M4, Grand Central M4, Feather M4 Express, etc.) and SAM DUE**. + +#### Releases v1.0.1 + +1. Use new [`WiFiNINA_Generic library`](https://github.com/khoih-prog/WiFiNINA_Generic) to provide support to many more boards running WiFiNINA. + +The original WiFiNINA library only supports **Nano-33 IoT**, Arduino MKR WiFi 1010, Arduino MKR VIDOR 4000 and Arduino UNO WiFi Rev.2. + +#### Initial Releases v1.0.0 + +This is simple yet complete WebServer library for `AVR Mega, Teensy, SAMD21, STM32, etc.` boards running WiFi modules/shields (WiFiNINA U-Blox W101, W102, etc.). **The functions are similar and compatible to ESP8266/ESP32 WebServer libraries** to make life much easier to port sketches from ESP8266/ESP32. + + diff --git a/software/firmware/source/libraries/WiFiWebServer/keywords.txt b/software/firmware/source/libraries/WiFiWebServer/keywords.txt new file mode 100644 index 000000000..e2ee7b54b --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/keywords.txt @@ -0,0 +1,211 @@ +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################### +# WiFiWebServer +####################### + +WiFiWebServer KEYWORD1 +HTTPMethod KEYWORD1 +HTTPUploadStatus KEYWORD1 +HTTPClientStatus KEYWORD1 +HTTPAuthMethod KEYWORD1 +HTTPUpload KEYWORD1 +RequestHandler KEYWORD1 +FunctionRequestHandler KEYWORD1 +StaticRequestHandler KEYWORD1 +WiFi_RingBuffer KEYWORD1 + +WWString KEYWORD1 + +####################### +# WiFiHttpClient +####################### + +WiFiHttpClient KEYWORD1 + +########################## +# WiFiWebSocketClient +########################## + +WiFiWebSocketClient KEYWORD1 + +########################## +# WiFiURLEncoderClass +########################## + +WiFiURLEncoderClass KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################### +# WiFiWebServer +####################### + +begin KEYWORD2 +handleClient KEYWORD2 +close KEYWORD2 +stop KEYWORD2 +authenticate KEYWORD2 +requestAuthentication KEYWORD2 +on KEYWORD2 +addHandler KEYWORD2 +onNotFound KEYWORD2 +onFileUpload KEYWORD2 +uri KEYWORD2 +method KEYWORD2 +client KEYWORD2 +upload KEYWORD2 +arg KEYWORD2 +argName KEYWORD2 +args KEYWORD2 +hasArg KEYWORD2 +collectHeaders KEYWORD2 +header KEYWORD2 +headerName KEYWORD2 +headers KEYWORD2 +hasHeader KEYWORD2 +hostHeader KEYWORD2 +send KEYWORD2 +send_P KEYWORD2 +void sendContent_P KEYWORD2 +setContentLength KEYWORD2 +sendHeader KEYWORD2 +sendContent KEYWORD2 +urlDecode KEYWORD2 +streamFile KEYWORD2 + +####################### +# Parsing-impl +####################### +readBytesWithTimeout KEYWORD2 +_parseRequest KEYWORD2 +_collectHeader KEYWORD2 +_parseArguments KEYWORD2 +_uploadWriteByte KEYWORD2 +_uploadReadByte KEYWORD2 +_parseForm KEYWORD2 +urlDecode KEYWORD2 +_parseFormUploadAborted KEYWORD2 + +####################### +# RequestHandler +####################### +canHandle KEYWORD2 +canUpload KEYWORD2 +handle KEYWORD2 +upload KEYWORD2 +next KEYWORD2 +getContentType KEYWORD2 + +####################### +# WiFi_RingBuffer +####################### +reset KEYWORD2 +init KEYWORD2 +push KEYWORD2 +getPos KEYWORD2 +endsWith KEYWORD2 +getStr KEYWORD2 +getStrN KEYWORD2 + +####################### +# WiFiHttpClient +####################### + +beginRequest KEYWORD2 +endRequest KEYWORD2 +beginBody KEYWORD2 +get KEYWORD2 +post KEYWORD2 +put KEYWORD2 +patch KEYWORD2 +del KEYWORD2 +startRequest KEYWORD2 +sendHeader KEYWORD2 +sendBasicAuth KEYWORD2 +responseStatusCode KEYWORD2 +headerAvailable KEYWORD2 +readHeaderValue KEYWORD2 +readHeader KEYWORD2 +skipResponseHeaders KEYWORD2 +endOfHeadersReached KEYWORD2 +endOfBodyReached KEYWORD2 +endOfStream KEYWORD2 +completed KEYWORD2 +contentLength KEYWORD2 +isResponseChunked KEYWORD2 +responseBody KEYWORD2 +connectionKeepAlive KEYWORD2 +noDefaultRequestHeaders KEYWORD2 +write KEYWORD2 +available KEYWORD2 +read KEYWORD2 +peek KEYWORD2 +flush KEYWORD2 +connect KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +httpResponseTimeout KEYWORD2 +setHttpResponseTimeout KEYWORD2 + +########################## +# WiFiWebSocketClient +########################## + +begin KEYWORD2 +beginMessage KEYWORD2 +endMessage KEYWORD2 +parseMessage KEYWORD2 +messageType KEYWORD2 +isFinal KEYWORD2 +readString KEYWORD2 +ping KEYWORD2 +write KEYWORD2 +available KEYWORD2 +read KEYWORD2 +peek KEYWORD2 + +########################## +# WiFiURLEncoderClass +########################## + +encode KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + +WIFI_WEBSERVER_VERSION LITERAL1 +WIFI_WEBSERVER_VERSION_MAJOR LITERAL1 +WIFI_WEBSERVER_VERSION_MINOR LITERAL1 +WIFI_WEBSERVER_VERSION_PATCH LITERAL1 +WIFI_WEBSERVER_VERSION_INT LITERAL1 + +HTTP_ANY LITERAL1 +HTTP_GET LITERAL1 +HTTP_HEAD LITERAL1 +HTTP_POST LITERAL1 +HTTP_PUT LITERAL1 +HTTP_PATCH LITERAL1 +HTTP_DELETE LITERAL1 +HTTP_OPTIONS LITERAL1 + +UPLOAD_FILE_START LITERAL1 +UPLOAD_FILE_WRITE LITERAL1 +UPLOAD_FILE_END LITERAL1 +UPLOAD_FILE_ABORTED LITERAL1 + +HC_NONE LITERAL1 +HC_WAIT_READ LITERAL1 +HC_WAIT_CLOSE LITERAL1 + +BASIC_AUTH LITERAL1 +DIGEST_AUTH LITERAL1 + +AUTHORIZATION_HEADER LITERAL1 + diff --git a/software/firmware/source/libraries/WiFiWebServer/library.json b/software/firmware/source/libraries/WiFiWebServer/library.json new file mode 100644 index 000000000..f79f2a11a --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/library.json @@ -0,0 +1,69 @@ +{ + "name": "WiFiWebServer", + "version": "1.10.1", + "keywords": "wifi, wi-fi, WebServer, WiFiNINA, WiFi101, ESP32, Portenta-H7, SAM-DUE, SAMD, STM32, nRF52, rpi-pico, rp2040, HTTP-Client, WebSocket-Client, server, client, websocket, wifi-multi, mega-avr", + "description": "Simple WiFiWebServer, HTTP Client and WebSocket Client library for AVR Mega, megaAVR, Portenta_H7, Teensy, SAM DUE, SAMD21, SAMD51, STM32F/L/H/G/WB/MP1, nRF52, RP2040-based (Nano-RP2040-Connect, RASPBERRY_PI_PICO, RASPBERRY_PI_PICO_W, ESP32/ESP8266, etc.) boards using WiFi, such as WiFiNINA, WiFi101, CYW43439, U-Blox W101, W102, ESP8266/ESP32-AT modules/shields, with functions similar to those of ESP8266/ESP32 WebServer libraries", + "authors": + { + "name": "Khoi Hoang", + "url": "https://github.com/khoih-prog", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "https://github.com/khoih-prog/WiFiWebServer" + }, + "homepage": "https://github.com/khoih-prog/WiFiWebServer", + "export": { + "exclude": [ + "linux", + "extras", + "tests" + ] + }, + "dependencies": + [ + { + "owner": "khoih-prog", + "name": "WiFiNINA_Generic", + "version": ">=1.8.15-1", + "platforms": ["*"] + }, + { + "owner": "khoih-prog", + "name": "WiFi101_Generic", + "version": ">=1.0.0", + "platforms": ["*"] + }, + { + "owner": "khoih-prog", + "name": "Functional-Vlpp", + "version": ">=1.0.2", + "platforms": ["*"] + }, + { + "owner": "khoih-prog", + "name": "WiFiMulti_Generic", + "version": ">=1.2.2", + "platforms": ["*"] + }, + { + "owner": "khoih-prog", + "name": "ESP_AT_Lib", + "version": ">=1.4.1", + "platforms": ["*"] + }, + { + "owner": "jandrassy", + "name": "WiFiEspAT", + "version": ">=1.4.1", + "platforms": ["*"] + } + ], + "license": "MIT", + "frameworks": "*", + "platforms": "*", + "examples": "examples/*/*/*.ino", + "headers": ["WiFiWebServer.h", "WiFiWebServer.hpp", "WiFiHttpClient.h"] +} diff --git a/software/firmware/source/libraries/WiFiWebServer/library.properties b/software/firmware/source/libraries/WiFiWebServer/library.properties new file mode 100644 index 000000000..ac7ea6071 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/library.properties @@ -0,0 +1,12 @@ +name=WiFiWebServer +version=1.10.1 +author=Khoi Hoang +license=MIT +maintainer=Khoi Hoang +sentence=Simple WiFiWebServer, HTTP Client and WebSocket Client library for AVR Mega, megaAVR, Portenta_H7, Teensy, SAM DUE, SAMD21, SAMD51, STM32F/L/H/G/WB/MP1, nRF52, RP2040-based (Nano-RP2040-Connect, RASPBERRY_PI_PICO, RASPBERRY_PI_PICO_W, ESP32/ESP8266, etc.) boards using WiFi, such as WiFiNINA, WiFi101, CYW43439, U-Blox W101, W102, ESP8266/ESP32-AT modules/shields, with functions similar to those of ESP8266/ESP32 WebServer libraries. +paragraph=The WebServer supports HTTP GET and POST requests, provides argument parsing, handles one client at a time. It now provides HTTP Client and WebSocket Client. Now using WiFiMulti_Generic library +category=Communication +url=https://github.com/khoih-prog/WiFiWebServer +architectures=* +depends=Functional-Vlpp, WiFiNINA_Generic, WiFi101_Generic, ESP_AT_Lib, WiFiEspAT, WiFiMulti_Generic +includes=WiFiWebServer.h, WiFiWebServer.hpp, WiFiHttpClient.h diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer.png new file mode 100644 index 000000000..eb05b090b Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_ESP32_C3.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_ESP32_C3.png new file mode 100644 index 000000000..bfb33238d Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_ESP32_C3.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_ESP32_S3.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_ESP32_S3.png new file mode 100644 index 000000000..cb28e3716 Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_ESP32_S3.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_NanoRP2040Connect.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_NanoRP2040Connect.png new file mode 100644 index 000000000..a71307a50 Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_NanoRP2040Connect.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_Portenta_H7.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_Portenta_H7.png new file mode 100644 index 000000000..0750965bd Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_Portenta_H7.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_WiFiMulti_NanoRP2040Connect.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_WiFiMulti_NanoRP2040Connect.png new file mode 100644 index 000000000..cb4150be5 Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_WiFiMulti_NanoRP2040Connect.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_WiFiMulti_RP2040W.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_WiFiMulti_RP2040W.png new file mode 100644 index 000000000..cbf3e7a94 Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_WiFiMulti_RP2040W.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_v1.0.6.png b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_v1.0.6.png new file mode 100644 index 000000000..6cee39d2e Binary files /dev/null and b/software/firmware/source/libraries/WiFiWebServer/pics/AdvancedWebServer_v1.0.6.png differ diff --git a/software/firmware/source/libraries/WiFiWebServer/platformio/platformio.ini b/software/firmware/source/libraries/WiFiWebServer/platformio/platformio.ini new file mode 100644 index 000000000..d4c36f533 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/platformio/platformio.ini @@ -0,0 +1,374 @@ +;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] +; ============================================================ +; chose environment: +; ESP8266 +; ESP32 +; SAMD +; NRF52 +; STM32 +; ============================================================ +;default_envs = ESP8266 +;default_envs = ESP32 +default_envs = SAMD +;default_envs = NRF52 +;default_envs = STM32 +;default_envs = pico +;default_envs = portenta_h7_m7 +;default_envs = portenta_h7_m4 + +[env] +; ============================================================ +; Serial configuration +; choose upload speed, serial-monitor speed +; ============================================================ +upload_speed = 921600 +;upload_port = COM11 +;monitor_speed = 9600 +;monitor_port = COM11 + +; Checks for the compatibility with frameworks and dev/platforms +lib_compat_mode = strict +lib_ldf_mode = chain+ +;lib_ldf_mode = deep+ + +lib_deps = +; PlatformIO 4.x +; Functional-Vlpp@>=1.0.2 +; WiFiNINA_Generic@>=1.8.15-1 +; WiFi101_Generic@>=1.0.0 +; WiFiMulti_Generic@>=1.2.2 +; ESP_AT_Lib@>=1.4.1 +; PlatformIO 5.x + khoih-prog/Functional-Vlpp@>=1.0.2 + khoih-prog/WiFiNINA_Generic@>=1.8.15-1 + khoih-prog/WiFi101_Generic@>=1.0.0 + khoih-prog/WiFiMulti_Generic@>=1.2.2 + khoih-prog/ESP_AT_Lib@>=1.4.1 + +build_flags = +; set your debug output (default=Serial) +; -D DEBUG_ESP_PORT=Serial +; comment the following line to enable WiFi debugging +; -D NDEBUG + +[env:ESP8266] +platform = espressif8266 +framework = arduino +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = gen4iod +;board = huzzah +;board = oak +;board = esp_wroom_02 +;board = espduino +;board = espectro +;board = espino +;board = espresso_lite_v1 +;board = espresso_lite_v2 +;board = esp12e +;board = esp01_1m +;board = esp01 +;board = esp07 +;board = esp8285 +;board = heltec_wifi_kit_8 +;board = inventone +;board = nodemcu +board = nodemcuv2 +;board = modwifi +;board = phoenix_v1 +;board = phoenix_v2 +;board = sparkfunBlynk +;board = thing +;board = thingdev +;board = esp210 +;board = espinotee +;board = d1 +;board = d1_mini +;board = d1_mini_lite +;board = d1_mini_pro +;board = wifi_slot +;board = wifiduino +;board = wifinfo +;board = wio_link +;board = wio_node +;board = xinabox_cw01 +;board = esp32doit-devkit-v1 + +[env:ESP32] +platform = espressif32 +framework = arduino +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = esp32cam +;board = alksesp32 +;board = featheresp32 +;board = espea32 +;board = bpi-bit +;board = d-duino-32 +board = esp32doit-devkit-v1 +;board = pocket_32 +;board = fm-devkit +;board = pico32 +;board = esp32-evb +;board = esp32-gateway +;board = esp32-pro +;board = esp32-poe +;board = oroca_edubot +;board = onehorse32dev +;board = lopy +;board = lopy4 +;board = wesp32 +;board = esp32thing +;board = sparkfun_lora_gateway_1-channel +;board = ttgo-lora32-v1 +;board = ttgo-t-beam +;board = turta_iot_node +;board = lolin_d32 +;board = lolin_d32_pro +;board = lolin32 +;board = wemosbat +;board = widora-air +;board = xinabox_cw02 +;board = iotbusio +;board = iotbusproteus +;board = nina_w10 + +[env:SAMD] +platform = atmelsam +framework = arduino +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ +; ============================================================ +; Board configuration Adafruit SAMD +; ============================================================ + +;board = adafruit_feather_m0 +;board = adafruit_feather_m0_express +;board = adafruit_metro_m0 +;board = adafruit_circuitplayground_m0 +;board = adafruit_gemma_m0 +;board = adafruit_trinket_m0 +;board = adafruit_itsybitsy_m0 +;board = adafruit_pirkey +;board = adafruit_hallowing +;board = adafruit_crickit_m0 +;board = adafruit_metro_m4 +;board = adafruit_grandcentral_m4 +board = adafruit_itsybitsy_m4 +;board = adafruit_feather_m4 +;board = adafruit_trellis_m4 +;board = adafruit_pyportal_m4 +;board = adafruit_pyportal_m4_titano +;board = adafruit_pybadge_m4 +;board = adafruit_metro_m4_airliftlite +;board = adafruit_pygamer_m4 +;board = adafruit_pygamer_advance_m4 +;board = adafruit_pybadge_airlift_m4 +;board = adafruit_monster_m4sk +;board = adafruit_hallowing_m4 + +; ============================================================ +; Board configuration Arduino SAMD and SAM +; ============================================================ + +;board = arduino_zero_edbg +;board = arduino_zero_native +;board = mkr1000 +;board = mkrzero +;board = mkrwifi1010 +;board = nano_33_iot +;board = mkrfox1200 +;board = mkrwan1300 +;board = mkrwan1310 +;board = mkrgsm1400 +;board = mkrnb1500 +;board = mkrvidor4000 +;board = adafruit_circuitplayground_m0 +;board = mzero_pro_bl_dbg +;board = mzero_pro_bl +;board = mzero_bl +;board = tian +;board = tian_cons +;board = arduino_due_x_dbg +;board = arduino_due_x + +; ============================================================ +; Board configuration Seeeduino SAMD +; ============================================================ + +;board = seeed_wio_terminal +;board = Seeed_femto_m0 +;board = seeed_XIAO_m0 +;board = Wio_Lite_MG126 +;board = WioGPS +;board = zero +;board = rolawan +;board = seeed_grove_ui_wireless + + +[env:NRF52] +platform = nordicnrf52 +framework = arduino +; ============================================================ +; Board configuration Adafruit nRF52 +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = feather52832 +board = feather52840 +;board = feather52840sense +;board = itsybitsy52840 +;board = cplaynrf52840 +;board = cluenrf52840 +;board = metro52840 +;board = pca10056 +;board = particle_xenon +;board = mdbt50qrx +;board = ninab302 +;board = ninab112 + +[env:STM32] +platform = ststm32 +framework = arduino + +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ + +; ============================================================ +; Board configuration Nucleo-144 +; ============================================================ + +;board = nucleo_f207zg +;board = nucleo_f429zi +;board = nucleo_f746zg +;board = nucleo_f756zg +;board = nucleo_f767zi +;board = nucleo_h743zi +;board = nucleo_l496zg +;board = nucleo_l496zg-p +;board = nucleo_l4r5zi +;board = nucleo_l4r5zi-p + +; ============================================================ +; Board configuration Nucleo-64 +; ============================================================ + +;board = nucleo_f030r8 +;board = nucleo_f072rb + +;board = nucleo_f091rc +;board = nucleo_f103rb +;board = nucleo_f302r8 +;board = nucleo_f303re +;board = nucleo_f401re +;board = nucleo_f411re +;board = nucleo_f446re +;board = nucleo_g071rb +;board = nucleo_g431rb +;board = nucleo_g474re +;board = nucleo_l053r8 +;board = nucleo_l073rz +;board = nucleo_l152re +;board = nucleo_l433rc_p +;board = nucleo_l452re +;board = nucleo_l452re-p +;board = nucleo_l476rg +;board = pnucleo_wb55rg + +; ============================================================ +; Board configuration Nucleo-32 +; ============================================================ + +;board = nucleo_f031k6 +;board = nucleo_l031k6 +;board = nucleo_l412kb +;board = nucleo_l432lc +;board = nucleo_f303k8 +;board = nucleo_g431kb + +; ============================================================ +; Board configuration Discovery Boards +; ============================================================ + +;board = disco_f030r8 +;board = disco_f072rb +;board = disco_f030r8 +;board = disco_f100rb +;board = disco_f407vg +;board = disco_f413zh +;board = disco_f746ng +;board = disco_g0316 +;board = disco_l475vg_iot +;board = disco_f072cz-lrwan1 + +; ============================================================ +; Board configuration STM32MP1 Boards +; ============================================================ + +;board = stm32mp157a-dk1 +;board = stm32mp157c-dk2 + +; ============================================================ +; Board configuration Generic Boards +; ============================================================ + +;board = bluepill_f103c6 +;board = bluepill_f103c8 +;board = blackpill_f103c8 +;board = stm32f103cx +;board = stm32f103rx +;board = stm32f103tx +;board = stm32f103vx +;board = stm32f103zx +;board = stm32f103zet6 +;board = maplemini_f103cb +;board = blackpill_f303cc +;board = black_f407ve +;board = black_f407vg +;board = black_f407ze +;board = black_f407zg +;board = blue_f407ve_mini +;board = blackpill_f401cc +;board = blackpill_f411ce +;board = coreboard_f401rc +;board = feather_f405 + +[env:portenta_h7_m7] +platform = ststm32 +board = portenta_h7_m7 +framework = arduino + +[env:portenta_h7_m4] +platform = ststm32 +board = portenta_h7_m4 +framework = arduino + +[env:pico] +; ============================================================ +; Just a sample +; You have to research and fix if there is issue +; ============================================================ +platform = raspberrypi +board = pico +framework = arduino +upload_protocol = picotool + +; ============================================================ +; Board configuration Many more Boards to be filled +; ============================================================ + diff --git a/software/firmware/source/libraries/WiFiWebServer/src/Parsing-impl.h b/software/firmware/source/libraries/WiFiWebServer/src/Parsing-impl.h new file mode 100644 index 000000000..f926a1108 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/Parsing-impl.h @@ -0,0 +1,1473 @@ +/********************************************************************************************************************************* + Parsing-impl.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + **********************************************************************************************************************************/ + +#pragma once + +#ifndef Parsing_Impl_H +#define Parsing_Impl_H + +#include + +#include "WiFiWebServer.hpp" + +#ifndef WEBSERVER_MAX_POST_ARGS + #define WEBSERVER_MAX_POST_ARGS 32 +#endif + +//////////////////////////////////////// + +// KH +#if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +static bool readBytesWithTimeout(WiFiClient& client, size_t maxLength, String& data, int timeout_ms) +{ + if (!data.reserve(maxLength + 1)) + return false; + + data[0] = 0; // data.clear()?? + + while (data.length() < maxLength) + { + int tries = timeout_ms; + size_t avail; + + while (!(avail = client.available()) && tries--) + delay(1); + + if (!avail) + break; + + if (data.length() + avail > maxLength) + avail = maxLength - data.length(); + + while (avail--) + data += (char)client.read(); + } + + return data.length() == maxLength; +} + +//////////////////////////////////////// + +#else + +//////////////////////////////////////// + +#if !WIFI_USE_PORTENTA_H7 + +static char* readBytesWithTimeout(WiFiClient& client, size_t maxLength, size_t& dataLength, int timeout_ms) +{ + char *buf = nullptr; + dataLength = 0; + + while (dataLength < maxLength) + { + int tries = timeout_ms; + size_t newLength; + + while (!(newLength = client.available()) && tries--) + delay(1); + + if (!newLength) + { + break; + } + + if (!buf) + { + buf = (char *) malloc(newLength + 1); + + if (!buf) + { + return nullptr; + } + } + else + { + char* newBuf = (char *) realloc(buf, dataLength + newLength + 1); + + if (!newBuf) + { + free(buf); + return nullptr; + } + + buf = newBuf; + } + + client.readBytes(buf + dataLength, newLength); + dataLength += newLength; + buf[dataLength] = '\0'; + } + + return buf; +} +#endif // #if !WIFI_USE_PORTENTA_H7 + +#endif // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +bool WiFiWebServer::_parseRequest(WiFiClient& client) +{ + // Read the first line of HTTP request + String req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + //reset header value + for (int i = 0; i < _headerKeysCount; ++i) + { + _currentHeaders[i].value = String(); + } + + // 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) + { + WS_LOGDEBUG1(F("_parseRequest: Invalid request: "), req); + return false; + } + + String methodStr = req.substring(0, addr_start); + String url = req.substring(addr_start + 1, addr_end); + String versionEnd = req.substring(addr_end + 8); + _currentVersion = atoi(versionEnd.c_str()); + String searchStr = ""; + int hasSearch = url.indexOf('?'); + + if (hasSearch != -1) + { + searchStr = url.substring(hasSearch + 1); + url = url.substring(0, hasSearch); + } + + _currentUri = url; + _chunked = false; + + HTTPMethod method = HTTP_GET; + +#if USE_NEW_WEBSERVER_VERSION + + if (methodStr == "HEAD") + { + method = HTTP_HEAD; + } + else if (methodStr == "POST") + { + method = HTTP_POST; + } + else if (methodStr == "DELETE") + { + method = HTTP_DELETE; + } + else if (methodStr == "OPTIONS") + { + method = HTTP_OPTIONS; + } + else if (methodStr == "PUT") + { + method = HTTP_PUT; + } + else if (methodStr == "PATCH") + { + method = HTTP_PATCH; + } + +#else // #if USE_NEW_WEBSERVER_VERSION + + if (methodStr == "POST") + { + method = HTTP_POST; + } + else if (methodStr == "DELETE") + { + + method = HTTP_DELETE; + } + else if (methodStr == "OPTIONS") + { + method = HTTP_OPTIONS; + } + else if (methodStr == "PUT") + { + method = HTTP_PUT; + } + else if (methodStr == "PATCH") + { + method = HTTP_PATCH; + } + +#endif // #if USE_NEW_WEBSERVER_VERSION + + _currentMethod = method; + + WS_LOGDEBUG1(F("method: "), methodStr); + WS_LOGDEBUG1(F("url: "), url); + WS_LOGDEBUG1(F("search: "), searchStr); + + //attach handler + RequestHandler* handler = nullptr; + + for (handler = _firstHandler; handler; handler = handler->next()) + { + if (handler->canHandle(_currentMethod, _currentUri)) + break; + } + + _currentHandler = handler; + + String formData; + + // below is needed only when POST type request + if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE) + { + String boundaryStr; + String headerName; + String headerValue; + + bool isForm = false; + bool isEncoded = false; + uint32_t contentLength = 0; + + //parse headers + while (1) + { + req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (req == "") + break;//no more headers + + int headerDiv = req.indexOf(':'); + + if (headerDiv == -1) + { + break; + } + + headerName = req.substring(0, headerDiv); + headerValue = req.substring(headerDiv + 1); + + headerValue.trim(); + _collectHeader(headerName.c_str(), headerValue.c_str()); + + WS_LOGDEBUG1(F("headerName: "), headerName); + WS_LOGDEBUG1(F("headerValue: "), headerValue); + + if (headerName.equalsIgnoreCase("Content-Type")) + { +#if (ESP32 || ESP8266) + using namespace mime_esp; +#else + using namespace mime; +#endif + + if (headerValue.startsWith(mimeTable[txt].mimeType)) + { + isForm = false; + } + else if (headerValue.startsWith("application/x-www-form-urlencoded")) + { + isForm = false; + isEncoded = true; + } + else if (headerValue.startsWith("multipart/")) + { + boundaryStr = headerValue.substring(headerValue.indexOf('=') + 1); + boundaryStr.replace("\"", ""); + isForm = true; + } + } + else if (headerName.equalsIgnoreCase("Content-Length")) + { + contentLength = headerValue.toInt(); + _clientContentLength = headerValue.toInt(); + } + else if (headerName.equalsIgnoreCase("Host")) + { + _hostHeader = headerValue; + } + } + + //KH +#if USE_NEW_WEBSERVER_VERSION + + //////////////////////////////////////// + + String plainBuf; + + if ( !isForm + && // read content into plainBuf + ( !readBytesWithTimeout(client, contentLength, plainBuf, HTTP_MAX_POST_WAIT) + || (plainBuf.length() < contentLength) + ) + ) + { + return false; + } + + if (isEncoded) + { + // isEncoded => !isForm => plainBuf is not empty + // add plainBuf in search str + if (searchStr.length()) + searchStr += '&'; + + searchStr += plainBuf; + } + + // parse searchStr for key/value pairs + _parseArguments(searchStr); + + if (!isForm) + { + if (contentLength) + { + // add key=value: plain={body} (post json or other data) + RequestArgument& arg = _currentArgs[_currentArgCount++]; + arg.key = F("plain"); + arg.value = plainBuf; + } + } + else + { + // isForm is true + // here: content is not yet read (plainBuf is still empty) + if (!_parseForm(client, boundaryStr, contentLength)) + { + return false; + } + } + } + else + { + String headerName; + String headerValue; + + //parse headers + while (1) + { + req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (req == "") + break;//no more headers + + int headerDiv = req.indexOf(':'); + + if (headerDiv == -1) + { + break; + } + + headerName = req.substring(0, headerDiv); + headerValue = req.substring(headerDiv + 2); + _collectHeader(headerName.c_str(), headerValue.c_str()); + + WS_LOGDEBUG1(F("headerName:"), headerName); + WS_LOGDEBUG1(F("headerValue:"), headerValue); + + if (headerName.equalsIgnoreCase(F("Host"))) + { + _hostHeader = headerValue; + } + } + + _parseArguments(searchStr); + } + + client.flush(); + + WS_LOGDEBUG1(F("Request:"), url); + WS_LOGDEBUG1(F("Arguments:"), searchStr); + WS_LOGDEBUG (F("Final list of key/value pairs:")); + + for (int i = 0; i < _currentArgCount; i++) + { + WS_LOGDEBUG1("key:", _currentArgs[i].key.c_str()); + WS_LOGDEBUG1("value:", _currentArgs[i].value.c_str()); + } + + return true; + + //////////////////////////////////////// + +#else // #if USE_NEW_WEBSERVER_VERSION + + //////////////////////////////////////// + + (void) isEncoded; + + if (isForm) + { + _parseArguments(searchStr); + + if (!_parseForm(client, boundaryStr, contentLength)) + { + return false; + } + } + } + else + { + String headerName; + String headerValue; + + //parse headers + while (1) + { + req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (req == "") + break;//no more headers + + int headerDiv = req.indexOf(':'); + + if (headerDiv == -1) + { + break; + } + + headerName = req.substring(0, headerDiv); + headerValue = req.substring(headerDiv + 2); + _collectHeader(headerName.c_str(), headerValue.c_str()); + + WS_LOGDEBUG1(F("headerName: "), headerName); + WS_LOGDEBUG1(F("headerValue: "), headerValue); + + if (headerName == "Host") + { + _hostHeader = headerValue; + } + } + + _parseArguments(searchStr); + } + + client.flush(); + + WS_LOGDEBUG1(F("Request: "), url); + WS_LOGDEBUG1(F("Arguments: "), searchStr); + + return true; + +#endif // #if USE_NEW_WEBSERVER_VERSION +} + +//////////////////////////////////////// + +bool WiFiWebServer::_collectHeader(const char* headerName, const char* headerValue) +{ + for (int i = 0; i < _headerKeysCount; i++) + { + if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) + { + _currentHeaders[i].value = headerValue; + return true; + } + } + + return false; +} + +//////////////////////////////////////// + +#if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +struct storeArgHandler +{ + void operator() (String& key, String& value, const String& data, int equal_index, int pos, int key_end_pos, + int next_index) + { + key = WiFiWebServer::urlDecode(data.substring(pos, key_end_pos)); + + if ((equal_index != -1) && ((equal_index < next_index - 1) || (next_index == -1))) + value = WiFiWebServer::urlDecode(data.substring(equal_index + 1, next_index)); + } +}; + +//////////////////////////////////////// + +struct nullArgHandler +{ + void operator() (String& key, String& value, const String& data, int equal_index, int pos, int key_end_pos, + int next_index) + { + (void)key; + (void)value; + (void)data; + (void)equal_index; + (void)pos; + (void)key_end_pos; + (void)next_index; + // do nothing + } +}; + +//////////////////////////////////////// + +void WiFiWebServer::_parseArguments(const String& data) +{ + if (_currentArgs) + delete[] _currentArgs; + + _currentArgs = 0; + + if (data.length() == 0) + { + _currentArgCount = 0; + _currentArgs = new RequestArgument[1]; + + return; + } + + _currentArgCount = 1; + + for (int i = 0; i < (int)data.length(); ) + { + i = data.indexOf('&', i); + + if (i == -1) + break; + + ++i; + ++_currentArgCount; + } + + _currentArgs = new RequestArgument[_currentArgCount + 1]; + + int pos = 0; + int iarg; + + for (iarg = 0; iarg < _currentArgCount;) + { + int equal_sign_index = data.indexOf('=', pos); + int next_arg_index = data.indexOf('&', pos); + + if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) + { + if (next_arg_index == -1) + break; + + pos = next_arg_index + 1; + + continue; + } + + RequestArgument& arg = _currentArgs[iarg]; + arg.key = urlDecode(data.substring(pos, equal_sign_index)); + arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index)); + + ++iarg; + + if (next_arg_index == -1) + break; + + pos = next_arg_index + 1; + } + + _currentArgCount = iarg; +} + +//////////////////////////////////////// + +void WiFiWebServer::_uploadWriteByte(uint8_t b) +{ + if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN) + { + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + + _currentUpload->totalSize += _currentUpload->currentSize; + _currentUpload->currentSize = 0; + } + + _currentUpload->buf[_currentUpload->currentSize++] = b; +} + +//////////////////////////////////////// + +int WiFiWebServer::_uploadReadByte(WiFiClient& client) +{ + int res = client.read(); + + if (res < 0) + { + // keep trying until you either read a valid byte or timeout + unsigned long startMillis = millis(); + unsigned long timeoutIntervalMillis = client.getTimeout(); + bool timedOut = false; + + for (;;) + { + if (!client.connected()) + return -1; + + // loosely modeled after blinkWithoutDelay pattern + while (!timedOut && !client.available() && client.connected()) + { + delay(2); + timedOut = (millis() - startMillis) >= timeoutIntervalMillis; + } + + res = client.read(); + + if (res >= 0) + { + return res; // exit on a valid read + } + + timedOut = (millis() - startMillis) >= timeoutIntervalMillis; + + if (timedOut) + { + return res; // exit on a timeout + } + } + } + + return res; +} + +//////////////////////////////////////// + +#else // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +void WiFiWebServer::_parseArguments(const String& data) +{ + + WS_LOGDEBUG1(F("args: "), data); + + if (_currentArgs) + delete[] _currentArgs; + + _currentArgs = 0; + + if (data.length() == 0) + { + _currentArgCount = 0; + _currentArgs = new RequestArgument[1]; + + return; + } + + _currentArgCount = 1; + + for (int i = 0; i < (int)data.length(); ) + { + i = data.indexOf('&', i); + + if (i == -1) + break; + + ++i; + ++_currentArgCount; + } + + WS_LOGDEBUG1(F("args count: "), _currentArgCount); + + _currentArgs = new RequestArgument[_currentArgCount + 1]; + + int pos = 0; + int iarg; + + for (iarg = 0; iarg < _currentArgCount;) + { + int equal_sign_index = data.indexOf('=', pos); + int next_arg_index = data.indexOf('&', pos); + + WS_LOGDEBUG1(F("pos: "), pos); + WS_LOGDEBUG1(F("=@ "), equal_sign_index); + WS_LOGDEBUG1(F(" &@ "), next_arg_index); + + + if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) + { + WS_LOGDEBUG1(F("arg missing value: "), iarg); + + if (next_arg_index == -1) + break; + + pos = next_arg_index + 1; + + continue; + } + + RequestArgument& arg = _currentArgs[iarg]; + arg.key = data.substring(pos, equal_sign_index); + arg.value = data.substring(equal_sign_index + 1, next_arg_index); + + WS_LOGDEBUG1(F("arg: "), iarg); + WS_LOGDEBUG1(F("key: "), arg.key); + WS_LOGDEBUG1(F("value: "), arg.value); + + ++iarg; + + if (next_arg_index == -1) + break; + + pos = next_arg_index + 1; + } + + _currentArgCount = iarg; + + WS_LOGDEBUG1(F("args count: "), _currentArgCount); +} + +//////////////////////////////////////// + +void WiFiWebServer::_uploadWriteByte(uint8_t b) +{ + if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN) + { + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); + + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.currentSize = 0; + } + + _currentUpload.buf[_currentUpload.currentSize++] = b; +} + +//////////////////////////////////////// + +int WiFiWebServer::_uploadReadByte(WiFiClient& client) +{ + int res = client.read(); + + if (res == -1) + { + while (!client.available() && client.connected()) + yield(); + + res = client.read(); + } + + return res; +} + +//////////////////////////////////////// + +#endif // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +#if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +bool WiFiWebServer::_parseForm(WiFiClient& client, const String& boundary, uint32_t len) +{ + (void) len; + + WS_LOGDEBUG1(F("Parse Form: Boundary: "), boundary); + WS_LOGDEBUG1(F("Length: "), len); + + String line; + int retry = 0; + + do + { + line = client.readStringUntil('\r'); + ++retry; + } while (line.length() == 0 && retry < 3); + + client.readStringUntil('\n'); + + //start reading the form + if (line == ("--" + boundary)) + { + if (_postArgs) + delete[] _postArgs; + + _postArgs = new RequestArgument[WEBSERVER_MAX_POST_ARGS]; + _postArgsLen = 0; + + while (1) + { + String argName; + String argValue; + String argType; + String argFilename; + + bool argIsFile = false; + + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))) + { + int nameStart = line.indexOf('='); + + if (nameStart != -1) + { + argName = line.substring(nameStart + 2); + nameStart = argName.indexOf('='); + + if (nameStart == -1) + { + argName = argName.substring(0, argName.length() - 1); + } + else + { + argFilename = argName.substring(nameStart + 2, argName.length() - 1); + argName = argName.substring(0, argName.indexOf('"')); + argIsFile = true; + + WS_LOGDEBUG1(F("PostArg FileName: "), argFilename); + + //use GET to set the filename if uploading using blob + if (argFilename == F("blob") && hasArg("filename")) + argFilename = arg("filename"); + } + + WS_LOGDEBUG1(F("PostArg Name: "), argName); + +#if (ESP32 || ESP8266) + using namespace mime_esp; +#else + using namespace mime; +#endif + + argType = mimeTable[txt].mimeType; + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase("Content-Type")) + { + argType = line.substring(line.indexOf(':') + 2); + //skip next line + client.readStringUntil('\r'); + client.readStringUntil('\n'); + } + + WS_LOGDEBUG1(F("PostArg Type: "), argType); + + if (!argIsFile) + { + while (1) + { + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (line.startsWith("--" + boundary)) + break; + + if (argValue.length() > 0) + argValue += "\n"; + + argValue += line; + } + + WS_LOGDEBUG1(F("PostArg Value: "), argValue); + + RequestArgument& arg = _postArgs[_postArgsLen++]; + arg.key = argName; + arg.value = argValue; + + if (line == ("--" + boundary + "--")) + { + WS_LOGDEBUG(F("Done Parsing POST")); + + break; + } + } + else + { + //_currentUpload.reset(new HTTPUpload()); + if (!_currentUpload) + _currentUpload = new HTTPUpload(); + + _currentUpload->status = UPLOAD_FILE_START; + _currentUpload->name = argName; + _currentUpload->filename = argFilename; + _currentUpload->type = argType; + _currentUpload->totalSize = 0; + _currentUpload->currentSize = 0; + _currentUpload->contentLength = len; + + WS_LOGDEBUG1(F("Start File: "), _currentUpload->filename); + WS_LOGDEBUG1(F("Type: "), _currentUpload->type); + + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + + _currentUpload->status = UPLOAD_FILE_WRITE; + uint8_t argByte = _uploadReadByte(client); + +readfile: + + while (argByte != 0x0D) + { + if (!client.connected()) + return _parseFormUploadAborted(); + + _uploadWriteByte(argByte); + argByte = _uploadReadByte(client); + } + + argByte = _uploadReadByte(client); + + if (!client.connected()) + return _parseFormUploadAborted(); + + if (argByte == 0x0A) + { + argByte = _uploadReadByte(client); + + if (!client.connected()) + return _parseFormUploadAborted(); + + if ((char)argByte != '-') + { + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + goto readfile; + } + else + { + argByte = _uploadReadByte(client); + + if (!client.connected()) + return _parseFormUploadAborted(); + + if ((char)argByte != '-') + { + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + goto readfile; + } + } + +#define USING_VLA true + +#if USING_VLA + // Better compiler warning than risk of fragmented heap + uint8_t endBuf[boundary.length()]; +#else + // No compiler warning, but risk of fragmented heap + uint8_t* endBuf = new uint8_t[boundary.length()]; + + if (!endBuf) + { + return false; + } + +#endif + + client.readBytes(endBuf, boundary.length()); + + if (strstr((const char*)endBuf, boundary.c_str()) != NULL) + { + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + + _currentUpload->totalSize += _currentUpload->currentSize; + _currentUpload->status = UPLOAD_FILE_END; + + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + + WS_LOGDEBUG1(F("End File: "), _currentUpload->filename); + WS_LOGDEBUG1(F("Type: "), _currentUpload->type); + WS_LOGDEBUG1(F("Size: "), _currentUpload->totalSize); + + line = client.readStringUntil(0x0D); + client.readStringUntil(0x0A); + + if (line == "--") + { + WS_LOGDEBUG(F("Done Parsing POST")); + + break; + } + + continue; + } + else + { + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + _uploadWriteByte((uint8_t)('-')); + + uint32_t i = 0; + + while (i < boundary.length()) + { + _uploadWriteByte(endBuf[i++]); + } + + argByte = _uploadReadByte(client); + goto readfile; + } + +#if !USING_VLA + + if (endBuf) + delete [] endBuf; + +#endif + } + else + { + _uploadWriteByte(0x0D); + goto readfile; + } + + break; + } + } + } + } + + int iarg; + int totalArgs = ((WEBSERVER_MAX_POST_ARGS - _postArgsLen) < _currentArgCount) ? (WEBSERVER_MAX_POST_ARGS - _postArgsLen) + : _currentArgCount; + + for (iarg = 0; iarg < totalArgs; iarg++) + { + RequestArgument& arg = _postArgs[_postArgsLen++]; + arg.key = _currentArgs[iarg].key; + arg.value = _currentArgs[iarg].value; + } + + if (_currentArgs) + delete[] _currentArgs; + + _currentArgs = new RequestArgument[_postArgsLen]; + + for (iarg = 0; iarg < _postArgsLen; iarg++) + { + RequestArgument& arg = _currentArgs[iarg]; + arg.key = _postArgs[iarg].key; + arg.value = _postArgs[iarg].value; + } + + _currentArgCount = iarg; + + if (_postArgs) + { + delete[] _postArgs; + _postArgs = nullptr; + _postArgsLen = 0; + } + + return true; + } + + WS_LOGDEBUG1(F("Error: line: "), line); + + return false; +} + +bool WiFiWebServer::_parseFormUploadAborted() +{ + _currentUpload->status = UPLOAD_FILE_ABORTED; + + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, *_currentUpload); + + return false; +} + +//////////////////////////////////////// + +#else // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +bool WiFiWebServer::_parseForm(WiFiClient& client, const String& boundary, uint32_t len) +{ + WS_LOGDEBUG1(F("Parse Form: Boundary: "), boundary); + WS_LOGDEBUG1(F("Length: "), len); + WS_LOGERROR1(F("Parse Form: Boundary: "), boundary); + WS_LOGERROR1(F("Length: "), len); + + String line; + int retry = 0; + + do + { + line = client.readStringUntil('\r'); + ++retry; + } while (line.length() == 0 && retry < 3); + + client.readStringUntil('\n'); + + //start reading the form + if (line == ("--" + boundary)) + { + RequestArgument* postArgs = new RequestArgument[32]; + int postArgsLen = 0; + + while (1) + { + String argName; + String argValue; + String argType; + String argFilename; + + bool argIsFile = false; + + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (line.startsWith("Content-Disposition")) + { + int nameStart = line.indexOf('='); + + if (nameStart != -1) + { + argName = line.substring(nameStart + 2); + nameStart = argName.indexOf('='); + + if (nameStart == -1) + { + argName = argName.substring(0, argName.length() - 1); + } + else + { + argFilename = argName.substring(nameStart + 2, argName.length() - 1); + argName = argName.substring(0, argName.indexOf('"')); + argIsFile = true; + + WS_LOGDEBUG1(F("PostArg FileName: "), argFilename); + + //use GET to set the filename if uploading using blob + if (argFilename == "blob" && hasArg("filename")) + argFilename = arg("filename"); + } + + WS_LOGDEBUG1(F("PostArg Name: "), argName); + + argType = "text/plain"; + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (line.startsWith("Content-Type")) + { + argType = line.substring(line.indexOf(':') + 2); + //skip next line + client.readStringUntil('\r'); + client.readStringUntil('\n'); + } + + WS_LOGDEBUG1(F("PostArg Type: "), argType); + + if (!argIsFile) + { + while (1) + { + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + if (line.startsWith("--" + boundary)) + break; + + if (argValue.length() > 0) + argValue += "\n"; + + argValue += line; + } + + WS_LOGDEBUG1(F("PostArg Value: "), argValue); + + RequestArgument& arg = postArgs[postArgsLen++]; + arg.key = argName; + arg.value = argValue; + + if (line == ("--" + boundary + "--")) + { + WS_LOGDEBUG(F("Done Parsing POST")); + + break; + } + } + else + { + _currentUpload.status = UPLOAD_FILE_START; + _currentUpload.name = argName; + _currentUpload.filename = argFilename; + _currentUpload.type = argType; + _currentUpload.totalSize = 0; + _currentUpload.currentSize = 0; + + WS_LOGDEBUG1(F("Start File: "), _currentUpload.filename); + WS_LOGDEBUG1(F("Type: "), _currentUpload.type); + + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); + + _currentUpload.status = UPLOAD_FILE_WRITE; + uint8_t argByte = _uploadReadByte(client); + +readfile: + + while (argByte != 0x0D) + { + if (!client.connected()) + return _parseFormUploadAborted(); + + _uploadWriteByte(argByte); + argByte = _uploadReadByte(client); + } + + argByte = _uploadReadByte(client); + + if (!client.connected()) + return _parseFormUploadAborted(); + + if (argByte == 0x0A) + { + argByte = _uploadReadByte(client); + + if (!client.connected()) + return _parseFormUploadAborted(); + + if ((char)argByte != '-') + { + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + goto readfile; + } + else + { + argByte = _uploadReadByte(client); + + if (!client.connected()) + return _parseFormUploadAborted(); + + if ((char)argByte != '-') + { + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + goto readfile; + } + } + +#define USING_VLA true + +#if USING_VLA + // Better compiler warning than risk of fragmented heap + uint8_t endBuf[boundary.length()]; +#else + // No compiler warning, but risk of fragmented heap + uint8_t* endBuf = new uint8_t[boundary.length()]; + + if (!endBuf) + { + return false; + } + +#endif + + client.readBytes(endBuf, boundary.length()); + + if (strstr((const char*)endBuf, boundary.c_str()) != NULL) + { + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); + + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.status = UPLOAD_FILE_END; + + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); + + WS_LOGDEBUG1(F("End File: "), _currentUpload.filename); + WS_LOGDEBUG1(F("Type: "), _currentUpload.type); + WS_LOGDEBUG1(F("Size: "), _currentUpload.totalSize); + + line = client.readStringUntil(0x0D); + client.readStringUntil(0x0A); + + if (line == "--") + { + WS_LOGDEBUG(F("Done Parsing POST")); + + break; + } + + continue; + } + else + { + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + _uploadWriteByte((uint8_t)('-')); + + uint32_t i = 0; + + while (i < boundary.length()) + { + _uploadWriteByte(endBuf[i++]); + } + + argByte = _uploadReadByte(client); + goto readfile; + } + +#if !USING_VLA + + if (endBuf) + delete [] endBuf; + +#endif + } + else + { + _uploadWriteByte(0x0D); + goto readfile; + } + + break; + } + } + } + } + + int iarg; + int totalArgs = ((32 - postArgsLen) < _currentArgCount) ? (32 - postArgsLen) : _currentArgCount; + + for (iarg = 0; iarg < totalArgs; iarg++) + { + RequestArgument& arg = postArgs[postArgsLen++]; + arg.key = _currentArgs[iarg].key; + arg.value = _currentArgs[iarg].value; + } + + if (_currentArgs) + delete[] _currentArgs; + + _currentArgs = new RequestArgument[postArgsLen]; + + for (iarg = 0; iarg < postArgsLen; iarg++) + { + RequestArgument& arg = _currentArgs[iarg]; + arg.key = postArgs[iarg].key; + arg.value = postArgs[iarg].value; + } + + _currentArgCount = iarg; + + if (postArgs) + delete[] postArgs; + + return true; + } + + WS_LOGDEBUG1(F("Error: line: "), line); + + return false; +} + +//////////////////////////////////////// + +bool WiFiWebServer::_parseFormUploadAborted() +{ + _currentUpload.status = UPLOAD_FILE_ABORTED; + + if (_currentHandler && _currentHandler->canUpload(_currentUri)) + _currentHandler->upload(*this, _currentUri, _currentUpload); + + return false; +} + +//////////////////////////////////////// + +#endif // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +String WiFiWebServer::urlDecode(const String& text) +{ + String decoded = ""; + char temp[] = "0x00"; + unsigned int len = text.length(); + unsigned int i = 0; + + while (i < len) + { + char decodedChar; + char encodedChar = text.charAt(i++); + + if ((encodedChar == '%') && (i + 1 < len)) + { + temp[2] = text.charAt(i++); + temp[3] = text.charAt(i++); + + decodedChar = strtol(temp, NULL, 16); + } + else + { + if (encodedChar == '+') + { + decodedChar = ' '; + } + else + { + decodedChar = encodedChar; // normal ascii char + } + } + + decoded += decodedChar; + } + + return decoded; +} + +//////////////////////////////////////// + +#endif // Parsing_Impl_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/Uri.h b/software/firmware/source/libraries/WiFiWebServer/src/Uri.h new file mode 100644 index 000000000..c34784dec --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/Uri.h @@ -0,0 +1,75 @@ +/**************************************************************************************************************************** + Uri.h - Dead simple HTTP WebClient. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#ifndef URI_H +#define URI_H + +#include +#include + +//////////////////////////////////////// + +class Uri +{ + protected: + const String _uri; + + public: + Uri(const char *uri) : _uri(uri) {} + Uri(const String &uri) : _uri(uri) {} + Uri(const __FlashStringHelper *uri) : _uri(String(uri)) {} + virtual ~Uri() {} + + //////////////////////////////////////// + + virtual Uri* clone() const + { + return new Uri(_uri); + }; + + //////////////////////////////////////// + + virtual void initPathArgs(__attribute__((unused)) std::vector &pathArgs) {} + + //////////////////////////////////////// + + virtual inline bool canHandle(const String &requestUri, __attribute__((unused)) std::vector &pathArgs) + { + return _uri == requestUri; + } +}; + +#endif diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFiHttpClient.h b/software/firmware/source/libraries/WiFiWebServer/src/WiFiHttpClient.h new file mode 100644 index 000000000..a713bbc6b --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFiHttpClient.h @@ -0,0 +1,54 @@ +/**************************************************************************************************************************** + WiFiHttpClient.h - Dead simple HTTP WebClient. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// Library to simplify HTTP fetching on Arduino +// (c) Copyright Arduino. 2016 +// Released under Apache License, version 2.0 + +#pragma once + +#ifndef WiFiHttpClient_H +#define WiFiHttpClient_H + +#include + +#include "utility/WiFiDebug.h" +#include "WiFi_HTTPClient/WiFi_HttpClient.h" +#include "WiFi_HTTPClient/WiFi_WebSocketClient.h" +#include "WiFi_HTTPClient/WiFi_URLEncoder.h" + +#endif // WiFiHttpClient_H + diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer-impl.h b/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer-impl.h new file mode 100644 index 000000000..f0fdfeac7 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer-impl.h @@ -0,0 +1,1365 @@ +/********************************************************************************************************************************* + WiFiWebServer-impl.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + **********************************************************************************************************************************/ + +#pragma once + +#ifndef WiFiWebServer_Impl_H +#define WiFiWebServer_Impl_H + +#include +#include + +#include "WiFiWebServer.hpp" +#include "utility/RequestHandlersImpl.h" +#include "utility/WiFiDebug.h" +#include "utility/mimetable.h" + +const char * AUTHORIZATION_HEADER = "Authorization"; + +// New to use WWString + +//////////////////////////////////////// + +WWString fromString(const String& str) +{ + return str.c_str(); +} + +//////////////////////////////////////// + +WWString fromString(const String&& str) +{ + return str.c_str(); +} + +//////////////////////////////////////// + +String fromWWString(const WWString& str) +{ + return str.c_str(); +} + +//////////////////////////////////////// + +String fromWWString(const WWString&& str) +{ + return str.c_str(); +} + +//////////////////////////////////////// +//////////////////////////////////////// + +#if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +#if (ESP32 || ESP8266) +WiFiWebServer::WiFiWebServer(IPAddress addr, int port) + : _corsEnabled(false) + , _server(addr, port) + , _currentMethod(HTTP_ANY) + , _currentVersion(0) + , _currentStatus(HC_NONE) + , _statusChange(0) + , _nullDelay(true) + , _currentHandler(nullptr) + , _firstHandler(nullptr) + , _lastHandler(nullptr) + , _currentArgCount(0) + , _currentArgs(nullptr) + , _postArgsLen(0) + , _postArgs(nullptr) + , _headerKeysCount(0) + , _currentHeaders(nullptr) + , _contentLength(0) + , _clientContentLength(0) + , _chunked(false) +{ +} +#endif + +//////////////////////////////////////// + +WiFiWebServer::WiFiWebServer(int port) + : _corsEnabled(false) + , _server(port) + , _currentMethod(HTTP_ANY) + , _currentVersion(0) + , _currentStatus(HC_NONE) + , _statusChange(0) + , _nullDelay(true) + , _currentHandler(nullptr) + , _firstHandler(nullptr) + , _lastHandler(nullptr) + , _currentArgCount(0) + , _currentArgs(nullptr) + , _postArgsLen(0) + , _postArgs(nullptr) + , _headerKeysCount(0) + , _currentHeaders(nullptr) + , _contentLength(0) + , _clientContentLength(0) + , _chunked(false) +{ +} + +//////////////////////////////////////// + +WiFiWebServer::~WiFiWebServer() +{ +#if (ESP32 || ESP8266) + _server.close(); +#endif + + if (_currentHeaders) + delete[]_currentHeaders; + + RequestHandler* handler = _firstHandler; + + while (handler) + { + RequestHandler* next = handler->next(); + delete handler; + handler = next; + } +} + +//////////////////////////////////////// + +void WiFiWebServer::begin() +{ + close(); + _server.begin(); + +#if (ESP32 || ESP8266) + _server.setNoDelay(true); +#endif +} + +//////////////////////////////////////// + +void WiFiWebServer::begin(uint16_t port) +{ + close(); + _server.begin(port); + +#if (ESP32 || ESP8266) + _server.setNoDelay(true); +#endif +} + +//////////////////////////////////////// + +#else // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +WiFiWebServer::WiFiWebServer(int port) + : _corsEnabled(false) + , _server(port) + , _currentMethod(HTTP_ANY) + , _currentVersion(0) + , _currentHandler(nullptr) + , _firstHandler(nullptr) + , _lastHandler(nullptr) + , _currentArgCount(0) + , _currentArgs(nullptr) + , _headerKeysCount(0) + , _currentHeaders(nullptr) + , _contentLength(0) + , _chunked(false) +{ +} + +//////////////////////////////////////// + +WiFiWebServer::~WiFiWebServer() +{ + if (_currentHeaders) + delete[]_currentHeaders; + + _headerKeysCount = 0; + RequestHandler* handler = _firstHandler; + + while (handler) + { + RequestHandler* next = handler->next(); + delete handler; + handler = next; + } + + close(); +} + +//////////////////////////////////////// + +void WiFiWebServer::begin() +{ + _currentStatus = HC_NONE; + _server.begin(); + + if (!_headerKeysCount) + collectHeaders(0, 0); +} + +//////////////////////////////////////// + +#endif // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +bool WiFiWebServer::authenticate(const char * username, const char * password) +{ + if (hasHeader(AUTHORIZATION_HEADER)) + { + String authReq = header(AUTHORIZATION_HEADER); + + if (authReq.startsWith("Basic")) + { + authReq = authReq.substring(6); + authReq.trim(); + char toencodeLen = strlen(username) + strlen(password) + 1; + char *toencode = new char[toencodeLen + 1]; + + if (toencode == NULL) + { + authReq = String(); + + return false; + } + + char *encoded = new char[base64_encode_expected_len(toencodeLen) + 1]; + + if (encoded == NULL) + { + authReq = String(); + delete[] toencode; + + return false; + } + + sprintf(toencode, "%s:%s", username, password); + + if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equals(encoded)) + { + authReq = String(); + delete[] toencode; + delete[] encoded; + + return true; + } + + delete[] toencode; + delete[] encoded; + } + + authReq = String(); + } + + return false; +} + +//////////////////////////////////////// + +void WiFiWebServer::requestAuthentication() +{ + sendHeader("WWW-Authenticate", "Basic realm=\"Login Required\""); + send(401); +} + +//////////////////////////////////////// + +void WiFiWebServer::on(const String &uri, WiFiWebServer::THandlerFunction handler) +{ + on(uri, HTTP_ANY, handler); +} + +//////////////////////////////////////// + +void WiFiWebServer::on(const String &uri, HTTPMethod method, WiFiWebServer::THandlerFunction fn) +{ + on(uri, method, fn, _fileUploadHandler); +} + +//////////////////////////////////////// + +void WiFiWebServer::on(const String &uri, HTTPMethod method, WiFiWebServer::THandlerFunction fn, + WiFiWebServer::THandlerFunction ufn) +{ + _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); +} + +//////////////////////////////////////// + +void WiFiWebServer::addHandler(RequestHandler* handler) +{ + _addRequestHandler(handler); +} + +//////////////////////////////////////// + +void WiFiWebServer::_addRequestHandler(RequestHandler* handler) +{ + if (!_lastHandler) + { + _firstHandler = handler; + _lastHandler = handler; + } + else + { + _lastHandler->next(handler); + _lastHandler = handler; + } +} + +//////////////////////////////////////// + +#if USE_NEW_WEBSERVER_VERSION + +void WiFiWebServer::handleClient() +{ + if (_currentStatus == HC_NONE) + { + WiFiClient client = _server.available(); + + if (!client) + { + if (_nullDelay) + { + delay(1); + } + + return; + } + + WS_LOGDEBUG(F("handleClient: New Client")); + + _currentClient = client; + _currentStatus = HC_WAIT_READ; + _statusChange = millis(); + } + + bool keepCurrentClient = false; + bool callYield = false; + + if (_currentClient.connected() || _currentClient.available()) + { + switch (_currentStatus) + { + case HC_NONE: + // No-op to avoid C++ compiler warning + break; + + case HC_WAIT_READ: + + // Wait for data from client to become available + if (_currentClient.available()) + { + if (_parseRequest(_currentClient)) + { + _currentClient.setTimeout(HTTP_MAX_SEND_WAIT); + _contentLength = CONTENT_LENGTH_NOT_SET; + _handleRequest(); + +#if USE_WIFI_NINA || ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_SAMD_NANO_33_IOT) ) + + // Fix for issue with Chrome based browsers: https://github.com/espressif/arduino-esp32/issues/3652 + // Remove this will hang boards using WiFNINA, such as + // Nano_RP2040_Connect with arduino_pico core, Nano_33_IoT + if (_currentClient.connected()) + { + _currentStatus = HC_WAIT_CLOSE; + _statusChange = millis(); + keepCurrentClient = true; + } + +#endif + } + } + else + { + // !_currentClient.available() + if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) + { + keepCurrentClient = true; + } + + callYield = true; + } + + break; + + case HC_WAIT_CLOSE: + + // Wait for client to close the connection + if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) + { + keepCurrentClient = true; + callYield = true; + } + } + } + + if (!keepCurrentClient) + { + WS_LOGDEBUG(F("handleClient: Don't keepCurrentClient")); + _currentClient = WiFiClient(); + _currentStatus = HC_NONE; + // KH + //_currentUpload.reset(); + } + + if (callYield) + { + yield(); + } + +#if (USE_WIFI_NINA || WIFI_USE_PORTENTA_H7) + // KH, fix bug relating to New NINA FW 1.4.0. Have to close the connection + _currentClient.stop(); + WS_LOGDEBUG(F("handleClient: Client disconnected")); +#endif +} + +//////////////////////////////////////// + +#else // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +// KH, rewritten for Portenta H7 from v1.4.0 +void WiFiWebServer::handleClient() +{ + if (_currentStatus == HC_NONE) + { + WiFiClient client = _server.available(); + + if (!client) + { + return; + } + + WS_LOGDEBUG(F("handleClient: New Client")); + + _currentClient = client; + _currentStatus = HC_WAIT_READ; + _statusChange = millis(); + } + + if (!_currentClient.connected()) + { + _currentStatus = HC_NONE; + + goto stopClient; + } + + // Wait for data from client to become available + if (_currentStatus == HC_WAIT_READ) + { + if (!_currentClient.available()) + { + if (millis() - _statusChange > HTTP_MAX_DATA_WAIT) + { + WS_LOGDEBUG(F("handleClient: HTTP_MAX_DATA_WAIT Timeout")); + + _currentStatus = HC_NONE; + + goto stopClient; + } + + yield(); + return; + } + + WS_LOGDEBUG(F("handleClient: Parsing Request")); + + if (!_parseRequest(_currentClient)) + { + WS_LOGDEBUG(F("handleClient: Can't parse request")); + + _currentStatus = HC_NONE; + + goto stopClient; + } + + _currentClient.setTimeout(HTTP_MAX_SEND_WAIT); + _contentLength = CONTENT_LENGTH_NOT_SET; + + _handleRequest(); + + if (!_currentClient.connected()) + { + WS_LOGINFO(F("handleClient: Connection closed")); + + _currentStatus = HC_NONE; + + goto stopClient; + } + else + { + _currentStatus = HC_WAIT_CLOSE; + _statusChange = millis(); + return; + } + } + + if (_currentStatus == HC_WAIT_CLOSE) + { + if (millis() - _statusChange > HTTP_MAX_CLOSE_WAIT) + { + _currentStatus = HC_NONE; + + WS_LOGDEBUG(F("handleClient: HTTP_MAX_CLOSE_WAIT Timeout")); + + yield(); + } + else + { + yield(); + return; + } + } + +stopClient: + +#if (USE_WIFI_NINA || WIFI_USE_PORTENTA_H7) + // To be used with New NINA FW 1.4.0 and Portenta_H7 WiFi. Have to close the connection + _currentClient.stop(); + WS_LOGDEBUG(F("handleClient: Client disconnected")); +#endif +} + +#endif // #if USE_NEW_WEBSERVER_VERSION + +//////////////////////////////////////// + +void WiFiWebServer::close() +{ +#if (ESP32 || ESP8266) + _server.close(); +#endif + + _currentStatus = HC_NONE; + + if (!_headerKeysCount) + collectHeaders(0, 0); +} + +//////////////////////////////////////// + +void WiFiWebServer::stop() +{ + close(); +} + +//////////////////////////////////////// + +void WiFiWebServer::sendHeader(const String& name, const String& value, bool first) +{ + WWString headerLine = fromString(name); + + headerLine += ": "; + headerLine += fromString(value); + headerLine += RETURN_NEWLINE; + + if (first) + { + _responseHeaders = fromWWString(headerLine + fromString(_responseHeaders)); + } + else + { + _responseHeaders = fromWWString(fromString(_responseHeaders) + headerLine); + } +} + +//////////////////////////////////////// + +void WiFiWebServer::setContentLength(size_t contentLength) +{ + _contentLength = contentLength; +} + +//////////////////////////////////////// + +void WiFiWebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) +{ + WWString aResponse = fromString(response); + + aResponse = "HTTP/1." + fromString(String(_currentVersion)) + " "; + aResponse += fromString(String(code)); + aResponse += " "; + aResponse += fromString(_responseCodeToString(code)); + aResponse += RETURN_NEWLINE; + +#if (ESP32 || ESP8266) + using namespace mime_esp; +#else + using namespace mime; +#endif + + if (!content_type) + content_type = mimeTable[html].mimeType; + + sendHeader("Content-Type", content_type, true); + + if (_contentLength == CONTENT_LENGTH_NOT_SET) + { + sendHeader("Content-Length", String(contentLength)); + } + else if (_contentLength != CONTENT_LENGTH_UNKNOWN) + { + sendHeader("Content-Length", String(_contentLength)); + } + else if (_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion) + { + //HTTP/1.1 or above client + //let's do chunked + _chunked = true; + sendHeader("Accept-Ranges", "none"); + sendHeader("Transfer-Encoding", "chunked"); + } + + if (_corsEnabled) + { + sendHeader("Access-Control-Allow-Origin", "*"); + sendHeader("Access-Control-Allow-Methods", "*"); + sendHeader("Access-Control-Allow-Headers", "*"); + } + + WS_LOGDEBUG(F("_prepareHeader sendHeader Conn close")); + + sendHeader("Connection", "close"); + + aResponse += fromString(_responseHeaders); + aResponse += RETURN_NEWLINE; + + response = fromWWString(aResponse); + + _responseHeaders = String(""); +} + +//////////////////////////////////////// + +void WiFiWebServer::_prepareHeader(WWString& response, int code, const char* content_type, size_t contentLength) +{ + response = "HTTP/1." + fromString(String(_currentVersion)) + " "; + response += fromString(String(code)); + response += " "; + response += fromString(_responseCodeToString(code)); + response += RETURN_NEWLINE; + +#if (ESP32 || ESP8266) + using namespace mime_esp; +#else + using namespace mime; +#endif + + if (!content_type) + content_type = mimeTable[html].mimeType; + + sendHeader("Content-Type", content_type, true); + + if (_contentLength == CONTENT_LENGTH_NOT_SET) + { + sendHeader("Content-Length", String(contentLength)); + } + else if (_contentLength != CONTENT_LENGTH_UNKNOWN) + { + sendHeader("Content-Length", String(_contentLength)); + } + else if (_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion) + { + //HTTP/1.1 or above client + //let's do chunked + _chunked = true; + sendHeader("Accept-Ranges", "none"); + sendHeader("Transfer-Encoding", "chunked"); + } + else if (_contentLength != CONTENT_LENGTH_UNKNOWN) + { + sendHeader("Content-Length", String(_contentLength)); + } + else if (_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion) + { + //HTTP/1.1 or above client + //let's do chunked + _chunked = true; + sendHeader("Accept-Ranges", "none"); + sendHeader("Transfer-Encoding", "chunked"); + } + + if (_corsEnabled) + { + sendHeader("Access-Control-Allow-Origin", "*"); + sendHeader("Access-Control-Allow-Methods", "*"); + sendHeader("Access-Control-Allow-Headers", "*"); + } + + WS_LOGDEBUG(F("_prepareHeader sendHeader Conn close")); + + sendHeader("Connection", "close"); + + response += fromString(_responseHeaders); + response += RETURN_NEWLINE; + + _responseHeaders = String(""); +} + +//////////////////////////////////////// + +void WiFiWebServer::send(int code, const char* content_type, const String& content) +{ + WWString header; + + _prepareHeader(header, code, content_type, content.length()); + + _currentClient.write((const uint8_t *)header.c_str(), header.length()); + + if (content.length()) + { + sendContent(content, content.length()); + } +} + +//////////////////////////////////////// + +void WiFiWebServer::send(int code, char* content_type, const String& content, size_t contentLength) +{ + WWString header; + + char type[64]; + + memccpy((void*)type, content_type, 0, sizeof(type)); + _prepareHeader(header, code, (const char* )type, contentLength); + + _currentClient.write((const uint8_t *) header.c_str(), header.length()); + + if (contentLength) + { + sendContent(content, contentLength); + } +} + +//////////////////////////////////////// + +void WiFiWebServer::send(int code, char* content_type, const String& content) +{ + send(code, (const char*)content_type, content); +} + +//////////////////////////////////////// + +void WiFiWebServer::send(int code, const String& content_type, const String& content) +{ + send(code, (const char*)content_type.c_str(), content); +} + +//////////////////////////////////////// + +// KH New + +void WiFiWebServer::send(int code, const char* content_type, const char* content) +{ + send(code, content_type, content, content ? strlen(content) : 0); +} + +//////////////////////////////////////// + +void WiFiWebServer::send(int code, const char* content_type, const char* content, size_t contentLength) +{ + String header; + + _prepareHeader(header, code, content_type, contentLength); + + _currentClient.write((const uint8_t *) header.c_str(), header.length()); + + if (contentLength) + { + sendContent(content, contentLength); + } +} + +//////////////////////////////////////// + +void WiFiWebServer::sendContent(const char* content, size_t contentLength) +{ + const char * footer = RETURN_NEWLINE; + + if (_chunked) + { + char chunkSize[11]; + + WS_LOGDEBUG1(F("sendContent_char: _chunked, _currentVersion ="), _currentVersion); + + sprintf(chunkSize, "%x%s", contentLength, footer); + _currentClient.write(chunkSize, strlen(chunkSize)); + } + + _currentClient.write(content, contentLength); + + if (_chunked) + { + _currentClient.write(footer, 2); + + if (contentLength == 0) + { + _chunked = false; + } + } +} + +//////////////////////////////////////// + +void WiFiWebServer::sendContent(const String& content) +{ + sendContent(content.c_str(), content.length()); +} + +//////////////////////////////////////// + +void WiFiWebServer::sendContent(const String& content, size_t contentLength) +{ + sendContent(content.c_str(), contentLength); +} + +//////////////////////////////////////// + +// KH, Restore PROGMEM commands +void WiFiWebServer::send_P(int code, PGM_P content_type, PGM_P content) +{ + size_t contentLength = 0; + + if (content != NULL) + { + contentLength = strlen_P(content); + } + + String header; + char type[64]; + + memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type)); + _prepareHeader(header, code, (const char* )type, contentLength); + +#if !( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) ) + WS_LOGDEBUG1(F("send_P: len = "), contentLength); + WS_LOGDEBUG1(F("content = "), content); + WS_LOGDEBUG1(F("send_P: hdrlen = "), header.length()); + WS_LOGDEBUG1(F("header = "), header); +#endif + + _currentClient.write((const uint8_t *) header.c_str(), header.length()); + + if (contentLength) + { + sendContent_P(content); + } +} + +//////////////////////////////////////// + +void WiFiWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) +{ + WWString header; + + char type[64]; + + memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type)); + _prepareHeader(header, code, (const char* )type, contentLength); + +#if !( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) ) + WS_LOGDEBUG1(F("send_P: len = "), contentLength); + WS_LOGDEBUG1(F("content = "), content); + WS_LOGDEBUG1(F("send_P: hdrlen = "), header.length()); + WS_LOGDEBUG1(F("header = "), fromWWString(header)); +#endif + + _currentClient.write((const uint8_t *) header.c_str(), header.length()); + + if (contentLength) + { + sendContent_P(content, contentLength); + } +} + +//////////////////////////////////////// + +void WiFiWebServer::sendContent_P(PGM_P content) +{ + sendContent_P(content, strlen_P(content)); +} + +//////////////////////////////////////// + +void WiFiWebServer::sendContent_P(PGM_P content, size_t contentLength) +{ + const char * footer = RETURN_NEWLINE; + + if (_chunked) + { + char chunkSize[11]; + + WS_LOGDEBUG1(F("sendContent_P: _chunked, _currentVersion ="), _currentVersion); + + sprintf(chunkSize, "%x%s", contentLength, footer); + _currentClient.write(chunkSize, strlen(chunkSize)); + } + + uint8_t* _sendContentBuffer = new uint8_t[SENDCONTENT_P_BUFFER_SZ]; + + if (_sendContentBuffer) + { + uint16_t count = contentLength / SENDCONTENT_P_BUFFER_SZ; + uint16_t remainder = contentLength % SENDCONTENT_P_BUFFER_SZ; + uint16_t i = 0; + + for (i = 0; i < count; i++) + { + /* code */ + memcpy_P(_sendContentBuffer, &content[i * SENDCONTENT_P_BUFFER_SZ], SENDCONTENT_P_BUFFER_SZ); + _currentClient.write(_sendContentBuffer, SENDCONTENT_P_BUFFER_SZ); + } + + memcpy_P(_sendContentBuffer, &content[i * SENDCONTENT_P_BUFFER_SZ], remainder); + _currentClient.write(_sendContentBuffer, remainder); + + delete [] _sendContentBuffer; + } + else + { + WS_LOGERROR1(F("sendContent_P: Error, can't allocate _sendContentBuffer, Sz ="), SENDCONTENT_P_BUFFER_SZ); + + return; + } + + if (_chunked) + { + _currentClient.write(footer, 2); + + _chunked = false; + } +} + +//////////////////////////////////////// + +#if (ESP32 || ESP8266) + +#include "FS.h" + +//////////////////////////////////////// + +void WiFiWebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) +{ + _addRequestHandler(new StaticFileRequestHandler(fs, path, uri, cache_header)); +} + +//////////////////////////////////////// + +void WiFiWebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType, + const int code) +{ +#if (ESP32 || ESP8266) + using namespace mime_esp; +#else + using namespace mime; +#endif + + setContentLength(fileSize); + + if (fileName.endsWith(String(FPSTR(mimeTable[gz].endsWith))) && + contentType != String(FPSTR(mimeTable[gz].mimeType)) && + contentType != String(FPSTR(mimeTable[none].mimeType))) + { + sendHeader(F("Content-Encoding"), F("gzip")); + } + + send(code, contentType, emptyString); +} + +#endif + +//////////////////////////////////////// + +String WiFiWebServer::arg(const String& name) +{ + for (int i = 0; i < _currentArgCount; ++i) + { + if ( _currentArgs[i].key == name ) + return _currentArgs[i].value; + } + + return String(); +} + +//////////////////////////////////////// + +String WiFiWebServer::arg(int i) +{ + if (i < _currentArgCount) + return _currentArgs[i].value; + + return String(); +} + +//////////////////////////////////////// + +String WiFiWebServer::argName(int i) +{ + if (i < _currentArgCount) + return _currentArgs[i].key; + + return String(); +} + +//////////////////////////////////////// + +int WiFiWebServer::args() +{ + return _currentArgCount; +} + +//////////////////////////////////////// + +bool WiFiWebServer::hasArg(const String& name) +{ + for (int i = 0; i < _currentArgCount; ++i) + { + if (_currentArgs[i].key == name) + return true; + } + + return false; +} + +//////////////////////////////////////// + +String WiFiWebServer::header(const String& name) +{ + for (int i = 0; i < _headerKeysCount; ++i) + { + if (_currentHeaders[i].key == name) + return _currentHeaders[i].value; + } + + return String(); +} + +//////////////////////////////////////// + +void WiFiWebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) +{ + _headerKeysCount = headerKeysCount + 1; + + if (_currentHeaders) + delete[]_currentHeaders; + + _currentHeaders = new RequestArgument[_headerKeysCount]; + _currentHeaders[0].key = AUTHORIZATION_HEADER; + + for (int i = 1; i < _headerKeysCount; i++) + { + _currentHeaders[i].key = headerKeys[i - 1]; + } +} + +//////////////////////////////////////// + +String WiFiWebServer::header(int i) +{ + if (i < _headerKeysCount) + return _currentHeaders[i].value; + + return String(); +} + +//////////////////////////////////////// + +String WiFiWebServer::headerName(int i) +{ + if (i < _headerKeysCount) + return _currentHeaders[i].key; + + return String(); +} + +//////////////////////////////////////// + +int WiFiWebServer::headers() +{ + return _headerKeysCount; +} + +//////////////////////////////////////// + +bool WiFiWebServer::hasHeader(const String& name) +{ + for (int i = 0; i < _headerKeysCount; ++i) + { + if ((_currentHeaders[i].key == name) && (_currentHeaders[i].value.length() > 0)) + return true; + } + + return false; +} + +//////////////////////////////////////// + +String WiFiWebServer::hostHeader() +{ + return _hostHeader; +} + +//////////////////////////////////////// + +void WiFiWebServer::onFileUpload(THandlerFunction fn) +{ + _fileUploadHandler = fn; +} + +//////////////////////////////////////// + +void WiFiWebServer::onNotFound(THandlerFunction fn) +{ + _notFoundHandler = fn; +} + +//////////////////////////////////////// + +void WiFiWebServer::_handleRequest() +{ + bool handled = false; + + if (!_currentHandler) + { + WS_LOGDEBUG(F("_handleRequest: request handler not found")); + } + else + { + WS_LOGDEBUG(F("_handleRequest handle")); + + handled = _currentHandler->handle(*this, _currentMethod, _currentUri); + + if (!handled) + { + WS_LOGDEBUG(F("_handleRequest: _handleRequest failed")); + } + else + { + WS_LOGDEBUG(F("_handleRequest OK")); + } + } + + if (!handled && _notFoundHandler) + { + WS_LOGDEBUG(F("_handleRequest: Call _notFoundHandler")); + + _notFoundHandler(); + handled = true; + } + + if (!handled) + { +#if (ESP32 || ESP8266) + using namespace mime_esp; +#else + using namespace mime; +#endif + + WS_LOGDEBUG(F("_handleRequest: Send Not found")); + + send(404, mimeTable[html].mimeType, String("Not found: ") + _currentUri); + handled = true; + } + + if (handled) + { + WS_LOGDEBUG(F("_handleRequest: _finalizeResponse")); + + _finalizeResponse(); + } + +#if WIFI_USE_PORTENTA_H7 + WS_LOGDEBUG(F("_handleRequest: Clear _currentUri")); + //_currentUri = String(); + WS_LOGDEBUG(F("_handleRequest: Done Clear _currentUri")); +#else + _responseHeaders = String(""); +#endif +} + +//////////////////////////////////////// + +void WiFiWebServer::_finalizeResponse() +{ + if (_chunked) + { + sendContent(String()); + } +} + +//////////////////////////////////////// + +String WiFiWebServer::_responseCodeToString(int code) +{ + switch (code) + { + case 100: + return F("Continue"); + + case 101: + return F("Switching Protocols"); + + case 200: + return F("OK"); + + case 201: + return F("Created"); + + case 202: + return F("Accepted"); + + case 203: + return F("Non-Authoritative Information"); + + case 204: + return F("No Content"); + + case 205: + return F("Reset Content"); + + case 206: + return F("Partial Content"); + + case 300: + return F("Multiple Choices"); + + case 301: + return F("Moved Permanently"); + + case 302: + return F("Found"); + + case 303: + return F("See Other"); + + case 304: + return F("Not Modified"); + + case 305: + return F("Use Proxy"); + + case 307: + return F("Temporary Redirect"); + + case 400: + return F("Bad Request"); + + case 401: + return F("Unauthorized"); + + case 402: + return F("Payment Required"); + + case 403: + return F("Forbidden"); + + case 404: + return F("Not Found"); + + case 405: + return F("Method Not Allowed"); + + case 406: + return F("Not Acceptable"); + + case 407: + return F("Proxy Authentication Required"); + + case 408: + return F("Request Time-out"); + + case 409: + return F("Conflict"); + + case 410: + return F("Gone"); + + case 411: + return F("Length Required"); + + case 412: + return F("Precondition Failed"); + + case 413: + return F("Request Entity Too Large"); + + case 414: + return F("Request-URI Too Large"); + + case 415: + return F("Unsupported Media Type"); + + case 416: + return F("Requested range not satisfiable"); + + case 417: + return F("Expectation Failed"); + + case 500: + return F("Internal Server Error"); + + case 501: + return F("Not Implemented"); + + case 502: + return F("Bad Gateway"); + + case 503: + return F("Service Unavailable"); + + case 504: + return F("Gateway Time-out"); + + case 505: + return F("HTTP Version not supported"); + + default: + return ""; + } +} + +//////////////////////////////////////// + +#endif // WiFiWebServer_Impl_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer.h b/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer.h new file mode 100644 index 000000000..d286d30bf --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer.h @@ -0,0 +1,57 @@ +/********************************************************************************************************************************* + WiFiWebServer.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + **********************************************************************************************************************************/ + +#pragma once + +#ifndef WiFiWebServer_H +#define WiFiWebServer_H + +#ifndef WIFI_WEBSERVER_VERSION + #define WIFI_WEBSERVER_VERSION "WiFiWebServer v1.10.1" + + #define WIFI_WEBSERVER_VERSION_MAJOR 1 + #define WIFI_WEBSERVER_VERSION_MINOR 10 + #define WIFI_WEBSERVER_VERSION_PATCH 1 + + #define WIFI_WEBSERVER_VERSION_INT 1010001 +#endif + +#include "WiFiWebServer.hpp" +#include "WiFiWebServer-impl.h" +#include "Parsing-impl.h" + + +#endif // WiFiWebServer_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer.hpp b/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer.hpp new file mode 100644 index 000000000..cde6f93c2 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFiWebServer.hpp @@ -0,0 +1,706 @@ +/********************************************************************************************************************************* + WiFiWebServer.hpp - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + **********************************************************************************************************************************/ + +#pragma once + +#ifndef WiFiWebServer_HPP +#define WiFiWebServer_HPP + +#define USE_NEW_WEBSERVER_VERSION true + +//////////////////////////////////////// + +#if ( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) ) + #if defined(WIFI_USE_PORTENTA_H7) + #undef WIFI_USE_PORTENTA_H7 + #endif + #define WIFI_USE_PORTENTA_H7 true + + #if defined(USE_NEW_WEBSERVER_VERSION) + #undef USE_NEW_WEBSERVER_VERSION + #endif + #define USE_NEW_WEBSERVER_VERSION false + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use mbed-portenta architecture for PORTENTA_H7 from WiFiWebServer + + #undef _WIFI_LOGLEVEL_ + // Somehow Portenta_H7 with latest core hangs if printing too much + #define _WIFI_LOGLEVEL_ 1 + #endif + +//////////////////////////////////////// + +#elif ( defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) \ + || defined(ARDUINO_SAMD_NANO_33_IOT) || defined(ARDUINO_SAMD_MKRFox1200) || defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310) \ + || defined(ARDUINO_SAMD_MKRGSM1400) || defined(ARDUINO_SAMD_MKRNB1500) || defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(__SAMD21G18A__) \ + || defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(__SAMD21E18A__) || defined(__SAMD51__) || defined(__SAMD51J20A__) || defined(__SAMD51J19A__) \ + || defined(__SAMD51G19A__) || defined(__SAMD51P19A__) || defined(__SAMD21G18A__) ) + #if defined(WIFI_USE_SAMD) + #undef WIFI_USE_SAMD + #endif + #define WIFI_USE_SAMD true + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use SAMD architecture from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif (defined(NRF52840_FEATHER) || defined(NRF52832_FEATHER) || defined(NRF52_SERIES) || defined(ARDUINO_NRF52_ADAFRUIT) || \ + defined(NRF52840_FEATHER_SENSE) || defined(NRF52840_ITSYBITSY) || defined(NRF52840_CIRCUITPLAY) || \ + defined(NRF52840_CLUE) || defined(NRF52840_METRO) || defined(NRF52840_PCA10056) || defined(PARTICLE_XENON) || \ + defined(MDBT50Q_RX) || defined(NINA_B302_ublox) || defined(NINA_B112_ublox) ) + #if defined(WIFI_USE_NRF528XX) + #undef WIFI_USE_NRF528XX + #endif + #define WIFI_USE_NRF528XX true + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use nFR52 architecture from WiFiWebServer + #endif + + #include + +//////////////////////////////////////// + +#elif ( defined(ARDUINO_SAM_DUE) || defined(__SAM3X8E__) ) + #if defined(WIFI_USE_SAM_DUE) + #undef WIFI_USE_SAM_DUE + #endif + #define WIFI_USE_SAM_DUE true + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use SAM_DUE architecture from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif ( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \ + defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \ + defined(STM32WB) || defined(STM32MP1) ) && !( defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) ) + #if (_WIFI_LOGLEVEL_ > 2) + #warning STM32F/L/H/G/WB/MP1 board selected + #endif + + #if defined(WIFI_USE_STM32) + #undef WIFI_USE_STM32 + #endif + #define WIFI_USE_STM32 true + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use STM32 architecture from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif ( defined(ARDUINO_NANO_RP2040_CONNECT) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO) || \ + defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) || defined(ARDUINO_GENERIC_RP2040) || defined(ARDUINO_RASPBERRY_PI_PICO_W) ) + + #if (_WIFI_LOGLEVEL_ > 2) + #if defined(ARDUINO_RASPBERRY_PI_PICO_W) + #warning RASPBERRY_PI_PICO_W board using CYW4343 WiFi selected + #else + #warning RP2040-based board selected + #endif + #endif + + #if defined(WIFI_USE_RP2040) + #undef WIFI_USE_RP2040 + #endif + #define WIFI_USE_RP2040 true + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use RP2040 architecture from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif ( defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) ) + + #include "ArduinoSTL.h" + + #if defined(WIFI_USE_MEGA_AVR) + #undef WIFI_USE_MEGA_AVR + #endif + #define WIFI_USE_MEGA_AVR true + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use Arduino megaAVR architecture from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif ( defined(__AVR_ATmega4809__) || defined(ARDUINO_AVR_ATmega4809) || defined(ARDUINO_AVR_ATmega4808) || \ + defined(ARDUINO_AVR_ATmega3209) || defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || \ + defined(ARDUINO_AVR_ATmega1608) || defined(ARDUINO_AVR_ATmega809) || defined(ARDUINO_AVR_ATmega808) ) + + #if defined(WIFI_USE_MEGACOREX) + #undef WIFI_USE_MEGACOREX + #endif + #define WIFI_USE_MEGACOREX true + #error megaAVR architecture and MegaCoreX from WiFiWebServer not supported yet + +//////////////////////////////////////// + +#elif (ESP32) + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use ESP32 from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif (ESP8266) + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use ESP8266 from WiFiWebServer + #endif + +//////////////////////////////////////// + +#elif defined(CORE_TEENSY) + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use Teensy from WiFiWebServer + #endif + +//////////////////////////////////////// + +#else + + #warning Unknown or unsupported board + +#endif + +//////////////////////////////////////// + +// To support lambda function in class +#include + +#if !defined(USE_WIFI_NINA) + #define USE_WIFI_NINA true +#endif + +//////////////////////////////////////// + +// Default to use +#if !defined(USE_WIFI101_GENERIC) + #define USE_WIFI101_GENERIC true +#endif + +// Modify to use new WiFiNINA_Generic library to support boards besides Nano-33 IoT, MKRWiFi1010, Adafruit MetroM4, etc. +#if USE_WIFI_NINA + #include + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use WiFiNINA_Generic from WiFiWebServer + #endif +#elif USE_WIFI101 + #if USE_WIFI101_GENERIC + #include + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use WiFi101_Generic from WiFiWebServer + #endif + #else + #include + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use WiFi101 from WiFiWebServer + #endif + #endif + +#elif USE_WIFI_CUSTOM + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use Custom WiFi for WiFiWebServer + #endif +#else + #include + + #if (_WIFI_LOGLEVEL_ > 2) + #warning Use WiFi.h from WiFiWebServer + #endif +#endif + +//////////////////////////////////////// + +#include "utility/mimetable.h" +#include "utility/RingBuffer.h" + +//////////////////////////////////////// + +// KH, For PROGMEM commands +// ESP32/ESP8266 includes by default, and memccpy_P was already defined there +#if !(ESP32 || ESP8266 || defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4)) + #include + #define memccpy_P(dest, src, c, n) memccpy((dest), (src), (c), (n)) +#endif + +//////////////////////////////////////// + +// Permit redefinition of SENDCONTENT_P_BUFFER_SZ in sketch, default is 4K, minimum is 256 bytes +#ifndef SENDCONTENT_P_BUFFER_SZ + #define SENDCONTENT_P_BUFFER_SZ 4096 + + #if (_WIFI_LOGLEVEL_ > 2) + #warning SENDCONTENT_P_BUFFER_SZ using default 4 Kbytes + #endif +#else + #if (SENDCONTENT_P_BUFFER_SZ < 256) + #undef SENDCONTENT_P_BUFFER_SZ + #define SENDCONTENT_P_BUFFER_SZ 256 + + #if (_WIFI_LOGLEVEL_ > 2) + #warning SENDCONTENT_P_BUFFER_SZ reset to min 256 bytes + #endif + #endif +#endif + +//////////////////////////////////////// + +#ifndef PGM_VOID_P + #define PGM_VOID_P const void * +#endif + +//////////////////////////////////////// + +enum HTTPMethod +{ + HTTP_ANY, + HTTP_GET, + HTTP_HEAD, + HTTP_POST, + HTTP_PUT, + HTTP_PATCH, + HTTP_DELETE, + HTTP_OPTIONS +}; + +enum HTTPUploadStatus +{ + UPLOAD_FILE_START, + UPLOAD_FILE_WRITE, + UPLOAD_FILE_END, + UPLOAD_FILE_ABORTED +}; + +enum HTTPClientStatus +{ + HC_NONE, + HC_WAIT_READ, + HC_WAIT_CLOSE +}; + +enum HTTPAuthMethod +{ + BASIC_AUTH, + DIGEST_AUTH +}; + +//////////////////////////////////////// + +#define HTTP_DOWNLOAD_UNIT_SIZE 1460 + +// Permit user to increase HTTP_UPLOAD_BUFLEN larger than default 2K +//#define HTTP_UPLOAD_BUFLEN 2048 +#if !defined(HTTP_UPLOAD_BUFLEN) + #define HTTP_UPLOAD_BUFLEN 2048 +#endif + +#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request +#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive +#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed +#define HTTP_MAX_CLOSE_WAIT 2000 //ms to wait for the client to close the connection + +#define CONTENT_LENGTH_UNKNOWN ((size_t) -1) +#define CONTENT_LENGTH_NOT_SET ((size_t) -2) + +//////////////////////////////////////// + +#define RETURN_NEWLINE "\r\n" + +#include +#include + +typedef std::string WWString; + +//////////////////////////////////////// + +#include "Uri.h" + +//////////////////////////////////////// + +class WiFiWebServer; + +typedef struct +{ + HTTPUploadStatus status; + String filename; + String name; + String type; + size_t totalSize; // file size + size_t currentSize; // size of data currently in buf + size_t contentLength; // size of entire post request, file size + headers and other request data. + uint8_t buf[HTTP_UPLOAD_BUFLEN]; +} HTTPUpload; + +//////////////////////////////////////// + +#include "utility/RequestHandler.h" + +#if (ESP32 || ESP8266) + #include "FS.h" +#endif + +//////////////////////////////////////// +//////////////////////////////////////// + +class WiFiWebServer +{ + public: + +#if (ESP32 || ESP8266) + WiFiWebServer(IPAddress addr, int port = 80); +#endif + + WiFiWebServer(int port = 80); + virtual ~WiFiWebServer(); + + virtual void begin(); + +#if USE_NEW_WEBSERVER_VERSION + virtual void begin(uint16_t port); +#endif + + virtual void handleClient(); + + virtual void close(); + void stop(); + + bool authenticate(const char * username, const char * password); + void requestAuthentication(); + + typedef vl::Func THandlerFunction; + //typedef std::function THandlerFunction; + //typedef void (*THandlerFunction)(void); + + void on(const String &uri, THandlerFunction handler); + void on(const String &uri, HTTPMethod method, THandlerFunction fn); + void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); + void addHandler(RequestHandler* handler); + void onNotFound(THandlerFunction fn); //called when handler is not assigned + void onFileUpload(THandlerFunction fn); //handle file uploads + + //////////////////////////////////////// + + inline String uri() + { + return _currentUri; + } + + //////////////////////////////////////// + + inline HTTPMethod method() + { + return _currentMethod; + } + + //////////////////////////////////////// + + virtual inline WiFiClient client() + { + return _currentClient; + } + + //////////////////////////////////////// + +#if USE_NEW_WEBSERVER_VERSION + inline HTTPUpload& upload() + { + return *_currentUpload; + } +#else + inline HTTPUpload& upload() + { + return _currentUpload; + } +#endif + + //////////////////////////////////////// + + String pathArg(unsigned int i); // get request path argument by number + + String arg(const String& name); // get request argument value by name + String arg(int i); // get request argument value by number + String argName(int i); // get request argument name by number + + int args(); // get arguments count + bool hasArg(const String& name); // check if argument exists + void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect + String header(const String& name); // get request header value by name + String header(int i); // get request header value by number + String headerName(int i); // get request header name by number + int headers(); // get header count + bool hasHeader(const String& name); // check if header exists + + //////////////////////////////////////// + + inline int clientContentLength() + { + return _clientContentLength; + } + + //////////////////////////////////////// + + String hostHeader(); // get request host header if available or empty String if not + + // send response to the client + // code - HTTP response code, can be 200 or 404 + // content_type - HTTP content type, like "text/plain" or "image/png" + // content - actual content body + void send(int code, const char* content_type = NULL, const String& content = String("")); + void send(int code, char* content_type, const String& content); + void send(int code, const String& content_type, const String& content); + + void send(int code, char* content_type, const String& content, size_t contentLength); + void send(int code, const char* content_type, const char* content); + void send(int code, const char* content_type, const char* content, size_t contentLength); + + //////////////////////////////////////// + + inline void enableDelay(bool value) + { + _nullDelay = value; + } + + //////////////////////////////////////// + + inline void enableCORS(bool value = true) + { + _corsEnabled = value; + } + + //////////////////////////////////////// + + inline void enableCrossOrigin(bool value = true) + { + enableCORS(value); + } + + //////////////////////////////////////// + + void setContentLength(size_t contentLength); + void sendHeader(const String& name, const String& value, bool first = false); + void sendContent(const String& content); + void sendContent(const String& content, size_t contentLength); + + // New + void sendContent(const char* content, size_t contentLength); + ////// + + // KH, Restore PROGMEM commands + void send_P(int code, PGM_P content_type, PGM_P content); + void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength); + + void sendContent_P(PGM_P content); + void sendContent_P(PGM_P content, size_t contentLength); + ////// + + static String urlDecode(const String& text); + + //////////////////////////////////////// + +#if !(ESP32 || ESP8266) + template size_t streamFile(T &file, const String& contentType) + { + using namespace mime; + setContentLength(file.size()); + + if (String(file.name()).endsWith(mimeTable[gz].endsWith) && contentType != mimeTable[gz].mimeType && contentType != mimeTable[none].mimeType) + { + sendHeader("Content-Encoding", "gzip"); + } + + send(200, contentType, ""); + + return _currentClient.write(file); + } + + //////////////////////////////////////// + +#else + + //////////////////////////////////////// + + void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL ); // serve static pages from file system + + // Handle a GET request by sending a response header and stream file content to response body + //template + //size_t streamFile(T &file, const String& contentType) + //{ + // return streamFile(file, contentType, HTTP_GET); + //} + + // Implement GET and HEAD requests for files. + // Stream body on HTTP_GET but not on HTTP_HEAD requests. + template + size_t streamFile(T &file, const String& contentType, const int code = 200) + { + _streamFileCore(file.size(), file.name(), contentType, code); + + return _currentClient.write(file); + } + + //////////////////////////////////////// + +#endif + + protected: + + //////////////////////////////////////// + + virtual size_t _currentClientWrite(const char* buffer, size_t length) + { + return _currentClient.write( buffer, length ); + } + + //////////////////////////////////////// + +#if (ESP32 || ESP8266) + virtual size_t _currentClientWrite_P(PGM_P buffer, size_t length) + { + return _currentClient.write_P( buffer, length ); + } +#endif + + //////////////////////////////////////// + + void _addRequestHandler(RequestHandler* handler); + void _handleRequest(); + void _finalizeResponse(); + bool _parseRequest(WiFiClient& client); + +#if USE_NEW_WEBSERVER_VERSION + void _parseArguments(const String& data); + int _parseArgumentsPrivate(const String& data, vl::Func handler); + bool _parseForm(WiFiClient& client, const String& boundary, uint32_t len); +#else + void _parseArguments(const String& data); + bool _parseForm(WiFiClient& client, const String& boundary, uint32_t len); +#endif + + static String _responseCodeToString(int code); + bool _parseFormUploadAborted(); + void _uploadWriteByte(uint8_t b); + int _uploadReadByte(WiFiClient& client); + void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength); + void _prepareHeader(WWString& response, int code, const char* content_type, size_t contentLength); + bool _collectHeader(const char* headerName, const char* headerValue); + +#if (ESP32 || ESP8266) + void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType, const int code = 200); + + //////////////////////////////////////// + + template + size_t _customClientWrite(T &file) + { + char buffer[256]; + size_t contentLength = 0; + size_t bytesRead = 0; + + // read up to sizeof(buffer) bytes + while ((bytesRead = file.readBytes(buffer, sizeof(buffer))) > 0) + { + _currentClient.write(buffer, bytesRead); + contentLength += bytesRead; + } + + return contentLength; + } + + //////////////////////////////////////// + +#endif + + struct RequestArgument + { + String key; + String value; + }; + + bool _corsEnabled; + + WiFiServer _server; + + WiFiClient _currentClient; + HTTPMethod _currentMethod; + String _currentUri; + uint8_t _currentVersion; + HTTPClientStatus _currentStatus; + unsigned long _statusChange; + + bool _nullDelay; + + RequestHandler* _currentHandler = nullptr; + RequestHandler* _firstHandler = nullptr; + RequestHandler* _lastHandler = nullptr; + THandlerFunction _notFoundHandler; + THandlerFunction _fileUploadHandler; + + int _currentArgCount; + RequestArgument* _currentArgs = nullptr; + +#if USE_NEW_WEBSERVER_VERSION + HTTPUpload* _currentUpload = nullptr; + int _postArgsLen; + RequestArgument* _postArgs = nullptr; +#else + HTTPUpload _currentUpload; +#endif + + int _headerKeysCount; + RequestArgument* _currentHeaders = nullptr; + size_t _contentLength; + int _clientContentLength; // "Content-Length" from header of incoming POST or GET request + String _responseHeaders; + String _hostHeader; + bool _chunked; +}; + +#endif // WiFiWebServer_HPP diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_HttpClient.cpp b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_HttpClient.cpp new file mode 100644 index 000000000..55bcc61f4 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_HttpClient.cpp @@ -0,0 +1,1061 @@ +/**************************************************************************************************************************** + WiFi_HttpClient.cpp - Dead simple HTTP WebClient. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// Class to simplify HTTP fetching on Arduino +// (c) Copyright 2010-2011 MCQN Ltd +// Released under Apache License, version 2.0 + +#define _WIFI_LOGLEVEL_ 0 + + +#include "WiFi_HTTPClient/WiFi_HttpClient.h" +#include "libb64/base64.h" + +#include "utility/WiFiDebug.h" + +//////////////////////////////////////// + +// Initialize constants +const char* WiFiHttpClient::kUserAgent = "Arduino/2.2.0"; +const char* WiFiHttpClient::kContentLengthPrefix = HTTP_HEADER_CONTENT_LENGTH ": "; +const char* WiFiHttpClient::kTransferEncodingChunked = HTTP_HEADER_TRANSFER_ENCODING ": " HTTP_HEADER_VALUE_CHUNKED; + +//////////////////////////////////////// + +WiFiHttpClient::WiFiHttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort) + : iClient(&aClient), iServerName(aServerName), iServerAddress(), iServerPort(aServerPort), + iConnectionClose(true), iSendDefaultRequestHeaders(true) +{ + resetState(); +} + +//////////////////////////////////////// + +WiFiHttpClient::WiFiHttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort) + : WiFiHttpClient(aClient, aServerName.c_str(), aServerPort) +{ +} + +//////////////////////////////////////// + +WiFiHttpClient::WiFiHttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort) + : iClient(&aClient), iServerName(NULL), iServerAddress(aServerAddress), iServerPort(aServerPort), + iConnectionClose(true), iSendDefaultRequestHeaders(true) +{ + resetState(); +} + +//////////////////////////////////////// + +void WiFiHttpClient::resetState() +{ + iState = eIdle; + iStatusCode = 0; + iContentLength = kNoContentLengthHeader; + + iBodyLengthConsumed = 0; + iContentLengthPtr = kContentLengthPrefix; + iTransferEncodingChunkedPtr = kTransferEncodingChunked; + + iIsChunked = false; + iChunkLength = 0; + iHttpResponseTimeout = kHttpResponseTimeout; +} + +//////////////////////////////////////// + +void WiFiHttpClient::stop() +{ + iClient->stop(); + resetState(); +} + +//////////////////////////////////////// + +void WiFiHttpClient::connectionKeepAlive() +{ + iConnectionClose = false; +} + +//////////////////////////////////////// + +void WiFiHttpClient::noDefaultRequestHeaders() +{ + iSendDefaultRequestHeaders = false; +} + +//////////////////////////////////////// + +void WiFiHttpClient::beginRequest() +{ + iState = eRequestStarted; +} + +//////////////////////////////////////// + +int WiFiHttpClient::startRequest(const char* aURLPath, const char* aHttpMethod, + const char* aContentType, int aContentLength, const byte aBody[]) +{ + if (iState == eReadingBody || iState == eReadingChunkLength || iState == eReadingBodyChunk) + { + flushClientRx(); + + resetState(); + } + + tHttpState initialState = iState; + + if ((eIdle != iState) && (eRequestStarted != iState)) + { + return HTTP_ERROR_API; + } + + if (iConnectionClose || !iClient->connected()) + { + if (iServerName) + { + if (! ( iClient->connect(iServerName, iServerPort) > 0) ) + { + WS_LOGDEBUG(F("WiFiHttpClient::startRequest: Connection failed")); + + return HTTP_ERROR_CONNECTION_FAILED; + } + } + else + { + if (! ( iClient->connect(iServerAddress, iServerPort) > 0) ) + { + WS_LOGDEBUG(F("WiFiHttpClient::startRequest: Connection failed")); + + return HTTP_ERROR_CONNECTION_FAILED; + } + } + } + else + { + WS_LOGDEBUG(F("WiFiHttpClient::startRequest: Connection already open")); + } + + // Now we're connected, send the first part of the request + int ret = sendInitialHeaders(aURLPath, aHttpMethod); + + if (HTTP_SUCCESS == ret) + { + if (aContentType) + { + sendHeader(HTTP_HEADER_CONTENT_TYPE, aContentType); + } + + if (aContentLength > 0) + { + sendHeader(HTTP_HEADER_CONTENT_LENGTH, aContentLength); + } + + bool hasBody = (aBody && aContentLength > 0); + + if (initialState == eIdle || hasBody) + { + // This was a simple version of the API, so terminate the headers now + finishHeaders(); + } + + // else we'll call it in endRequest or in the first call to print, etc. + + if (hasBody) + { + write(aBody, aContentLength); + } + } + + return ret; +} + +//////////////////////////////////////// + +int WiFiHttpClient::sendInitialHeaders(const char* aURLPath, const char* aHttpMethod) +{ + WS_LOGDEBUG(F("WiFiHttpClient::startRequest: Connected")); + + // Send the HTTP command, i.e. "GET /somepath/ HTTP/1.0" + iClient->print(aHttpMethod); + iClient->print(" "); + + iClient->print(aURLPath); + iClient->println(" HTTP/1.1"); + + if (iSendDefaultRequestHeaders) + { + // The host header, if required + if (iServerName) + { + iClient->print("Host: "); + iClient->print(iServerName); + + if (iServerPort != kHttpPort) + { + iClient->print(":"); + iClient->print(iServerPort); + } + + iClient->println(); + } + + // And user-agent string + sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent); + ////// + } + + if (iConnectionClose) + { + // Tell the server to + // close this connection after we're done + sendHeader(HTTP_HEADER_CONNECTION, "close"); + } + + // Everything has gone well + iState = eRequestStarted; + + return HTTP_SUCCESS; +} + +//////////////////////////////////////// + +void WiFiHttpClient::sendHeader(const char* aHeader) +{ + iClient->println(aHeader); +} + +//////////////////////////////////////// + +void WiFiHttpClient::sendHeader(const char* aHeaderName, const char* aHeaderValue) +{ + iClient->print(aHeaderName); + iClient->print(": "); + iClient->println(aHeaderValue); +} + +//////////////////////////////////////// + +void WiFiHttpClient::sendHeader(const char* aHeaderName, const int aHeaderValue) +{ + iClient->print(aHeaderName); + iClient->print(": "); + iClient->println(aHeaderValue); +} + +//////////////////////////////////////// + +void WiFiHttpClient::sendBasicAuth(const char* aUser, const char* aPassword) +{ + // Send the initial part of this header line + iClient->print("Authorization: Basic "); + // Now Base64 encode "aUser:aPassword" and send that + // This seems trickier than it should be but it's mostly to avoid either + // (a) some arbitrarily sized buffer which hopes to be big enough, or + // (b) allocating and freeing memory + // ...so we'll loop through 3 bytes at a time, outputting the results as we + // go. + // In Base64, each 3 bytes of unencoded data become 4 bytes of encoded data + unsigned char input[3]; + unsigned char output[5]; // Leave space for a '\0' terminator so we can easily print + + int userLen = strlen(aUser); + int passwordLen = strlen(aPassword); + int inputOffset = 0; + + for (int i = 0; i < (userLen + 1 + passwordLen); i++) + { + // Copy the relevant input byte into the input + if (i < userLen) + { + input[inputOffset++] = aUser[i]; + } + else if (i == userLen) + { + input[inputOffset++] = ':'; + } + else + { + input[inputOffset++] = aPassword[i - (userLen + 1)]; + } + + // See if we've got a chunk to encode + if ( (inputOffset == 3) || (i == userLen + passwordLen) ) + { + // We've either got to a 3-byte boundary, or we've reached then end + base64_encode(input, inputOffset, output, 4); + // NUL-terminate the output string + output[4] = '\0'; + // And write it out + iClient->print((char*)output); + // FIXME We might want to fill output with '=' characters if base64_encode doesn't + // FIXME do it for us when we're encoding the final chunk + inputOffset = 0; + } + } + + // And end the header we've sent + iClient->println(); +} + +//////////////////////////////////////// + +void WiFiHttpClient::finishHeaders() +{ + iClient->println(); + iState = eRequestSent; +} + +//////////////////////////////////////// + +void WiFiHttpClient::flushClientRx() +{ + while (iClient->available()) + { + iClient->read(); + } +} + +//////////////////////////////////////// + +void WiFiHttpClient::endRequest() +{ + beginBody(); +} + +//////////////////////////////////////// + +void WiFiHttpClient::beginBody() +{ + if (iState < eRequestSent) + { + // We still need to finish off the headers + finishHeaders(); + } + + // else the end of headers has already been sent, so nothing to do here +} + +//////////////////////////////////////// + +int WiFiHttpClient::get(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_GET); +} + +//////////////////////////////////////// + +int WiFiHttpClient::get(const String& aURLPath) +{ + return get(aURLPath.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::post(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_POST); +} + +//////////////////////////////////////// + +int WiFiHttpClient::post(const String& aURLPath) +{ + return post(aURLPath.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::post(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return post(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::post(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return post(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::post(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_POST, aContentType, aContentLength, aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::put(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_PUT); +} + +//////////////////////////////////////// + +int WiFiHttpClient::put(const String& aURLPath) +{ + return put(aURLPath.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::put(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return put(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::put(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return put(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::put(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_PUT, aContentType, aContentLength, aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::patch(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_PATCH); +} + +//////////////////////////////////////// + +int WiFiHttpClient::patch(const String& aURLPath) +{ + return patch(aURLPath.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::patch(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return patch(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::patch(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return patch(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::patch(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_PATCH, aContentType, aContentLength, aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::del(const char* aURLPath) +{ + return startRequest(aURLPath, HTTP_METHOD_DELETE); +} + +//////////////////////////////////////// + +int WiFiHttpClient::del(const String& aURLPath) +{ + return del(aURLPath.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::del(const char* aURLPath, const char* aContentType, const char* aBody) +{ + return del(aURLPath, aContentType, strlen(aBody), (const byte*)aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::del(const String& aURLPath, const String& aContentType, const String& aBody) +{ + return del(aURLPath.c_str(), aContentType.c_str(), aBody.length(), (const byte*)aBody.c_str()); +} + +//////////////////////////////////////// + +int WiFiHttpClient::del(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]) +{ + return startRequest(aURLPath, HTTP_METHOD_DELETE, aContentType, aContentLength, aBody); +} + +//////////////////////////////////////// + +int WiFiHttpClient::responseStatusCode() +{ + if (iState < eRequestSent) + { + return HTTP_ERROR_API; + } + + // The first line will be of the form Status-Line: + // HTTP-Version SP Status-Code SP Reason-Phrase CRLF + // Where HTTP-Version is of the form: + // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT + + int c = '\0'; + + do + { + // Make sure the status code is reset, and likewise the state. This + // lets us easily cope with 1xx informational responses by just + // ignoring them really, and reading the next line for a proper response + iStatusCode = 0; + iState = eRequestSent; + + unsigned long timeoutStart = millis(); + + // Psuedo-regexp we're expecting before the status-code + const char* statusPrefix = "HTTP/*.* "; + const char* statusPtr = statusPrefix; + + // Whilst we haven't timed out & haven't reached the end of the headers + while ((c != '\n') && ( (millis() - timeoutStart) < iHttpResponseTimeout )) + { + if (available()) + { + c = read(); + + // KH test + WS_LOGDEBUG1(F("WiFiHttpClient::startRequest: c ="), String(c)); + ////// + + if (c != -1) + { + switch (iState) + { + case eRequestSent: + + // We haven't reached the status code yet + if ( (*statusPtr == '*') || (*statusPtr == c) ) + { + // This character matches, just move along + statusPtr++; + + if (*statusPtr == '\0') + { + // We've reached the end of the prefix + iState = eReadingStatusCode; + } + } + else + { + return HTTP_ERROR_INVALID_RESPONSE; + } + + break; + + case eReadingStatusCode: + if (isdigit(c)) + { + // This assumes we won't get more than the 3 digits we + // want + iStatusCode = iStatusCode * 10 + (c - '0'); + } + else + { + // We've reached the end of the status code + // We could sanity check it here or double-check for ' ' + // rather than anything else, but let's be lenient + iState = eStatusCodeRead; + } + + break; + + case eStatusCodeRead: + // We're just waiting for the end of the line now + break; + + default: + break; + }; + + // We read something, reset the timeout counter + timeoutStart = millis(); + } + } + else + { + // We haven't got any data, so let's pause to allow some to + // arrive + delay(kHttpWaitForDataDelay); + } + } + + if ( (c == '\n') && (iStatusCode < 200 && iStatusCode != 101) ) + { + // We've reached the end of an informational status line + c = '\0'; // Clear c so we'll go back into the data reading loop + } + } + + // If we've read a status code successfully but it's informational (1xx) + // loop back to the start + while ( (iState == eStatusCodeRead) && (iStatusCode < 200 && iStatusCode != 101) ); + + if ( (c == '\n') && (iState == eStatusCodeRead) ) + { + // We've read the status-line successfully + return iStatusCode; + } + else if (c != '\n') + { + // We must've timed out before we reached the end of the line + return HTTP_ERROR_TIMED_OUT; + } + else + { + // This wasn't a properly formed status line, or at least not one we + // could understand + return HTTP_ERROR_INVALID_RESPONSE; + } +} + +//////////////////////////////////////// + +int WiFiHttpClient::skipResponseHeaders() +{ + // Just keep reading until we finish reading the headers or time out + unsigned long timeoutStart = millis(); + + // Whilst we haven't timed out & haven't reached the end of the headers + while ((!endOfHeadersReached()) && ( (millis() - timeoutStart) < iHttpResponseTimeout )) + { + if (available()) + { + (void)readHeader(); + // We read something, reset the timeout counter + timeoutStart = millis(); + } + else + { + // We haven't got any data, so let's pause to allow some to + // arrive + delay(kHttpWaitForDataDelay); + } + } + + if (endOfHeadersReached()) + { + // Success + return HTTP_SUCCESS; + } + else + { + // We must've timed out + return HTTP_ERROR_TIMED_OUT; + } +} + +//////////////////////////////////////// + +bool WiFiHttpClient::endOfHeadersReached() +{ + return (iState == eReadingBody || iState == eReadingChunkLength || iState == eReadingBodyChunk); +}; + +//////////////////////////////////////// + +int WiFiHttpClient::contentLength() +{ + // skip the response headers, if they haven't been read already + if (!endOfHeadersReached()) + { + skipResponseHeaders(); + } + + return iContentLength; +} + +//////////////////////////////////////// + +String WiFiHttpClient::responseBody() +{ + int bodyLength = contentLength(); + String response; + + WS_LOGDEBUG1(F("WiFiHttpClient::responseBody => bodyLength ="), String(bodyLength)); + + if (bodyLength > 0) + { + // try to reserve bodyLength bytes + if (response.reserve(bodyLength) == 0) + { + // String reserve failed + return String((const char*)NULL); + } + } + + // keep on timedRead'ing, until: + // - we have a content length: body length equals consumed or no bytes + // available + // - no content length: no bytes are available + while (iBodyLengthConsumed != bodyLength) + { + // KH test + int c = timedRead(); + //int c = iClient->read(); + + WS_LOGDEBUG1(F("WiFiHttpClient::responseBody => c ="), String(c)); + ////// + + if (c == -1) + { + // read timed out, done + break; + } + + if (!response.concat((char)c)) + { + // adding char failed + return String((const char*)NULL); + } + } + + if (bodyLength > 0 && (unsigned int)bodyLength != response.length()) + { + // failure, we did not read in reponse content length bytes + return String((const char*)NULL); + } + + return response; +} + +//////////////////////////////////////// + +bool WiFiHttpClient::endOfBodyReached() +{ + if (endOfHeadersReached() && (contentLength() != kNoContentLengthHeader)) + { + // We've got to the body and we know how long it will be + return (iBodyLengthConsumed >= contentLength()); + } + + return false; +} + +//////////////////////////////////////// + +int WiFiHttpClient::available() +{ + if (iState == eReadingChunkLength) + { + while (iClient->available()) + { + char c = iClient->read(); + + if (c == '\n') + { + iState = eReadingBodyChunk; + break; + } + else if (c == '\r') + { + // no-op + } + else if (isHexadecimalDigit(c)) + { + char digit[2] = {c, '\0'}; + + iChunkLength = (iChunkLength * 16) + strtol(digit, NULL, 16); + } + } + } + + if (iState == eReadingBodyChunk && iChunkLength == 0) + { + iState = eReadingChunkLength; + } + + if (iState == eReadingChunkLength) + { + return 0; + } + + int clientAvailable = iClient->available(); + + if (iState == eReadingBodyChunk) + { + return min(clientAvailable, iChunkLength); + } + else + { + return clientAvailable; + } +} + +//////////////////////////////////////// + +int WiFiHttpClient::read() +{ + if (iIsChunked && !available()) + { + return -1; + } + + int ret = iClient->read(); + + if (ret >= 0) + { + if (endOfHeadersReached() && iContentLength > 0) + { + // We're outputting the body now and we've seen a Content-Length header + // So keep track of how many bytes are left + iBodyLengthConsumed++; + } + + if (iState == eReadingBodyChunk) + { + iChunkLength--; + + if (iChunkLength == 0) + { + iState = eReadingChunkLength; + } + } + } + + return ret; +} + +//////////////////////////////////////// + +bool WiFiHttpClient::headerAvailable() +{ + // clear the currently store header line + iHeaderLine = ""; + + while (!endOfHeadersReached()) + { + // read a byte from the header + int c = readHeader(); + + if (c == '\r' || c == '\n') + { + if (iHeaderLine.length()) + { + // end of the line, all done + break; + } + else + { + // ignore any CR or LF characters + continue; + } + } + + // append byte to header line + iHeaderLine += (char)c; + } + + return (iHeaderLine.length() > 0); +} + +//////////////////////////////////////// + +String WiFiHttpClient::readHeaderName() +{ + int colonIndex = iHeaderLine.indexOf(':'); + + if (colonIndex == -1) + { + return ""; + } + + return iHeaderLine.substring(0, colonIndex); +} + +//////////////////////////////////////// + +String WiFiHttpClient::readHeaderValue() +{ + int colonIndex = iHeaderLine.indexOf(':'); + int startIndex = colonIndex + 1; + + if (colonIndex == -1) + { + return ""; + } + + // trim any leading whitespace + while (startIndex < (int)iHeaderLine.length() && isSpace(iHeaderLine[startIndex])) + { + startIndex++; + } + + return iHeaderLine.substring(startIndex); +} + +//////////////////////////////////////// + +int WiFiHttpClient::read(uint8_t *buf, size_t size) +{ + int ret = iClient->read(buf, size); + + if (endOfHeadersReached() && iContentLength > 0) + { + // We're outputting the body now and we've seen a Content-Length header + // So keep track of how many bytes are left + if (ret >= 0) + { + iBodyLengthConsumed += ret; + } + } + + return ret; +} + +//////////////////////////////////////// + +int WiFiHttpClient::readHeader() +{ + char c = read(); + + if (endOfHeadersReached()) + { + // We've passed the headers, but rather than return an error, we'll just + // act as a slightly less efficient version of read() + return c; + } + + // Whilst reading out the headers to whoever wants them, we'll keep an + // eye out for the "Content-Length" header + switch (iState) + { + case eStatusCodeRead: + + // We're at the start of a line, or somewhere in the middle of reading + // the Content-Length prefix + if (*iContentLengthPtr == c) + { + // This character matches, just move along + iContentLengthPtr++; + + if (*iContentLengthPtr == '\0') + { + // We've reached the end of the prefix + iState = eReadingContentLength; + // Just in case we get multiple Content-Length headers, this + // will ensure we just get the value of the last one + iContentLength = 0; + iBodyLengthConsumed = 0; + } + } + else if (*iTransferEncodingChunkedPtr == c) + { + // This character matches, just move along + iTransferEncodingChunkedPtr++; + + if (*iTransferEncodingChunkedPtr == '\0') + { + // We've reached the end of the Transfer Encoding: chunked header + iIsChunked = true; + iState = eSkipToEndOfHeader; + } + } + else if (((iContentLengthPtr == kContentLengthPrefix) && (iTransferEncodingChunkedPtr == kTransferEncodingChunked)) + && (c == '\r')) + { + // We've found a '\r' at the start of a line, so this is probably + // the end of the headers + iState = eLineStartingCRFound; + } + else + { + // This isn't the Content-Length or Transfer Encoding chunked header, skip to the end of the line + iState = eSkipToEndOfHeader; + } + + break; + + case eReadingContentLength: + if (isdigit(c)) + { + iContentLength = iContentLength * 10 + (c - '0'); + } + else + { + // We've reached the end of the content length + // We could sanity check it here or double-check for "\r\n" + // rather than anything else, but let's be lenient + iState = eSkipToEndOfHeader; + } + + break; + + case eLineStartingCRFound: + if (c == '\n') + { + if (iIsChunked) + { + iState = eReadingChunkLength; + iChunkLength = 0; + } + else + { + iState = eReadingBody; + } + } + + break; + + default: + // We're just waiting for the end of the line now + break; + }; + + if ( (c == '\n') && !endOfHeadersReached() ) + { + // We've got to the end of this line, start processing again + iState = eStatusCodeRead; + iContentLengthPtr = kContentLengthPrefix; + iTransferEncodingChunkedPtr = kTransferEncodingChunked; + } + + // And return the character read to whoever wants it + return c; +} diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_HttpClient.h b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_HttpClient.h new file mode 100644 index 000000000..00541a30e --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_HttpClient.h @@ -0,0 +1,576 @@ +/**************************************************************************************************************************** + WiFi_HttpClient.h - Dead simple HTTP WebClient. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// Class to simplify HTTP fetching on Arduino +// (c) Copyright MCQN Ltd. 2010-2012 +// Released under Apache License, version 2.0 + +#pragma once + +#ifndef WiFi_HttpClient_H +#define WiFi_HttpClient_H + +#include +#include +#include "Client.h" + +#include "utility/WiFiDebug.h" + +//////////////////////////////////////// + +static const int HTTP_SUCCESS = 0; + +// The end of the headers has been reached. This consumes the '\n' +// Could not connect to the server +static const int HTTP_ERROR_CONNECTION_FAILED = -1; + +// This call was made when the WiFiHttpClient class wasn't expecting it +// to be called. Usually indicates your code is using the class +// incorrectly +static const int HTTP_ERROR_API = -2; + +// Spent too long waiting for a reply +static const int HTTP_ERROR_TIMED_OUT = -3; + +// The response from the server is invalid, is it definitely an HTTP +// server? +static const int HTTP_ERROR_INVALID_RESPONSE = -4; + +//////////////////////////////////////// + +// Define some of the common methods and headers here +// That lets other code reuse them without having to declare another copy +// of them, so saves code space and RAM +#define HTTP_METHOD_GET "GET" +#define HTTP_METHOD_POST "POST" +#define HTTP_METHOD_PUT "PUT" +#define HTTP_METHOD_PATCH "PATCH" +#define HTTP_METHOD_DELETE "DELETE" +#define HTTP_HEADER_CONTENT_LENGTH "Content-Length" +#define HTTP_HEADER_CONTENT_TYPE "Content-Type" +#define HTTP_HEADER_CONNECTION "Connection" +#define HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding" +#define HTTP_HEADER_USER_AGENT "User-Agent" +#define HTTP_HEADER_VALUE_CHUNKED "chunked" + +//////////////////////////////////////// + +// Number of milliseconds that we wait each time there isn't any data +// available to be read (during status code and header processing) +#define kHttpWaitForDataDelay 1000L + +// Number of milliseconds that we'll wait in total without receiveing any +// data before returning HTTP_ERROR_TIMED_OUT (during status code and header +// processing) +#define kHttpResponseTimeout 30000L + +//////////////////////////////////////// + +class WiFiHttpClient : public Client +{ + public: + static const int kNoContentLengthHeader = -1; + static const int kHttpPort = 80; + static const char* kUserAgent; + + // FIXME Write longer API request, using port and user-agent, example + // FIXME Update tempToPachube example to calculate Content-Length correctly + + WiFiHttpClient(Client& aClient, const char* aServerName, uint16_t aServerPort = kHttpPort); + WiFiHttpClient(Client& aClient, const String& aServerName, uint16_t aServerPort = kHttpPort); + WiFiHttpClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = kHttpPort); + + /** Start a more complex request. + Use this when you need to send additional headers in the request, + but you will also need to call endRequest() when you are finished. + */ + void beginRequest(); + + /** End a more complex request. + Use this when you need to have sent additional headers in the request, + but you will also need to call beginRequest() at the start. + */ + void endRequest(); + + /** Start the body of a more complex request. + Use this when you need to send the body after additional headers + in the request, but can optionally call endRequest() when + you are finished. + */ + void beginBody(); + + /** Connect to the server and start to send a GET request. + @param aURLPath Url to request + @return 0 if successful, else error + */ + int get(const char* aURLPath); + int get(const String& aURLPath); + + /** Connect to the server and start to send a POST request. + @param aURLPath Url to request + @return 0 if successful, else error + */ + int post(const char* aURLPath); + int post(const String& aURLPath); + + /** Connect to the server and send a POST request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int post(const char* aURLPath, const char* aContentType, const char* aBody); + int post(const String& aURLPath, const String& aContentType, const String& aBody); + int post(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); + + /** Connect to the server and start to send a PUT request. + @param aURLPath Url to request + @return 0 if successful, else error + */ + int put(const char* aURLPath); + int put(const String& aURLPath); + + /** Connect to the server and send a PUT request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int put(const char* aURLPath, const char* aContentType, const char* aBody); + int put(const String& aURLPath, const String& aContentType, const String& aBody); + int put(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); + + /** Connect to the server and start to send a PATCH request. + @param aURLPath Url to request + @return 0 if successful, else error + */ + int patch(const char* aURLPath); + int patch(const String& aURLPath); + + /** Connect to the server and send a PATCH request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int patch(const char* aURLPath, const char* aContentType, const char* aBody); + int patch(const String& aURLPath, const String& aContentType, const String& aBody); + int patch(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); + + /** Connect to the server and start to send a DELETE request. + @param aURLPath Url to request + @return 0 if successful, else error + */ + int del(const char* aURLPath); + int del(const String& aURLPath); + + /** Connect to the server and send a DELETE request + with body and content type + @param aURLPath Url to request + @param aContentType Content type of request body + @param aBody Body of the request + @return 0 if successful, else error + */ + int del(const char* aURLPath, const char* aContentType, const char* aBody); + int del(const String& aURLPath, const String& aContentType, const String& aBody); + int del(const char* aURLPath, const char* aContentType, int aContentLength, const byte aBody[]); + + /** Connect to the server and start to send the request. + If a body is provided, the entire request (including headers and body) will be sent + @param aURLPath Url to request + @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. + @param aContentType Content type of request body (optional) + @param aContentLength Length of request body (optional) + @param aBody Body of request (optional) + @return 0 if successful, else error + */ + int startRequest(const char* aURLPath, + const char* aHttpMethod, + const char* aContentType = NULL, + int aContentLength = -1, + const byte aBody[] = NULL); + + /** Send an additional header line. This can only be called in between the + calls to beginRequest and endRequest. + @param aHeader Header line to send, in its entirety (but without the + trailing CRLF. E.g. "Authorization: Basic YQDDCAIGES" + */ + void sendHeader(const char* aHeader); + + //////////////////////////////////////// + + void sendHeader(const String& aHeader) + { + sendHeader(aHeader.c_str()); + } + + //////////////////////////////////////// + + /** Send an additional header line. This is an alternate form of + sendHeader() which takes the header name and content as separate strings. + The call will add the ": " to separate the header, so for example, to + send a XXXXXX header call sendHeader("XXXXX", "Something") + @param aHeaderName Type of header being sent + @param aHeaderValue Value for that header + */ + void sendHeader(const char* aHeaderName, const char* aHeaderValue); + + //////////////////////////////////////// + + void sendHeader(const String& aHeaderName, const String& aHeaderValue) + { + sendHeader(aHeaderName.c_str(), aHeaderValue.c_str()); + } + + //////////////////////////////////////// + + /** Send an additional header line. This is an alternate form of + sendHeader() which takes the header name and content separately but where + the value is provided as an integer. + The call will add the ": " to separate the header, so for example, to + send a XXXXXX header call sendHeader("XXXXX", 123) + @param aHeaderName Type of header being sent + @param aHeaderValue Value for that header + */ + void sendHeader(const char* aHeaderName, const int aHeaderValue); + + //////////////////////////////////////// + + void sendHeader(const String& aHeaderName, const int aHeaderValue) + { + sendHeader(aHeaderName.c_str(), aHeaderValue); + } + + //////////////////////////////////////// + + /** Send a basic authentication header. This will encode the given username + and password, and send them in suitable header line for doing Basic + Authentication. + @param aUser Username for the authorization + @param aPassword Password for the user aUser + */ + void sendBasicAuth(const char* aUser, const char* aPassword); + + //////////////////////////////////////// + + void sendBasicAuth(const String& aUser, const String& aPassword) + { + sendBasicAuth(aUser.c_str(), aPassword.c_str()); + } + + //////////////////////////////////////// + + /** Get the HTTP status code contained in the response. + For example, 200 for successful request, 404 for file not found, etc. + */ + int responseStatusCode(); + + /** Check if a header is available to be read. + Use readHeaderName() to read header name, and readHeaderValue() to + read the header value + MUST be called after responseStatusCode() and before contentLength() + */ + bool headerAvailable(); + + /** Read the name of the current response header. + Returns empty string if a header is not available. + */ + String readHeaderName(); + + /** Read the vallue of the current response header. + Returns empty string if a header is not available. + */ + String readHeaderValue(); + + /** Read the next character of the response headers. + This functions in the same way as read() but to be used when reading + through the headers. Check whether or not the end of the headers has + been reached by calling endOfHeadersReached(), although after that point + this will still return data as read() would, but slightly less efficiently + MUST be called after responseStatusCode() and before contentLength() + @return The next character of the response headers + */ + int readHeader(); + + /** Skip any response headers to get to the body. + Use this if you don't want to do any special processing of the headers + returned in the response. You can also use it after you've found all of + the headers you're interested in, and just want to get on with processing + the body. + MUST be called after responseStatusCode() + @return HTTP_SUCCESS if successful, else an error code + */ + int skipResponseHeaders(); + + /** Test whether all of the response headers have been consumed. + @return true if we are now processing the response body, else false + */ + bool endOfHeadersReached(); + + /** Test whether the end of the body has been reached. + Only works if the Content-Length header was returned by the server + @return true if we are now at the end of the body, else false + */ + bool endOfBodyReached(); + + //////////////////////////////////////// + + virtual bool endOfStream() + { + return endOfBodyReached(); + }; + + //////////////////////////////////////// + + virtual bool completed() + { + return endOfBodyReached(); + }; + + //////////////////////////////////////// + + /** Return the length of the body. + Also skips response headers if they have not been read already + MUST be called after responseStatusCode() + @return Length of the body, in bytes, or kNoContentLengthHeader if no + Content-Length header was returned by the server + */ + int contentLength(); + + //////////////////////////////////////// + + /** Returns if the response body is chunked + @return true if response body is chunked, false otherwise + */ + int isResponseChunked() + { + return iIsChunked; + } + + //////////////////////////////////////// + + /** Return the response body as a String + Also skips response headers if they have not been read already + MUST be called after responseStatusCode() + @return response body of request as a String + */ + String responseBody(); + + /** Enables connection keep-alive mode + */ + void connectionKeepAlive(); + + /** Disables sending the default request headers (Host and User Agent) + */ + void noDefaultRequestHeaders(); + + //////////////////////////////////////// + + // Inherited from Print + // Note: 1st call to these indicates the user is sending the body, so if need + // Note: be we should finish the header first + virtual size_t write(uint8_t aByte) + { + if (iState < eRequestSent) + { + finishHeaders(); + }; + + return iClient-> write(aByte); + }; + + //////////////////////////////////////// + + virtual size_t write(const uint8_t *aBuffer, size_t aSize) + { + if (iState < eRequestSent) + { + finishHeaders(); + }; + + return iClient->write(aBuffer, aSize); + }; + + //////////////////////////////////////// + + // Inherited from Stream + virtual int available(); + + /** Read the next byte from the server. + @return Byte read or -1 if there are no bytes available. + */ + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + + //////////////////////////////////////// + + virtual int peek() + { + return iClient->peek(); + }; + + //////////////////////////////////////// + + virtual void flush() + { + iClient->flush(); + }; + + //////////////////////////////////////// + + // Inherited from Client + virtual int connect(IPAddress ip, uint16_t port) + { + return iClient->connect(ip, port); + }; + + //////////////////////////////////////// + + virtual int connect(const char *host, uint16_t port) + { + return iClient->connect(host, port); + }; + + //////////////////////////////////////// + + virtual void stop(); + + //////////////////////////////////////// + + virtual uint8_t connected() + { + return iClient->connected(); + }; + + //////////////////////////////////////// + + virtual operator bool() + { + return bool(iClient); + }; + + //////////////////////////////////////// + + virtual uint32_t httpResponseTimeout() + { + return iHttpResponseTimeout; + }; + + //////////////////////////////////////// + + virtual void setHttpResponseTimeout(uint32_t timeout) + { + iHttpResponseTimeout = timeout; + }; + + //////////////////////////////////////// + + protected: + /** Reset internal state data back to the "just initialised" state + */ + void resetState(); + + /** Send the first part of the request and the initial headers. + @param aURLPath Url to request + @param aHttpMethod Type of HTTP request to make, e.g. "GET", "POST", etc. + @return 0 if successful, else error + */ + int sendInitialHeaders(const char* aURLPath, + const char* aHttpMethod); + + /* Let the server know that we've reached the end of the headers + */ + void finishHeaders(); + + /** Reading any pending data from the client (used in connection keep alive mode) + */ + void flushClientRx(); + + static const char* kContentLengthPrefix; + static const char* kTransferEncodingChunked; + + //////////////////////////////////////// + + typedef enum + { + eIdle, + eRequestStarted, + eRequestSent, + eReadingStatusCode, + eStatusCodeRead, + eReadingContentLength, + eSkipToEndOfHeader, + eLineStartingCRFound, + eReadingBody, + eReadingChunkLength, + eReadingBodyChunk + } tHttpState; + + //////////////////////////////////////// + + // Client we're using + Client* iClient = nullptr; + // Server we are connecting to + const char* iServerName = nullptr; + IPAddress iServerAddress; + // Port of server we are connecting to + uint16_t iServerPort; + // Current state of the finite-state-machine + tHttpState iState; + // Stores the status code for the response, once known + int iStatusCode; + // Stores the value of the Content-Length header, if present + int iContentLength; + // How many bytes of the response body have been read by the user + int iBodyLengthConsumed; + // How far through a Content-Length header prefix we are + const char* iContentLengthPtr = nullptr; + // How far through a Transfer-Encoding chunked header we are + const char* iTransferEncodingChunkedPtr = nullptr; + // Stores if the response body is chunked + bool iIsChunked; + // Stores the value of the current chunk length, if present + int iChunkLength; + uint32_t iHttpResponseTimeout; + bool iConnectionClose; + bool iSendDefaultRequestHeaders; + String iHeaderLine; +}; + +#endif // WiFi_HttpClient_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_URLEncoder.cpp b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_URLEncoder.cpp new file mode 100644 index 000000000..4c7d7bc1e --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_URLEncoder.cpp @@ -0,0 +1,107 @@ +/**************************************************************************************************************************** + WiFi_URLEncoder.cpp - Dead simple HTTP WebClient. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// Library to simplify HTTP fetching on Arduino +// (c) Copyright Arduino. 2019 +// Released under Apache License, version 2.0 + +#define _WIFI_LOGLEVEL_ 0 + +#include "utility/WiFiDebug.h" +#include "WiFi_HTTPClient/WiFi_URLEncoder.h" + +//////////////////////////////////////// + +WiFiURLEncoderClass::WiFiURLEncoderClass() +{ +} + +//////////////////////////////////////// +WiFiURLEncoderClass::~WiFiURLEncoderClass() +{ +} + +//////////////////////////////////////// + +String WiFiURLEncoderClass::encode(const char* str) +{ + return encode(str, strlen(str)); +} + +//////////////////////////////////////// + +String WiFiURLEncoderClass::encode(const String& str) +{ + return encode(str.c_str(), str.length()); +} + +//////////////////////////////////////// + +String WiFiURLEncoderClass::encode(const char* str, int length) +{ + String encoded; + + encoded.reserve(length); + + for (int i = 0; i < length; i++) + { + char c = str[i]; + + const char HEX_DIGIT_MAPPER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + if (isAlphaNumeric(c) || (c == '-') || (c == '.') || (c == '_') || (c == '~')) + { + encoded += c; + } + else + { + char s[4]; + + s[0] = '%'; + s[1] = HEX_DIGIT_MAPPER[(c >> 4) & 0xf]; + s[2] = HEX_DIGIT_MAPPER[(c & 0x0f)]; + s[3] = 0; + + encoded += s; + } + } + + return encoded; +} + +//////////////////////////////////////// + +WiFiURLEncoderClass WiFiURLEncoder; diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_URLEncoder.h b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_URLEncoder.h new file mode 100644 index 000000000..59655a99d --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_URLEncoder.h @@ -0,0 +1,69 @@ +/**************************************************************************************************************************** + WiFi_URLEncoder.h - Dead simple HTTP WebClient. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// Library to simplify HTTP fetching on Arduino +// (c) Copyright Arduino. 2019 +// Released under Apache License, version 2.0 + +#pragma once + +#ifndef WiFi_URLEncoder_H +#define WiFi_URLEncoder_H + +#include + +#include "utility/WiFiDebug.h" + +//////////////////////////////////////// + +class WiFiURLEncoderClass +{ + public: + WiFiURLEncoderClass(); + virtual ~WiFiURLEncoderClass(); + + static String encode(const char* str); + static String encode(const String& str); + + private: + static String encode(const char* str, int length); +}; + +//////////////////////////////////////// + +extern WiFiURLEncoderClass WiFiURLEncoder; + +#endif // WiFi_URLEncoder_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_WebSocketClient.cpp b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_WebSocketClient.cpp new file mode 100644 index 000000000..5e909bfc3 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_WebSocketClient.cpp @@ -0,0 +1,459 @@ +/**************************************************************************************************************************** + WiFi_WebSocketClient.cpp - Dead simple HTTP WebSockets Client. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// (c) Copyright Arduino. 2016 +// Released under Apache License, version 2.0 + +#define _WIFI_LOGLEVEL_ 0 + +#include "libb64/base64.h" + +#include "utility/WiFiDebug.h" +#include "WiFi_HTTPClient/WiFi_WebSocketClient.h" + +//////////////////////////////////////// + +WiFiWebSocketClient::WiFiWebSocketClient(Client& aClient, const char* aServerName, uint16_t aServerPort) + : WiFiHttpClient(aClient, aServerName, aServerPort), + iTxStarted(false), + iRxSize(0) +{ +} + +//////////////////////////////////////// + +WiFiWebSocketClient::WiFiWebSocketClient(Client& aClient, const String& aServerName, uint16_t aServerPort) + : WiFiHttpClient(aClient, aServerName, aServerPort), + iTxStarted(false), + iRxSize(0) +{ +} + +//////////////////////////////////////// + +WiFiWebSocketClient::WiFiWebSocketClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort) + : WiFiHttpClient(aClient, aServerAddress, aServerPort), + iTxStarted(false), + iRxSize(0) +{ +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::begin(const char* aPath) +{ + // start the GET request + beginRequest(); + connectionKeepAlive(); + + int status = get(aPath); + + if (status == 0) + { + uint8_t randomKey[16]; + char base64RandomKey[25]; + + // create a random key for the connection upgrade + for (int i = 0; i < (int)sizeof(randomKey); i++) + { + randomKey[i] = random(0x01, 0xff); + } + + memset(base64RandomKey, 0x00, sizeof(base64RandomKey)); + base64_encode(randomKey, sizeof(randomKey), (unsigned char*)base64RandomKey, sizeof(base64RandomKey)); + + // start the connection upgrade sequence + sendHeader("Upgrade", "websocket"); + sendHeader("Connection", "Upgrade"); + sendHeader("Sec-WebSocket-Key", base64RandomKey); + sendHeader("Sec-WebSocket-Version", "13"); + endRequest(); + + status = responseStatusCode(); + + if (status > 0) + { + skipResponseHeaders(); + } + } + + iRxSize = 0; + + // status code of 101 means success + return (status == 101) ? 0 : status; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::begin(const String& aPath) +{ + return begin(aPath.c_str()); +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::beginMessage(int aType) +{ + if (iTxStarted) + { + // fail TX already started + return 1; + } + + iTxStarted = true; + iTxMessageType = (aType & 0xf); + iTxSize = 0; + + return 0; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::endMessage() +{ + if (!iTxStarted) + { + // fail TX not started + return 1; + } + + // send FIN + the message type (opcode) + WiFiHttpClient::write(0x80 | iTxMessageType); + + // the message is masked (0x80) + // send the length + if (iTxSize < 126) + { + WiFiHttpClient::write(0x80 | (uint8_t)iTxSize); + } + else if (iTxSize < 0xffff) + { + WiFiHttpClient::write(0x80 | 126); + WiFiHttpClient::write((iTxSize >> 8) & 0xff); + WiFiHttpClient::write((iTxSize >> 0) & 0xff); + } + else + { + WiFiHttpClient::write(0x80 | 127); + WiFiHttpClient::write((iTxSize >> 56) & 0xff); + WiFiHttpClient::write((iTxSize >> 48) & 0xff); + WiFiHttpClient::write((iTxSize >> 40) & 0xff); + WiFiHttpClient::write((iTxSize >> 32) & 0xff); + WiFiHttpClient::write((iTxSize >> 24) & 0xff); + WiFiHttpClient::write((iTxSize >> 16) & 0xff); + WiFiHttpClient::write((iTxSize >> 8) & 0xff); + WiFiHttpClient::write((iTxSize >> 0) & 0xff); + } + + uint8_t maskKey[4]; + + // create a random mask for the data and send + for (int i = 0; i < (int)sizeof(maskKey); i++) + { + maskKey[i] = random(0xff); + } + + WiFiHttpClient::write(maskKey, sizeof(maskKey)); + + // mask the data and send + for (int i = 0; i < (int)iTxSize; i++) + { + iTxBuffer[i] ^= maskKey[i % sizeof(maskKey)]; + } + + size_t txSize = iTxSize; + + iTxStarted = false; + iTxSize = 0; + + return (WiFiHttpClient::write(iTxBuffer, txSize) == txSize) ? 0 : 1; +} + +//////////////////////////////////////// + +size_t WiFiWebSocketClient::write(uint8_t aByte) +{ + return write(&aByte, sizeof(aByte)); +} + +//////////////////////////////////////// + +size_t WiFiWebSocketClient::write(const uint8_t *aBuffer, size_t aSize) +{ + if (iState < eReadingBody) + { + // have not upgraded the connection yet + return WiFiHttpClient::write(aBuffer, aSize); + } + + if (!iTxStarted) + { + // fail TX not started + return 0; + } + + // check if the write size, fits in the buffer + if ((iTxSize + aSize) > sizeof(iTxBuffer)) + { + aSize = sizeof(iTxSize) - iTxSize; + } + + // copy data into the buffer + memcpy(iTxBuffer + iTxSize, aBuffer, aSize); + + iTxSize += aSize; + + return aSize; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::parseMessage() +{ + flushRx(); + + // make sure 2 bytes (opcode + length) + // are available + if (WiFiHttpClient::available() < 2) + { + return 0; + } + + // read open code and length + uint8_t opcode = WiFiHttpClient::read(); + int length = WiFiHttpClient::read(); + + if ((opcode & 0x0f) == 0) + { + // continuation, use previous opcode and update flags + iRxOpCode |= opcode; + } + else + { + iRxOpCode = opcode; + } + + iRxMasked = (length & 0x80); + length &= 0x7f; + + // read the RX size + if (length < 126) + { + iRxSize = length; + } + else if (length == 126) + { + iRxSize = (WiFiHttpClient::read() << 8) | WiFiHttpClient::read(); + } + else + { + iRxSize = ((uint64_t)WiFiHttpClient::read() << 56) | + ((uint64_t)WiFiHttpClient::read() << 48) | + ((uint64_t)WiFiHttpClient::read() << 40) | + ((uint64_t)WiFiHttpClient::read() << 32) | + ((uint64_t)WiFiHttpClient::read() << 24) | + ((uint64_t)WiFiHttpClient::read() << 16) | + ((uint64_t)WiFiHttpClient::read() << 8) | + (uint64_t)WiFiHttpClient::read(); + } + + // read in the mask, if present + if (iRxMasked) + { + for (int i = 0; i < (int)sizeof(iRxMaskKey); i++) + { + iRxMaskKey[i] = WiFiHttpClient::read(); + } + } + + iRxMaskIndex = 0; + + if (TYPE_CONNECTION_CLOSE == messageType()) + { + flushRx(); + stop(); + iRxSize = 0; + } + else if (TYPE_PING == messageType()) + { + beginMessage(TYPE_PONG); + + while (available()) + { + write(read()); + } + + endMessage(); + + iRxSize = 0; + } + else if (TYPE_PONG == messageType()) + { + flushRx(); + iRxSize = 0; + } + + return iRxSize; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::messageType() +{ + return (iRxOpCode & 0x0f); +} + +//////////////////////////////////////// + +bool WiFiWebSocketClient::isFinal() +{ + return ((iRxOpCode & 0x80) != 0); +} + +//////////////////////////////////////// + +String WiFiWebSocketClient::readString() +{ + int avail = available(); + String s; + + if (avail > 0) + { + s.reserve(avail); + + for (int i = 0; i < avail; i++) + { + s += (char)read(); + } + } + + return s; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::ping() +{ + uint8_t pingData[16]; + + // create random data for the ping + for (int i = 0; i < (int)sizeof(pingData); i++) + { + pingData[i] = random(0xff); + } + + beginMessage(TYPE_PING); + write(pingData, sizeof(pingData)); + + return endMessage(); +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::available() +{ + if (iState < eReadingBody) + { + return WiFiHttpClient::available(); + } + + return iRxSize; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::read() +{ + byte b; + + if (read(&b, sizeof(b))) + { + return b; + } + + return -1; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::read(uint8_t *aBuffer, size_t aSize) +{ + int readCount = WiFiHttpClient::read(aBuffer, aSize); + + if (readCount > 0) + { + iRxSize -= readCount; + + // unmask the RX data if needed + if (iRxMasked) + { + for (int i = 0; i < (int)aSize; i++, iRxMaskIndex++) + { + aBuffer[i] ^= iRxMaskKey[iRxMaskIndex % sizeof(iRxMaskKey)]; + } + } + } + + return readCount; +} + +//////////////////////////////////////// + +int WiFiWebSocketClient::peek() +{ + int p = WiFiHttpClient::peek(); + + if (p != -1 && iRxMasked) + { + // unmask the RX data if needed + p = (uint8_t)p ^ iRxMaskKey[iRxMaskIndex % sizeof(iRxMaskKey)]; + } + + return p; +} + +//////////////////////////////////////// + +void WiFiWebSocketClient::flushRx() +{ + while (available()) + { + read(); + } +} + +//////////////////////////////////////// + diff --git a/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_WebSocketClient.h b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_WebSocketClient.h new file mode 100644 index 000000000..1dbaab7e7 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/WiFi_HTTPClient/WiFi_WebSocketClient.h @@ -0,0 +1,144 @@ +/**************************************************************************************************************************** + WiFi_WebSocketClient.h - Dead simple HTTP WebSockets Client. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +// (c) Copyright Arduino. 2016 +// Released under Apache License, version 2.0 + +#pragma once + +#ifndef WiFi_WebSocketClient_H +#define WiFi_WebSocketClient_H + +#include + +#include "utility/WiFiDebug.h" + +#include "WiFi_HTTPClient/WiFi_HttpClient.h" + +//////////////////////////////////////// + +static const int TYPE_CONTINUATION = 0x0; +static const int TYPE_TEXT = 0x1; +static const int TYPE_BINARY = 0x2; +static const int TYPE_CONNECTION_CLOSE = 0x8; +static const int TYPE_PING = 0x9; +static const int TYPE_PONG = 0xa; + +//////////////////////////////////////// + +class WiFiWebSocketClient : public WiFiHttpClient +{ + public: + WiFiWebSocketClient(Client& aClient, const char* aServerName, uint16_t aServerPort = WiFiHttpClient::kHttpPort); + WiFiWebSocketClient(Client& aClient, const String& aServerName, uint16_t aServerPort = WiFiHttpClient::kHttpPort); + WiFiWebSocketClient(Client& aClient, const IPAddress& aServerAddress, uint16_t aServerPort = WiFiHttpClient::kHttpPort); + + /** Start the Web Socket connection to the specified path + @param aURLPath Path to use in request (optional, "/" is used by default) + @return 0 if successful, else error + */ + int begin(const char* aPath = "/"); + int begin(const String& aPath); + + /** Begin to send a message of type (TYPE_TEXT or TYPE_BINARY) + Use the write or Stream API's to set message content, followed by endMessage + to complete the message. + @param aURLPath Path to use in request + @return 0 if successful, else error + */ + int beginMessage(int aType); + + /** Completes sending of a message started by beginMessage + @return 0 if successful, else error + */ + int endMessage(); + + /** Try to parse an incoming messages + @return 0 if no message available, else size of parsed message + */ + int parseMessage(); + + /** Returns type of current parsed message + @return type of current parsedMessage (TYPE_TEXT or TYPE_BINARY) + */ + int messageType(); + + /** Returns if the current message is the final chunk of a split + message + @return true for final message, false otherwise + */ + bool isFinal(); + + /** Read the current messages as a string + @return current message as a string + */ + String readString(); + + /** Send a ping + @return 0 if successful, else error + */ + int ping(); + + // Inherited from Print + virtual size_t write(uint8_t aByte); + virtual size_t write(const uint8_t *aBuffer, size_t aSize); + + // Inherited from Stream + virtual int available(); + /** Read the next byte from the server. + @return Byte read or -1 if there are no bytes available. + */ + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + + private: + void flushRx(); + + private: + bool iTxStarted; + uint8_t iTxMessageType; + uint8_t iTxBuffer[128]; + uint64_t iTxSize; + + uint8_t iRxOpCode; + uint64_t iRxSize; + bool iRxMasked; + int iRxMaskIndex; + uint8_t iRxMaskKey[4]; +}; + +#endif // WiFi_WebSocketClient_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/libb64/base64.cpp b/software/firmware/source/libraries/WiFiWebServer/src/libb64/base64.cpp new file mode 100644 index 000000000..febd2d35d --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/libb64/base64.cpp @@ -0,0 +1,87 @@ +/**************************************************************************************************************************** + base64.cpp - cpp source to a base64 encoding algorithm implementation + + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + *****************************************************************************************************************************/ + +#include "base64.h" + +/* Simple test program + #include + void main() + { + char* in = "amcewen"; + char out[22]; + + b64_encode(in, 15, out, 22); + out[21] = '\0'; + + printf(out); + } +*/ + +int base64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen) +{ + // Work out if we've got enough space to encode the input + // Every 6 bits of input becomes a byte of output + if (aOutputLen < (aInputLen * 8) / 6) + { + // FIXME Should we return an error here, or just the length + return (aInputLen * 8) / 6; + } + + // If we get here we've got enough space to do the encoding + + const char* b64_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + if (aInputLen == 3) + { + aOutput[0] = b64_dictionary[aInput[0] >> 2]; + aOutput[1] = b64_dictionary[(aInput[0] & 0x3) << 4 | (aInput[1] >> 4)]; + aOutput[2] = b64_dictionary[(aInput[1] & 0x0F) << 2 | (aInput[2] >> 6)]; + aOutput[3] = b64_dictionary[aInput[2] & 0x3F]; + } + else if (aInputLen == 2) + { + aOutput[0] = b64_dictionary[aInput[0] >> 2]; + aOutput[1] = b64_dictionary[(aInput[0] & 0x3) << 4 | (aInput[1] >> 4)]; + aOutput[2] = b64_dictionary[(aInput[1] & 0x0F) << 2]; + aOutput[3] = '='; + } + else if (aInputLen == 1) + { + aOutput[0] = b64_dictionary[aInput[0] >> 2]; + aOutput[1] = b64_dictionary[(aInput[0] & 0x3) << 4]; + aOutput[2] = '='; + aOutput[3] = '='; + } + else + { + // Break the input into 3-byte chunks and process each of them + int i; + + for (i = 0; i < aInputLen / 3; i++) + { + base64_encode(&aInput[i * 3], 3, &aOutput[i * 4], 4); + } + + if (aInputLen % 3 > 0) + { + // It doesn't fit neatly into a 3-byte chunk, so process what's left + base64_encode(&aInput[i * 3], aInputLen % 3, &aOutput[i * 4], aOutputLen - (i * 4)); + } + } + + return ((aInputLen + 2) / 3) * 4; +} + diff --git a/software/firmware/source/libraries/WiFiWebServer/src/libb64/base64.h b/software/firmware/source/libraries/WiFiWebServer/src/libb64/base64.h new file mode 100644 index 000000000..b0017f7a2 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/libb64/base64.h @@ -0,0 +1,28 @@ +/**************************************************************************************************************************** + base64.h - c source to a base64 encoding algorithm implementation + + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + *****************************************************************************************************************************/ + +#pragma once + +// Reintroduce to prevent duplication compile error if other lib/core already has LIB64 +// pragma once can't prevent that +#ifndef base64_h +#define base64_h + +int base64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen); + + +#endif // base64_h + diff --git a/software/firmware/source/libraries/WiFiWebServer/src/libb64/cdecode.c b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cdecode.c new file mode 100644 index 000000000..79fb395c1 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cdecode.c @@ -0,0 +1,147 @@ +/**************************************************************************************************************************** + cdecoder.c - c source to a base64 decoding algorithm implementation + + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + *****************************************************************************************************************************/ + +#if !(ESP32 || ESP8266) + +#include "cdecode.h" + +int base64_decode_value(int value_in) +{ + static const char 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 char 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; +} + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) +{ + const char* codechar = code_in; + char* plainchar = plaintext_out; + int 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 = base64_decode_value(*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 = base64_decode_value(*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 = base64_decode_value(*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 = base64_decode_value(*codechar++); + } while (fragment < 0); + + *plainchar++ |= (fragment & 0x03f); + + // fall through + } + } + + /* control should not reach here */ + return plainchar - plaintext_out; +} + +int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out) +{ + + base64_decodestate _state; + base64_init_decodestate(&_state); + int len = base64_decode_block(code_in, length_in, plaintext_out, &_state); + + if (len > 0) + plaintext_out[len] = 0; + + return len; +} + +#endif diff --git a/software/firmware/source/libraries/WiFiWebServer/src/libb64/cdecode.h b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cdecode.h new file mode 100644 index 000000000..e7fd954fe --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cdecode.h @@ -0,0 +1,54 @@ +/**************************************************************************************************************************** + cdecoder.h - c source to a base64 decoding algorithm implementation + + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + *****************************************************************************************************************************/ + +#pragma once + +// Reintroduce to prevent duplication compile error if other lib/core already has LIB64 +// pragma once can't prevent that +#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(int 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/software/firmware/source/libraries/WiFiWebServer/src/libb64/cencode.c b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cencode.c new file mode 100644 index 000000000..3365dcd24 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cencode.c @@ -0,0 +1,149 @@ +/**************************************************************************************************************************** + cencoder.c - c source to a base64 decoding algorithm implementation + + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + *****************************************************************************************************************************/ + +#if !(ESP32 || ESP8266) + +#include "cencode.h" + +const int CHARS_PER_LINE = 72; + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + if (value_in > 63) + return '='; + + return encoding[(unsigned 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); + + ++(state_in->stepcount); + + if (state_in->stepcount == CHARS_PER_LINE / 4) + { + *codechar++ = '\n'; + state_in->stepcount = 0; + } + + // fall through + } + } + + /* 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); +} + +#endif diff --git a/software/firmware/source/libraries/WiFiWebServer/src/libb64/cencode.h b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cencode.h new file mode 100644 index 000000000..ee76d0dd5 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/libb64/cencode.h @@ -0,0 +1,57 @@ +/**************************************************************************************************************************** + cencoder.h - c source to a base64 decoding algorithm implementation + + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + *****************************************************************************************************************************/ + +#pragma once + +// Reintroduce to prevent duplication compile error if other lib/core already has LIB64 +// pragma once can't prevent that +#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/software/firmware/source/libraries/WiFiWebServer/src/utility/ESP_RequestHandlersImpl.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/ESP_RequestHandlersImpl.h new file mode 100644 index 000000000..c854e0c0a --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/ESP_RequestHandlersImpl.h @@ -0,0 +1,338 @@ +/**************************************************************************************************************************** + ESP_RequestHandlersImpl.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef ESP_RequestHandlersImpl_H +#define ESP_RequestHandlersImpl_H + +#include "RequestHandler.h" +#include "utility/esp_detail/mimetable.h" +#include "FS.h" +#include "WString.h" +#include +#include + +#include "Uri.h" + +#include "utility/WiFiDebug.h" + +//////////////////////////////////////// +//////////////////////////////////////// + +class FunctionRequestHandler : public RequestHandler +{ + public: + + FunctionRequestHandler(WiFiWebServer::THandlerFunction fn, WiFiWebServer::THandlerFunction ufn, const Uri &uri, + const HTTPMethod& method) + : _fn(fn) + , _ufn(ufn) + , _uri(uri.clone()) + , _method(method) + { + _uri->initPathArgs(pathArgs); + } + + ~FunctionRequestHandler() + { + delete _uri; + } + + //////////////////////////////////////// + + bool canHandle(const HTTPMethod& requestMethod, const String& requestUri) override + { + if (_method != HTTP_ANY && _method != requestMethod) + return false; + + return _uri->canHandle(requestUri, pathArgs); + } + + //////////////////////////////////////// + + bool canUpload(const String& requestUri) override + { + if (!_ufn || !canHandle(HTTP_POST, requestUri)) + return false; + + return true; + } + + //////////////////////////////////////// + + bool handle(WiFiWebServer& server, const HTTPMethod& requestMethod, /*const*/ String& requestUri) override + { + WFW_UNUSED(server); + + if (!canHandle(requestMethod, requestUri)) + return false; + + _fn(); + + return true; + } + + //////////////////////////////////////// + + void upload(WiFiWebServer& server, const String& requestUri, const HTTPUpload& upload) override + { + WFW_UNUSED(server); + WFW_UNUSED(upload); + + if (canUpload(requestUri)) + _ufn(); + } + + //////////////////////////////////////// + + protected: + + WiFiWebServer::THandlerFunction _fn; + WiFiWebServer::THandlerFunction _ufn; + + Uri *_uri; + + HTTPMethod _method; +}; + +//////////////////////////////////////// +//////////////////////////////////////// + +class StaticRequestHandler : public RequestHandler +{ + using WebServerType = WiFiWebServer; + + public: + + StaticRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : _fs(fs) + , _uri(uri) + , _path(path) + , _cache_header(cache_header) + { + _isFile = fs.exists(path); + _baseUriLength = _uri.length(); + } + + //////////////////////////////////////// + + bool canHandle(const HTTPMethod& requestMethod, const String& requestUri) override + { + if (requestMethod != HTTP_GET) + return false; + + if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri)) + return false; + + return true; + } + + //////////////////////////////////////// + + bool handle(WiFiWebServer& server, const HTTPMethod& requestMethod, /*const*/ String& requestUri) override + { + if (!canHandle(requestMethod, requestUri)) + return false; + + WS_LOGDEBUG3(F("StaticRequestHandler::handle: request ="), requestUri, F(", _uri ="), _uri); + + String path(_path); + + if (!_isFile) + { + // Base URI doesn't point to a file. + // If a directory is requested, look for index file. + if (requestUri.endsWith("/")) + requestUri += "index.htm"; + + // Append whatever follows this URI in request to get the file path. + path += requestUri.substring(_baseUriLength); + } + + WS_LOGDEBUG3(F("StaticRequestHandler::handle: path ="), path, F(", _isFile ="), _isFile); + + String contentType = getContentType(path); + + using namespace mime_esp; + + // look for gz file, only if the original specified path is not a gz. + // So part only works to send gzip via content encoding when a non compressed is asked for + // if you point the the path to gzip you will serve the gzip as content type "application/x-gzip" + // not text or javascript etc... + if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) + { + String pathWithGz = path + FPSTR(mimeTable[gz].endsWith); + + if (_fs.exists(pathWithGz)) + path += FPSTR(mimeTable[gz].endsWith); + } + + File f = _fs.open(path, "r"); + + if (!f || !f.available()) + return false; + + if (_cache_header.length() != 0) + server.sendHeader("Cache-Control", _cache_header); + + server.streamFile(f, contentType); + + return true; + } + + //////////////////////////////////////// + + static String getContentType(const String& path) + { + using namespace mime_esp; + + char buff[sizeof(mimeTable[0].mimeType)]; + + // Check all entries but last one for match, return if found + for (size_t i = 0; i < sizeof(mimeTable) / sizeof(mimeTable[0]) - 1; i++) + { + strcpy_P(buff, mimeTable[i].endsWith); + + if (path.endsWith(buff)) + { + strcpy_P(buff, mimeTable[i].mimeType); + + return String(buff); + } + } + + // Fall-through and just return default type + strcpy_P(buff, mimeTable[sizeof(mimeTable) / sizeof(mimeTable[0]) - 1].mimeType); + + return String(buff); + } + + //////////////////////////////////////// + + bool validMethod(HTTPMethod requestMethod) + { + return (requestMethod == HTTP_GET) || (requestMethod == HTTP_HEAD); + } + + //////////////////////////////////////// + + protected: + FS _fs; + String _uri; + String _path; + String _cache_header; + bool _isFile; + size_t _baseUriLength; +}; + +//////////////////////////////////////// +//////////////////////////////////////// + + +class StaticFileRequestHandler : public StaticRequestHandler +{ + using SRH = StaticRequestHandler; + using WebServerType = WiFiWebServer; + + public: + + //////////////////////////////////////// + + StaticFileRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header) + : + StaticRequestHandler{fs, path, uri, cache_header} + { + File f = SRH::_fs.open(path, "r"); + MD5Builder calcMD5; + calcMD5.begin(); + calcMD5.addStream(f, f.size()); + calcMD5.calculate(); + calcMD5.getBytes(_ETag_md5); + f.close(); + } + + //////////////////////////////////////// + + bool canHandle(const HTTPMethod& requestMethod, const String& requestUri) override + { + return SRH::validMethod(requestMethod) && requestUri == SRH::_uri; + } + + //////////////////////////////////////// + + bool handle(WiFiWebServer& server, const HTTPMethod& requestMethod, const String& requestUri) + { + if (!canHandle(requestMethod, requestUri)) + return false; + + + const String etag = "\"" + base64::encode(_ETag_md5, 16) + "\""; + + if (server.header("If-None-Match") == etag) + { + server.send(304); + return true; + } + + File f = SRH::_fs.open(SRH::_path, "r"); + + if (!f) + return false; + + if (!_isFile) + { + f.close(); + return false; + } + + if (SRH::_cache_header.length() != 0) + server.sendHeader("Cache-Control", SRH::_cache_header); + + server.sendHeader("ETag", etag); + + server.streamFile(f, mime_esp::getContentType(SRH::_path), requestMethod); + return true; + } + + //////////////////////////////////////// + + protected: + uint8_t _ETag_md5[16]; +}; + + +#endif // ESP_RequestHandlersImpl_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/RequestHandler.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/RequestHandler.h new file mode 100644 index 000000000..5e9e2ce7c --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/RequestHandler.h @@ -0,0 +1,143 @@ +/**************************************************************************************************************************** + RequestHandler.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef RequestHandler_H +#define RequestHandler_H + +#ifndef WFW_UNUSED + #define WFW_UNUSED(x) (void)(x) +#endif + +#include "utility/WiFiDebug.h" + +#include + +//////////////////////////////////////// + +class RequestHandler +{ + public: + + virtual ~RequestHandler() { } + + //////////////////////////////////////// + + virtual bool canHandle(const HTTPMethod& method, const String& uri) + { + WFW_UNUSED(method); + WFW_UNUSED(uri); + + return false; + } + + //////////////////////////////////////// + + virtual bool canUpload(const String& uri) + { + WFW_UNUSED(uri); + + return false; + } + + //////////////////////////////////////// + + virtual bool handle(WiFiWebServer& server, const HTTPMethod& requestMethod, /*const*/ String& requestUri) + { + WFW_UNUSED(server); + WFW_UNUSED(requestMethod); + WFW_UNUSED(requestUri); + + return false; + } + + //////////////////////////////////////// + + virtual void upload(WiFiWebServer& server, const String& requestUri, const HTTPUpload& upload) + { + WFW_UNUSED(server); + WFW_UNUSED(requestUri); + WFW_UNUSED(upload); + } + + //////////////////////////////////////// + + RequestHandler* next() + { + return _next; + } + + //////////////////////////////////////// + + void next(RequestHandler* r) + { + _next = r; + } + + //////////////////////////////////////// + + private: + + RequestHandler* _next = nullptr; + + //////////////////////////////////////// + + protected: + std::vector pathArgs; + + //////////////////////////////////////// + + public: + + //////////////////////////////////////// + + const String& pathArg(unsigned int i) + { + if (i < pathArgs.size()) + { + return pathArgs[i]; + } + else + { + WS_LOGERROR3(F("RequestHandler::pathArg: error i ="), i, F(" > pathArgs.size() ="), pathArgs.size()); + + return pathArgs[0]; + } + } +}; + +#endif // RequestHandler_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/RequestHandlersImpl.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/RequestHandlersImpl.h new file mode 100644 index 000000000..24ffe54bf --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/RequestHandlersImpl.h @@ -0,0 +1,249 @@ +/**************************************************************************************************************************** + RequestHandlersImpl.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef RequestHandlersImpl_H +#define RequestHandlersImpl_H + +#if !(ESP32 || ESP8266) +#include "RequestHandler.h" +#include "mimetable.h" + +//////////////////////////////////////// +//////////////////////////////////////// + +class FunctionRequestHandler : public RequestHandler +{ + public: + + //////////////////////////////////////// + + FunctionRequestHandler(WiFiWebServer::THandlerFunction fn, WiFiWebServer::THandlerFunction ufn, const String &uri, + const HTTPMethod& method) + : _fn(fn) + , _ufn(ufn) + , _uri(uri) + , _method(method) + { + } + + //////////////////////////////////////// + + bool canHandle(const HTTPMethod& requestMethod, const String& requestUri) override + { + if (_method != HTTP_ANY && _method != requestMethod) + return false; + + if (requestUri == _uri) + return true; + + if (_uri.endsWith("/*")) + { + String _uristart = _uri; + _uristart.replace("/*", ""); + + if (requestUri.startsWith(_uristart)) + return true; + } + + return false; + } + + //////////////////////////////////////// + + bool canUpload(const String& requestUri) override + { + if (!_ufn || !canHandle(HTTP_POST, requestUri)) + return false; + + return true; + } + + //////////////////////////////////////// + + bool handle(WiFiWebServer& server, const HTTPMethod& requestMethod, /*const*/ String& requestUri) override + { + WFW_UNUSED(server); + + if (!canHandle(requestMethod, requestUri)) + return false; + + _fn(); + return true; + } + + //////////////////////////////////////// + + void upload(WiFiWebServer& server, const String& requestUri, const HTTPUpload& upload) override + { + WFW_UNUSED(server); + WFW_UNUSED(upload); + + if (canUpload(requestUri)) + _ufn(); + } + + //////////////////////////////////////// + + protected: + WiFiWebServer::THandlerFunction _fn; + WiFiWebServer::THandlerFunction _ufn; + String _uri; + HTTPMethod _method; +}; + +//////////////////////////////////////// +//////////////////////////////////////// + +class StaticRequestHandler : public RequestHandler +{ + public: + + //////////////////////////////////////// + + bool canHandle(const HTTPMethod& requestMethod, const String& requestUri) override + { + if (requestMethod != HTTP_GET) + return false; + + if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri)) + return false; + + return true; + } + + //////////////////////////////////////// + +#if USE_NEW_WEBSERVER_VERSION + + //////////////////////////////////////// + + static String getContentType(const String& path) + { + using namespace mime; + char buff[sizeof(mimeTable[0].mimeType)]; + + // Check all entries but last one for match, return if found + for (size_t i = 0; i < sizeof(mimeTable) / sizeof(mimeTable[0]) - 1; i++) + { + strcpy(buff, mimeTable[i].endsWith); + + if (path.endsWith(buff)) + { + strcpy(buff, mimeTable[i].mimeType); + return String(buff); + } + } + + // Fall-through and just return default type + strcpy(buff, mimeTable[sizeof(mimeTable) / sizeof(mimeTable[0]) - 1].mimeType); + return String(buff); + } + + //////////////////////////////////////// + +#else // #if USE_NEW_WEBSERVER_VERSION + + //////////////////////////////////////// + + static String getContentType(const String& path) + { + if (path.endsWith(".html")) + return "text/html"; + else if (path.endsWith(".htm")) + return "text/html"; + else if (path.endsWith(".css")) + return "text/css"; + else if (path.endsWith(".txt")) + return "text/plain"; + else if (path.endsWith(".js")) + return "application/javascript"; + else if (path.endsWith(".png")) + return "image/png"; + else if (path.endsWith(".gif")) + return "image/gif"; + else if (path.endsWith(".jpg")) + return "image/jpeg"; + else if (path.endsWith(".ico")) + return "image/x-icon"; + else if (path.endsWith(".svg")) + return "image/svg+xml"; + else if (path.endsWith(".ttf")) + return "application/x-font-ttf"; + else if (path.endsWith(".otf")) + return "application/x-font-opentype"; + else if (path.endsWith(".woff")) + return "application/font-woff"; + else if (path.endsWith(".woff2")) + return "application/font-woff2"; + else if (path.endsWith(".eot")) + return "application/vnd.ms-fontobject"; + else if (path.endsWith(".sfnt")) + return "application/font-sfnt"; + else if (path.endsWith(".xml")) + return "text/xml"; + else if (path.endsWith(".pdf")) + return "application/pdf"; + else if (path.endsWith(".zip")) + return "application/zip"; + else if (path.endsWith(".gz")) + return "application/x-gzip"; + else if (path.endsWith(".appcache")) + return "text/cache-manifest"; + + return "application/octet-stream"; + } + + //////////////////////////////////////// + +#endif // #if USE_NEW_WEBSERVER_VERSION + + protected: + + String _uri; + String _path; + String _cache_header; + bool _isFile; + size_t _baseUriLength; +}; + +#else // #if !(ESP32 || ESP8266) +#include "ESP_RequestHandlersImpl.h" +#endif + + +#endif // RequestHandlersImpl_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/RingBuffer.cpp b/software/firmware/source/libraries/WiFiWebServer/src/utility/RingBuffer.cpp new file mode 100644 index 000000000..d8af5797c --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/RingBuffer.cpp @@ -0,0 +1,138 @@ +/**************************************************************************************************************************** + RingBuffer.cpp - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#include "RingBuffer.h" + +#include + +//////////////////////////////////////// + +WiFi_RingBuffer::WiFi_RingBuffer(unsigned int size) +{ + _size = size; + // add one char to terminate the string + ringBuf = new char[size + 1]; + ringBufEnd = &ringBuf[size]; + init(); +} + +//////////////////////////////////////// + +WiFi_RingBuffer::~WiFi_RingBuffer() {} + +//////////////////////////////////////// + +void WiFi_RingBuffer::reset() +{ + ringBufP = ringBuf; +} + +//////////////////////////////////////// + +void WiFi_RingBuffer::init() +{ + ringBufP = ringBuf; + memset(ringBuf, 0, _size + 1); +} + +//////////////////////////////////////// + +void WiFi_RingBuffer::push(char c) +{ + *ringBufP = c; + ringBufP++; + + if (ringBufP >= ringBufEnd) + ringBufP = ringBuf; +} + +//////////////////////////////////////// + +bool WiFi_RingBuffer::endsWith(const char* str) +{ + int findStrLen = strlen(str); + + // b is the start position into the ring buffer + char* b = ringBufP - findStrLen; + + if (b < ringBuf) + b = b + _size; + + char *p1 = (char*)&str[0]; + char *p2 = p1 + findStrLen; + + for (char *p = p1; p < p2; p++) + { + if (*p != *b) + return false; + + b++; + + if (b == ringBufEnd) + b = ringBuf; + } + + return true; +} + +//////////////////////////////////////// + +void WiFi_RingBuffer::getStr(char * destination, unsigned int skipChars) +{ + unsigned int len = ringBufP - ringBuf - skipChars; + + // copy buffer to destination string + strncpy(destination, ringBuf, len); + + // terminate output string + //destination[len]=0; +} + +//////////////////////////////////////// + +void WiFi_RingBuffer::getStrN(char * destination, unsigned int skipChars, unsigned int num) +{ + unsigned int len = ringBufP - ringBuf - skipChars; + + if (len > num) + len = num; + + // copy buffer to destination string + strncpy(destination, ringBuf, len); + + // terminate output string + //destination[len]=0; +} diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/RingBuffer.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/RingBuffer.h new file mode 100644 index 000000000..819e77039 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/RingBuffer.h @@ -0,0 +1,68 @@ +/**************************************************************************************************************************** + RingBuffer.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef RingBuffer_H +#define RingBuffer_H + +//////////////////////////////////////// + +class WiFi_RingBuffer +{ + public: + WiFi_RingBuffer(unsigned int size); + ~WiFi_RingBuffer(); + + void reset(); + void init(); + void push(char c); + int getPos(); + bool endsWith(const char* str); + void getStr(char * destination, unsigned int skipChars); + void getStrN(char * destination, unsigned int skipChars, unsigned int num); + + private: + + unsigned int _size; + char* ringBuf; + char* ringBufEnd; + char* ringBufP; +}; + +//////////////////////////////////////// + +#endif // RingBuffer_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/WiFiDebug.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/WiFiDebug.h new file mode 100644 index 000000000..2c07e5a0b --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/WiFiDebug.h @@ -0,0 +1,116 @@ +/**************************************************************************************************************************** + WiFiDebug.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef WiFiDebug_H +#define WiFiDebug_H + +#if defined(ARDUINO) + #if ARDUINO >= 100 + #include + #else + #include + #endif +#endif + +#include + +#ifdef DEBUG_WIFI_WEBSERVER_PORT + #define WS_DEBUG_OUTPUT DEBUG_WIFI_WEBSERVER_PORT +#else + #define WS_DEBUG_OUTPUT Serial +#endif + +// Change _WIFI_LOGLEVEL_ to set tracing and logging verbosity +// 0: DISABLED: no logging +// 1: ERROR: errors +// 2: WARN: errors and warnings +// 3: INFO: errors, warnings and informational (default) +// 4: DEBUG: errors, warnings, informational and debug + +#ifndef _WIFI_LOGLEVEL_ + #define _WIFI_LOGLEVEL_ 0 +#endif + +const char WWS_MARK[] = "[WIFI] "; +const char WWS_SPACE[] = " "; +const char WWS_LINE[] = "========================================\n"; + +#define WWS_PRINT_MARK WWS_PRINT(WWS_MARK) +#define WWS_PRINT_SP WWS_PRINT(WWS_SPACE) +#define WWS_PRINT_LINE WWS_PRINT(WWS_LINE) + +#define WWS_PRINT WS_DEBUG_OUTPUT.print +#define WWS_PRINTLN WS_DEBUG_OUTPUT.println + +/////////////////////////////////////// + +#define WS_LOGERROR(x) if(_WIFI_LOGLEVEL_>0) { WWS_PRINT_MARK; WWS_PRINTLN(x); } +#define WS_LOGERROR0(x) if(_WIFI_LOGLEVEL_>0) { WWS_PRINT(x); } +#define WS_LOGERROR1(x,y) if(_WIFI_LOGLEVEL_>0) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINTLN(y); } +#define WS_LOGERROR2(x,y,z) if(_WIFI_LOGLEVEL_>0) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINTLN(z); } +#define WS_LOGERROR3(x,y,z,w) if(_WIFI_LOGLEVEL_>0) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINTLN(w); } +#define WS_LOGERROR5(x,y,z,w, xx, yy) if(_WIFI_LOGLEVEL_>0) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINT(w); WWS_PRINT_SP; WWS_PRINT(xx); WWS_PRINT_SP; WWS_PRINTLN(yy);} + +/////////////////////////////////////// + +#define WS_LOGWARN(x) if(_WIFI_LOGLEVEL_>1) { WWS_PRINT_MARK; WWS_PRINTLN(x); } +#define WS_LOGWARN0(x) if(_WIFI_LOGLEVEL_>1) { WWS_PRINT(x); } +#define WS_LOGWARN1(x,y) if(_WIFI_LOGLEVEL_>1) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINTLN(y); } +#define WS_LOGWARN2(x,y,z) if(_WIFI_LOGLEVEL_>1) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINTLN(z); } +#define WS_LOGWARN3(x,y,z,w) if(_WIFI_LOGLEVEL_>1) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINTLN(w); } +#define WS_LOGWARN5(x,y,z,w, xx, yy) if(_WIFI_LOGLEVEL_>1) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINT(w); WWS_PRINT_SP; WWS_PRINT(xx); WWS_PRINT_SP; WWS_PRINTLN(yy);} + +/////////////////////////////////////// + +#define WS_LOGINFO(x) if(_WIFI_LOGLEVEL_>2) { WWS_PRINT_MARK; WWS_PRINTLN(x); } +#define WS_LOGINFO0(x) if(_WIFI_LOGLEVEL_>2) { WWS_PRINT(x); } +#define WS_LOGINFO1(x,y) if(_WIFI_LOGLEVEL_>2) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINTLN(y); } +#define WS_LOGINFO2(x,y,z) if(_WIFI_LOGLEVEL_>2) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINTLN(z); } +#define WS_LOGINFO3(x,y,z,w) if(_WIFI_LOGLEVEL_>2) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINTLN(w); } +#define WS_LOGINFO5(x,y,z,w, xx, yy) if(_WIFI_LOGLEVEL_>2) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINT(w); WWS_PRINT_SP; WWS_PRINT(xx); WWS_PRINT_SP; WWS_PRINTLN(yy);} + +/////////////////////////////////////// + +#define WS_LOGDEBUG(x) if(_WIFI_LOGLEVEL_>3) { WWS_PRINT_MARK; WWS_PRINTLN(x); } +#define WS_LOGDEBUG0(x) if(_WIFI_LOGLEVEL_>3) { WWS_PRINT(x); } +#define WS_LOGDEBUG1(x,y) if(_WIFI_LOGLEVEL_>3) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINTLN(y); } +#define WS_LOGDEBUG2(x,y,z) if(_WIFI_LOGLEVEL_>3) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINTLN(z); } +#define WS_LOGDEBUG3(x,y,z,w) if(_WIFI_LOGLEVEL_>3) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINTLN(w); } +#define WS_LOGDEBUG5(x,y,z,w, xx, yy) if(_WIFI_LOGLEVEL_>3) { WWS_PRINT_MARK; WWS_PRINT(x); WWS_PRINT_SP; WWS_PRINT(y); WWS_PRINT_SP; WWS_PRINT(z); WWS_PRINT_SP; WWS_PRINT(w); WWS_PRINT_SP; WWS_PRINT(xx); WWS_PRINT_SP; WWS_PRINTLN(yy);} + +#endif // WiFiDebug_H diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/esp_detail/mimetable.cpp b/software/firmware/source/libraries/WiFiWebServer/src/utility/esp_detail/mimetable.cpp new file mode 100644 index 000000000..070f3fb25 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/esp_detail/mimetable.cpp @@ -0,0 +1,151 @@ +/**************************************************************************************************************************** + mimetable.cpp - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#if (ESP32 || ESP8266) + +#include "mimetable.h" +#include "pgmspace.h" +#include "WString.h" + +//////////////////////////////////////// + +namespace mime_esp +{ +static const char kHtmlSuffix[] PROGMEM = ".html"; +static const char kHtmSuffix[] PROGMEM = ".htm"; +static const char kTxtSuffix[] PROGMEM = ".txt"; + +static const char kCssSuffix[] PROGMEM = ".css"; +static const char kJsSuffix[] PROGMEM = ".js"; +static const char kJsonSuffix[] PROGMEM = ".json"; +static const char kPngSuffix[] PROGMEM = ".png"; +static const char kGifSuffix[] PROGMEM = ".gif"; +static const char kJpgSuffix[] PROGMEM = ".jpg"; +static const char kJpegSuffix[] PROGMEM = ".jpeg"; +static const char kIcoSuffix[] PROGMEM = ".ico"; +static const char kSvgSuffix[] PROGMEM = ".svg"; +static const char kTtfSuffix[] PROGMEM = ".ttf"; +static const char kOtfSuffix[] PROGMEM = ".otf"; +static const char kWoffSuffix[] PROGMEM = ".woff"; +static const char kWoff2Suffix[] PROGMEM = ".woff2"; +static const char kEotSuffix[] PROGMEM = ".eot"; +static const char kSfntSuffix[] PROGMEM = ".sfnt"; +static const char kXmlSuffix[] PROGMEM = ".xml"; +static const char kPdfSuffix[] PROGMEM = ".pdf"; +static const char kZipSuffix[] PROGMEM = ".zip"; +static const char kAppcacheSuffix[] PROGMEM = ".appcache"; + +static const char kGzSuffix[] PROGMEM = ".gz"; +static const char kDefaultSuffix[] PROGMEM = ""; + +//////////////////////////////////////// + +static const char kHtml[] PROGMEM = "text/html"; +static const char kTxt[] PROGMEM = "text/plain"; + +static const char kCss[] PROGMEM = "text/css"; +static const char kJs[] PROGMEM = "application/javascript"; +static const char kJson[] PROGMEM = "application/json"; +static const char kPng[] PROGMEM = "image/png"; +static const char kGif[] PROGMEM = "image/gif"; +static const char kJpg[] PROGMEM = "image/jpeg"; +static const char kJpeg[] PROGMEM = "image/jpeg"; +static const char kIco[] PROGMEM = "image/x-icon"; +static const char kSvg[] PROGMEM = "image/svg+xml"; +static const char kTtf[] PROGMEM = "application/x-font-ttf"; +static const char kOtf[] PROGMEM = "application/x-font-opentype"; +static const char kWoff[] PROGMEM = "application/font-woff"; +static const char kWoff2[] PROGMEM = "application/font-woff2"; +static const char kEot[] PROGMEM = "application/vnd.ms-fontobject"; +static const char kSfnt[] PROGMEM = "application/font-sfnt"; +static const char kXml[] PROGMEM = "text/xml"; +static const char kPdf[] PROGMEM = "application/pdf"; +static const char kZip[] PROGMEM = "application/zip"; +static const char kAppcache[] PROGMEM = "text/cache-manifest"; + +static const char kGz[] PROGMEM = "application/x-gzip"; +static const char kDefault[] PROGMEM = "application/octet-stream"; + +//////////////////////////////////////// + +const Entry mimeTable[maxType] PROGMEM = +{ + { kHtmlSuffix, kHtml }, + { kHtmSuffix, kHtml }, + { kCssSuffix, kCss }, + { kTxtSuffix, kTxt }, + { kJsSuffix, kJs }, + { kJsonSuffix, kJson }, + { kPngSuffix, kPng }, + { kGifSuffix, kGif }, + { kJpgSuffix, kJpg }, + { kIcoSuffix, kIco }, + { kSvgSuffix, kSvg }, + { kTtfSuffix, kTtf }, + { kOtfSuffix, kOtf }, + { kWoffSuffix, kWoff }, + { kWoff2Suffix, kWoff2 }, + { kEotSuffix, kEot }, + { kSfntSuffix, kSfnt }, + { kXmlSuffix, kXml }, + { kPdfSuffix, kPdf }, + { kZipSuffix, kZip }, + { kGzSuffix, kGz }, + { kAppcacheSuffix, kAppcache }, + { kDefaultSuffix, kDefault } +}; + +//////////////////////////////////////// + +String getContentType(const String& path) +{ + for (size_t i = 0; i < maxType; i++) + { + if (path.endsWith(FPSTR(mimeTable[i].endsWith))) + { + return String(FPSTR(mimeTable[i].mimeType)); + } + } + + // Fall-through and just return default type + return String(FPSTR(kDefault)); +} + +//////////////////////////////////////// + +} // namespace mime_esp + +#endif diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/esp_detail/mimetable.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/esp_detail/mimetable.h new file mode 100644 index 000000000..15210d4f6 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/esp_detail/mimetable.h @@ -0,0 +1,95 @@ +/**************************************************************************************************************************** + mimetable.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef __ESP_MIMETABLE_H__ +#define __ESP_MIMETABLE_H__ + +#if (ESP32 || ESP8266) + +#include "WString.h" + +//////////////////////////////////////// + +namespace mime_esp +{ + +enum type +{ + html, + htm, + css, + txt, + js, + json, + png, + gif, + jpg, + ico, + svg, + ttf, + otf, + woff, + woff2, + eot, + sfnt, + xml, + pdf, + zip, + gz, + appcache, + none, + maxType +}; + +//////////////////////////////////////// + +struct Entry +{ + const char * endsWith; + const char * mimeType; +}; + +//////////////////////////////////////// + +extern const Entry mimeTable[maxType]; + +String getContentType(const String& path); +} + +#endif // #if (ESP32 || ESP8266) +#endif // #ifndef __ESP_MIMETABLE_H__ diff --git a/software/firmware/source/libraries/WiFiWebServer/src/utility/mimetable.h b/software/firmware/source/libraries/WiFiWebServer/src/utility/mimetable.h new file mode 100644 index 000000000..f3bbf0c80 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/src/utility/mimetable.h @@ -0,0 +1,110 @@ +/**************************************************************************************************************************** + mimetable.h - Dead simple web-server. + For any WiFi shields, such as WiFiNINA W101, W102, W13x, or custom, such as ESP8266/ESP32-AT, Ethernet, etc + + WiFiWebServer is a library for the ESP32-based WiFi shields to run WebServer + Forked and modified from ESP8266 https://github.com/esp8266/Arduino/releases + Forked and modified from Arduino WiFiNINA library https://www.arduino.cc/en/Reference/WiFiNINA + Built by Khoi Hoang https://github.com/khoih-prog/WiFiWebServer + Licensed under MIT license + + Original author: + @file Esp8266WebServer.h + @author Ivan Grokhotkov + + Version: 1.10.1 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 12/02/2020 Initial coding for SAMD21, Nano 33 IoT, etc running WiFiNINA + ... + 1.6.0 K Hoang 13/02/2022 Add support to new ESP32-S3 and ESP32_C3 + 1.6.1 K Hoang 13/02/2022 Fix v1.6.0 issue + 1.6.2 K Hoang 22/02/2022 Add support to megaAVR using Arduino megaAVR core + 1.6.3 K Hoang 02/03/2022 Fix decoding error bug + 1.7.0 K Hoang 05/04/2022 Fix issue with Portenta_H7 core v2.7.2+ + 1.8.0 K Hoang 26/04/2022 Add WiFiMulti library support and examples + 1.9.0 K Hoang 12/08/2022 Add support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.1 K Hoang 13/08/2022 Add WiFiMulti support to RASPBERRY_PI_PICO_W using CYW4343 WiFi + 1.9.2 K Hoang 16/08/2022 Workaround for RP2040W WiFi.status() bug + 1.9.3 K Hoang 16/08/2022 Better workaround for RP2040W WiFi.status() bug using ping() to local gateway + 1.9.4 K Hoang 06/09/2022 Restore support to ESP32 and ESP8266 + 1.9.5 K Hoang 10/09/2022 Restore support to Teensy, etc. Fix bug in examples + 1.10.0 K Hoang 13/11/2022 Add new features, such as CORS. Update code and examples + 1.10.1 K Hoang 24/11/2022 Using new WiFi101_Generic library to send larger data + *****************************************************************************************************************************/ + +#pragma once + +#ifndef __MIMETABLE_H__ +#define __MIMETABLE_H__ + +namespace mime +{ + +enum type +{ + html, + htm, + css, + txt, + js, + json, + png, + gif, + jpg, + ico, + svg, + ttf, + otf, + woff, + woff2, + eot, + sfnt, + xml, + pdf, + zip, + gz, + appcache, + none, + maxType +}; + +struct Entry +{ + const char endsWith[16]; + const char mimeType[32]; +}; + +// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules +const Entry mimeTable[maxType] = +{ + { ".html", "text/html" }, + { ".htm", "text/html" }, + { ".css", "text/css" }, + { ".txt", "text/plain" }, + { ".js", "application/javascript" }, + { ".json", "application/json" }, + { ".png", "image/png" }, + { ".gif", "image/gif" }, + { ".jpg", "image/jpeg" }, + { ".ico", "image/x-icon" }, + { ".svg", "image/svg+xml" }, + { ".ttf", "application/x-font-ttf" }, + { ".otf", "application/x-font-opentype" }, + { ".woff", "application/font-woff" }, + { ".woff2", "application/font-woff2" }, + { ".eot", "application/vnd.ms-fontobject" }, + { ".sfnt", "application/font-sfnt" }, + { ".xml", "text/xml" }, + { ".pdf", "application/pdf" }, + { ".zip", "application/zip" }, + { ".gz", "application/x-gzip" }, + { ".appcache", "text/cache-manifest" }, + { "", "application/octet-stream" } +}; +//extern const Entry mimeTable[maxType]; +} + + +#endif // __MIMETABLE_H__ diff --git a/software/firmware/source/libraries/WiFiWebServer/utils/astyle_library.conf b/software/firmware/source/libraries/WiFiWebServer/utils/astyle_library.conf new file mode 100644 index 000000000..8a73bc276 --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/utils/astyle_library.conf @@ -0,0 +1,70 @@ +# Code formatting rules for Arduino libraries, modified from for KH libraries: +# +# https://github.com/arduino/Arduino/blob/master/build/shared/examples_formatter.conf +# + +# astyle --style=allman -s2 -t2 -C -S -xW -Y -M120 -f -p -xg -H -xb -c --xC120 -xL *.h *.cpp *.ino + +--mode=c +--lineend=linux +--style=allman + +# -r or -R +#--recursive + +# -c => Converts tabs into spaces +convert-tabs + +# -s2 => 2 spaces indentation +--indent=spaces=2 + +# -t2 => tab =2 spaces +#--indent=tab=2 + +# -C +--indent-classes + +# -S +--indent-switches + +# -xW +--indent-preproc-block + +# -Y => indent classes, switches (and cases), comments starting at column 1 +--indent-col1-comments + +# -M120 => maximum of 120 spaces to indent a continuation line +--max-continuation-indent=120 + +# -xC120 => max‑code‑length will break a line if the code exceeds # characters +--max-code-length=120 + +# -f => +--break-blocks + +# -p => put a space around operators +--pad-oper + +# -xg => Insert space padding after commas +--pad-comma + +# -H => put a space after if/for/while +pad-header + +# -xb => Break one line headers (e.g. if/for/while) +--break-one-line-headers + +# -c => Converts tabs into spaces +#--convert-tabs + +# if you like one-liners, keep them +#keep-one-line-statements + +# -xV +--attach-closing-while + +#unpad-paren + +# -xp +remove-comment-prefix + diff --git a/software/firmware/source/libraries/WiFiWebServer/utils/restyle.sh b/software/firmware/source/libraries/WiFiWebServer/utils/restyle.sh new file mode 100644 index 000000000..bcd846f7a --- /dev/null +++ b/software/firmware/source/libraries/WiFiWebServer/utils/restyle.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +for dir in . ; do + find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.ino" \) -exec astyle --suffix=none --options=./utils/astyle_library.conf \{\} \; +done + diff --git a/software/firmware/source/libraries/functional-vlpp/.gitignore b/software/firmware/source/libraries/functional-vlpp/.gitignore new file mode 100644 index 000000000..259148fa1 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/software/firmware/source/libraries/functional-vlpp/CONTRIBUTING.md b/software/firmware/source/libraries/functional-vlpp/CONTRIBUTING.md new file mode 100644 index 000000000..65a021b15 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/CONTRIBUTING.md @@ -0,0 +1,52 @@ +## Contributing to functional-vlpp + +### Reporting Bugs + +Please report bugs in Functional-Vlpp if you find them. + +However, before reporting a bug please check through the following: + +* [Existing Open Issues](https://github.com/khoih-prog/functional-vlpp/issues) - someone might have already encountered this. + +If you don't find anything, please [open a new issue](https://github.com/khoih-prog/functional-vlpp/issues/new). + +### How to submit a bug report + +Please ensure to specify the following: + +* Arduino IDE version (e.g. 1.8.13) or Platform.io version +* `SAMD` Core Version (e.g. Arduino SAMD core v1.8.11, Adafruit SAMD core v1.6.5, Seeed Studio SAMD v1.8.1) +* Contextual information (e.g. what you were trying to achieve) +* Simplest possible steps to reproduce +* Anything that might be relevant in your opinion, such as: + * Operating system (Windows, Ubuntu, etc.) and the output of `uname -a` + * Network configuration + + +### Example + +``` +Arduino IDE version: 1.8.13 +Arduino SAMD Core Version 1.8.11 +OS: Ubuntu 20.04 LTS +Linux xy-Inspiron-3593 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux + +Context: +The board couldn't autoreconnect to Local Blynk Server after router power recycling. + +Steps to reproduce: +1. ... +2. ... +3. ... +4. ... +``` + +### Sending Feature Requests + +Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful. + +There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/functional-vlpp/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them. + +### Sending Pull Requests + +Pull Requests with changes and fixes are also welcome! diff --git a/software/firmware/source/libraries/functional-vlpp/LICENSE b/software/firmware/source/libraries/functional-vlpp/LICENSE new file mode 100644 index 000000000..cfe22f4c5 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Khoi Hoang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/software/firmware/source/libraries/functional-vlpp/README.md b/software/firmware/source/libraries/functional-vlpp/README.md new file mode 100644 index 000000000..828f93231 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/README.md @@ -0,0 +1,441 @@ +## functional-vlpp Library + +[![arduino-library-badge](https://www.ardu-badge.com/badge/Functional-Vlpp.svg?)](https://www.ardu-badge.com/Functional-Vlpp) +[![GitHub release](https://img.shields.io/github/release/khoih-prog/Functional-Vlpp.svg)](https://github.com/khoih-prog/Functional-Vlpp/releases) +[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/Functional-Vlpp/blob/master/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing) +[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/Functional-Vlpp.svg)](http://github.com/khoih-prog/Functional-Vlpp/issues) + +--- +--- + +## Table of Contents + +* [Why do we need this functional-vlpp library](#why-do-we-need-this-functional-vlpp-library) + * [Features](#features) + * [Currently supported Boards](#currently-supported-boards) +* [Changelog](#changelog) + * [Release v1.0.2](#release-v102) + * [Release v1.0.1](#release-v101) + * [Release v1.0.0](#release-v100) +* [Prerequisites](#prerequisites) +* [Installation](#installation) + * [Use Arduino Library Manager](#use-arduino-library-manager) + * [Manual Install](#manual-install) + * [VS Code & PlatformIO](#vs-code--platformio) +* [Packages' Patches](#packages-patches) + * [1. For Adafruit nRF52840 and nRF52832 boards](#1-for-adafruit-nRF52840-and-nRF52832-boards) + * [2. For Teensy boards](#2-for-teensy-boards) + * [3. For Arduino SAM DUE boards](#3-for-arduino-sam-due-boards) + * [4. For Arduino SAMD boards](#4-for-arduino-samd-boards) + * [For core version v1.8.10+](#for-core-version-v1810) + * [For core version v1.8.9-](#for-core-version-v189-) + * [5. For Adafruit SAMD boards](#5-for-adafruit-samd-boards) + * [6. For Seeeduino SAMD boards](#6-for-seeeduino-samd-boards) + * [7. For STM32 boards](#7-for-stm32-boards) +* [How to use](#how-to-use) +* [Libraries using this Functional-Vlpp library](#libraries-using-this-functional-vlpp-library) +* [How to use in your sketch](#how-to-use-in-your-sketch) +* [Releases](#releases) +* [Issues](#issues) +* [Contributions and Thanks](#contributions-and-thanks) +* [Contributing](#contributing) +* [License](#license) +* [Copyright](#copyright) + +--- +--- + +### Why do we need this [functional-vlpp library](https://github.com/khoih-prog/functional-vlpp) + +#### Features + +The original [**vczh-libraries/Vlpp**](https://github.com/vczh-libraries/Vlpp) provides common C++ construction, including string operation / generic container / linq, function templates to better support **C++ functional programming across platforms**. + +The `functional portion` of the project was then forked and modified to be used for Arduino by [**Marcus Rugger's functional-vlpp library**](https://github.com/marcusrugger/functional-vlpp). + +This [**Functional-Vlpp library**](https://github.com/khoih-prog/Functional-Vlpp) is based on, modified to use and tested working **OK** in other architectures such as **Teensy, SAM-DUE, SAMD, STM32, eps8266, esp32**. + +#### Currently supported Boards + +This [**Functional-Vlpp library**](https://github.com/khoih-prog/Functional-Vlpp) currently supports these following boards: + + 1. **nRF52 boards**, such as **AdaFruit Feather nRF52832, nRF52840 Express, BlueFruit Sense, Itsy-Bitsy nRF52840 Express, Metro nRF52840 Express, NINA_B302_ublox, NINA_B112_ublox, etc.** + + 2. **SAMD21** + - Arduino SAMD21: ZERO, MKRs, NANO_33_IOT, etc. + - Adafruit SAMD21 (M0): ItsyBitsy M0, Feather M0, Feather M0 Express, Metro M0 Express, Circuit Playground Express, Trinket M0, PIRkey, Hallowing M0, Crickit M0, etc. + - Seeeduino: LoRaWAN, Zero, Femto M0, XIAO M0, Wio GPS Board, etc. + + 3. **SAMD51** + - Adafruit SAMD51 (M4): Metro M4, Grand Central M4, ItsyBitsy M4, Feather M4 Express, Trellis M4, Metro M4 AirLift Lite, MONSTER M4SK Express, Hallowing M4, etc. + - Seeeduino: Wio Terminal, Grove UI Wireless + + 4. **SAM DUE** + 5. **Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0)** + 6. **STM32F/L/H/G/WB/MP1 boards (with 32+K Flash)** + - Nucleo-144 + - Nucleo-64 + - Discovery + - Generic STM32F0, STM32F1, STM32F2, STM32F3, STM32F4, STM32F7 (with 64+K Flash): x8 and up + - STM32L0, STM32L1, STM32L4 + - STM32G0, STM32G4 + - STM32H7 + - STM32WB + - STM32MP1 + - LoRa boards + - 3-D printer boards + - Generic Flight Controllers + - Midatronics boards + + 7. **ESP32** + 8. **ESP8266** + +--- +--- + +## Changelog + +### Release v1.0.2 + +1. Clear compiler warnings. +2. Add Version String +3. Add Table of Contents + +### Release v1.0.1 + +1. Add support to and tested working **OK** in other architectures such as **Teensy, SAM, SAMD, STM32, eps8266, esp32** besides AVR. + +### Release v1.0.0 + +1. Based on and modified from [**Marcus Rugger's functional-vlpp Library**](https://github.com/marcusrugger/functional-vlpp). + +--- +--- + +## Prerequisites + + 1. [`Arduino IDE 1.8.13+` for Arduino](https://www.arduino.cc/en/Main/Software) + 2. [`Arduino AVR core 1.8.3+`](https://github.com/arduino/ArduinoCore-avr) for Arduino AVR boards. Use Arduino Board Manager to install. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-avr.svg)](https://github.com/arduino/ArduinoCore-avr/releases/latest) + 3. [`Arduino Core for STM32 v1.9.0+`](https://github.com/stm32duino/Arduino_Core_STM32) for STM32 boards. [![GitHub release](https://img.shields.io/github/release/stm32duino/Arduino_Core_STM32.svg)](https://github.com/stm32duino/Arduino_Core_STM32/releases/latest) + 4. [`Teensy core 1.51+`](https://www.pjrc.com/teensy/td_download.html) for Teensy (4.1, 4.0, 3.6, 3.5, 3,2, 3.1, 3.0, LC) boards + 5. [`Arduino SAM DUE core 1.6.12+`](https://github.com/arduino/ArduinoCore-sam) for SAM DUE ARM Cortex-M3 boards + 6. [`Arduino SAMD core 1.8.11+`](https://www.arduino.cc/en/Guide/ArduinoM0) for SAMD ARM Cortex-M0+ boards. [![GitHub release](https://img.shields.io/github/release/arduino/ArduinoCore-samd.svg)](https://github.com/arduino/ArduinoCore-samd/releases/latest) + 7. [`Adafruit SAMD core 1.6.5+`](https://www.adafruit.com/) for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). [![GitHub release](https://img.shields.io/github/release/adafruit/ArduinoCore-samd.svg)](https://github.com/adafruit/ArduinoCore-samd/releases/latest) + 8. [`Seeeduino SAMD core 1.8.1+`](https://github.com/Seeed-Studio/ArduinoCore-samd) for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). [![Latest release](https://img.shields.io/github/release/Seeed-Studio/ArduinoCore-samd.svg)](https://github.com/Seeed-Studio/ArduinoCore-samd/releases/latest/) + 9. [`Adafruit nRF52 v0.21.0+`](https://www.adafruit.com) for nRF52 boards such as Adafruit NRF52840_FEATHER, NRF52832_FEATHER, NRF52840_FEATHER_SENSE, NRF52840_ITSYBITSY, NRF52840_CIRCUITPLAY, NRF52840_CLUE, NRF52840_METRO, NRF52840_PCA10056, PARTICLE_XENON, **NINA_B302_ublox, NINA_B112_ublox**, etc. [![GitHub release](https://img.shields.io/github/release/adafruit/Adafruit_nRF52_Arduino.svg)](https://github.com/adafruit/Adafruit_nRF52_Arduino/releases/latest) + +--- + +## Installation + +### Use Arduino Library Manager + +The best and easiest way is to use `Arduino Library Manager`. Search for `Functional-Vlpp`, then select / install the latest version. +You can also use this link [![arduino-library-badge](https://www.ardu-badge.com/badge/Functional-Vlpp.svg?)](https://www.ardu-badge.com/Functional-Vlpp) for more detailed instructions. + +### Manual Install + +1. Navigate to [Functional-Vlpp](https://github.com/khoih-prog/Functional-Vlpp) page. +2. Download the latest release `Functional-Vlpp-master.zip`. +3. Extract the zip file to `Functional-Vlpp-master` directory +4. Copy whole + - `Functional-Vlpp-master` folder to Arduino libraries' directory such as `~/Arduino/libraries/`. + +### VS Code & PlatformIO: + +1. Install [VS Code](https://code.visualstudio.com/) +2. Install [PlatformIO](https://platformio.org/platformio-ide) +3. Install [**Functional-Vlpp** library](https://platformio.org/lib/show/7082/Functional-Vlpp) by using [Library Manager](https://platformio.org/lib/show/7082/Functional-Vlpp/installation). Search for **Functional-Vlpp** in [Platform.io Author's Libraries](https://platformio.org/lib/search?query=author:%22Khoi%20Hoang%22) +4. Use included [platformio.ini](platformio/platformio.ini) file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at [Project Configuration File](https://docs.platformio.org/page/projectconf.html) + +--- + +### Packages' Patches + +#### 1. For Adafruit nRF52840 and nRF52832 boards + +**To be able to compile, run and automatically detect and display BOARD_NAME on nRF52840/nRF52832 boards**, you have to copy the whole [nRF52 0.21.0](Packages_Patches/adafruit/hardware/nrf52/0.21.0) directory into Adafruit nRF52 directory (~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0). + +Supposing the Adafruit nRF52 version is 0.21.0. These files must be copied into the directory: +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/boards.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B302_ublox/variant.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/variants/NINA_B112_ublox/variant.cpp` +- **`~/.arduino15/packages/adafruit/hardware/nrf52/0.21.0/cores/nRF5/Udp.h`** + +Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z +These files must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/platform.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/boards.txt` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B302_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B302_ublox/variant.cpp` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B112_ublox/variant.h` +- `~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/variants/NINA_B112_ublox/variant.cpp` +- **`~/.arduino15/packages/adafruit/hardware/nrf52/x.yy.z/cores/nRF5/Udp.h`** + +#### 2. For Teensy boards + + **To be able to compile and run on Teensy boards**, you have to copy the files in [**Packages_Patches for Teensy directory**](Packages_Patches/hardware/teensy/avr) into Teensy hardware directory (./arduino-1.8.13/hardware/teensy/avr/boards.txt). + +Supposing the Arduino version is 1.8.13. These files must be copied into the directory: + +- `./arduino-1.8.13/hardware/teensy/avr/boards.txt` +- `./arduino-1.8.13/hardware/teensy/avr/cores/teensy/Stream.h` +- `./arduino-1.8.13/hardware/teensy/avr/cores/teensy3/Stream.h` +- `./arduino-1.8.13/hardware/teensy/avr/cores/teensy4/Stream.h` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +These files must be copied into the directory: + +- `./arduino-x.yy.zz/hardware/teensy/avr/boards.txt` +- `./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy/Stream.h` +- `./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy3/Stream.h` +- `./arduino-x.yy.zz/hardware/teensy/avr/cores/teensy4/Stream.h` + +#### 3. For Arduino SAM DUE boards + + **To be able to compile and run on SAM DUE boards**, you have to copy the whole [SAM DUE](Packages_Patches/arduino/hardware/sam/1.6.12) directory into Arduino sam directory (~/.arduino15/packages/arduino/hardware/sam/1.6.12). + +Supposing the Arduino SAM core version is 1.6.12. This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/sam/1.6.12/platform.txt` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/sam/x.yy.zz/platform.txt` + +#### 4. For Arduino SAMD boards + + ***To be able to compile without error and automatically detect and display BOARD_NAME on Arduino SAMD (Nano-33-IoT, etc) boards***, you have to copy the whole [Arduino SAMD cores 1.8.10](Packages_Patches/arduino/hardware/samd/1.8.10) directory into Arduino SAMD directory (~/.arduino15/packages/arduino/hardware/samd/1.8.10). + +#### For core version v1.8.10+ + +Supposing the Arduino SAMD version is 1.8.11. Now only one file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/1.8.11/platform.txt` + +Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz + +This file must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/x.yy.zz/platform.txt` + +#### For core version v1.8.9- + +Supposing the Arduino SAMD version is 1.8.9. These files must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/1.8.9/platform.txt` +- ***`~/.arduino15/packages/arduino/hardware/samd/1.8.9/cores/arduino/Arduino.h`*** + +Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z + +These files must be copied into the directory: + +- `~/.arduino15/packages/arduino/hardware/samd/x.yy.z/platform.txt` +- ***`~/.arduino15/packages/arduino/hardware/samd/x.yy.z/cores/arduino/Arduino.h`*** + + This is mandatory to fix the ***notorious Arduino SAMD compiler error***. See [Improve Arduino compatibility with the STL (min and max macro)](https://github.com/arduino/ArduinoCore-samd/pull/399) + +``` + ...\arm-none-eabi\include\c++\7.2.1\bits\stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2 + min(const _Tp& __a, const _Tp& __b, _Compare __comp) +``` + +Whenever the above-mentioned compiler error issue is fixed with the new Arduino SAMD release, you don't need to copy the `Arduino.h` file anymore. + +#### 5. For Adafruit SAMD boards + + ***To be able to automatically detect and display BOARD_NAME on Adafruit SAMD (Itsy-Bitsy M4, etc) boards***, you have to copy the file [Adafruit SAMD platform.txt](Packages_Patches/adafruit/hardware/samd/1.6.4) into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.6.4). + +Supposing the Adafruit SAMD core version is 1.6.4. This file must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/samd/1.6.4/platform.txt` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/platform.txt` + +#### 6. For Seeeduino SAMD boards + + ***To be able to automatically detect and display BOARD_NAME on Seeeduino SAMD (XIAO M0, Wio Terminal, etc) boards***, you have to copy the file [Seeeduino SAMD platform.txt](Packages_Patches/Seeeduino/hardware/samd/1.8.1) into Adafruit samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.1). + +Supposing the Seeeduino SAMD core version is 1.8.1. This file must be copied into the directory: + +- `~/.arduino15/packages/Seeeduino/hardware/samd/1.8.1/platform.txt` + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz +This file must be copied into the directory: + +- `~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/platform.txt` + +#### 7. For STM32 boards + +**To use Serial1 on some STM32 boards without Serial1 definition (Nucleo-144 NUCLEO_F767ZI, Nucleo-64 NUCLEO_L053R8, etc.) boards**, you have to copy the files [STM32 variant.h](Packages_Patches/STM32/hardware/stm32/1.9.0) into STM32 stm32 directory (~/.arduino15/packages/STM32/hardware/stm32/1.9.0). You have to modify the files corresponding to your boards, this is just an illustration how to do. + +Supposing the STM32 stm32 core version is 1.9.0. These files must be copied into the directory: + +- `~/.arduino15/packages/STM32/hardware/stm32/1.9.0/variants/NUCLEO_F767ZI/variant.h` for Nucleo-144 NUCLEO_F767ZI. +- `~/.arduino15/packages/STM32/hardware/stm32/1.9.0/variants/NUCLEO_L053R8/variant.h` for Nucleo-64 NUCLEO_L053R8. + +Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz, +theses files must be copied into the corresponding directory: + +- `~/.arduino15/packages/STM32/hardware/stm32/x.yy.zz/variants/NUCLEO_F767ZI/variant.h` +- `~/.arduino15/packages/STM32/hardware/stm32/x.yy.zz/variants/NUCLEO_L053R8/variant.h` + +--- +--- + +### How to use + +This library can be used as a replacement of C++11 STL `std::function`. + +For example, we can use `typedef vl::Func THandlerFunction` instead of `typedef std::function THandlerFunction` or `typedef void (*THandlerFunction)(void)`. + +Its importance is the ability to be used in complicated function calls, such as private Lambda functions in Classes. + +For example: + +```cpp +class BlynkEthernet + : public BlynkProtocol +{ + typedef BlynkProtocol Base; +public: + +... + +private: + EthernetWebServer *server; + ... + + void startConfigurationMode() + { + ... + if (!server) + server = new EthernetWebServer; + + if (server) + { + server->on("/", [this](){ handleRequest(); }); + server->begin(); + } + ... + } +}; + +``` + +--- +--- + +### Libraries using this [Functional-Vlpp library](https://github.com/khoih-prog/Functional-Vlpp) + +This [**Functional-Vlpp library**](https://github.com/khoih-prog/Functional-Vlpp) has been used sucessfully in : + +1. [ESP8266_AT_WebServer library for Arduino, Teensy, SAM, SAMD, STM32, etc. architectures](https://github.com/khoih-prog/ESP8266_AT_WebServer) +2. [EthernetWebServer library for Arduino, ESP,Teensy, SAM, SAMD, etc. architectures](https://github.com/khoih-prog/EthernetWebServer) +3. [EthernetWebServer_STM32 library for STM32 architectures](https://github.com/khoih-prog/EthernetWebServer_STM32) +4. [Blynk_Esp8266AT_WM library for Arduino, Teensy, SAM, SAMD, STM32, etc. architectures](https://github.com/khoih-prog/Blynk_Esp8266AT_WM) +5. [BlynkEthernet_WM library for Arduino, ESP,Teensy, SAM, SAMD, etc. architectures](https://github.com/khoih-prog/BlynkEthernet_WM) +6. [BlynkEthernet_STM32_WM library for Arduino, Teensy, SAM, SAMD, STM32, etc. architectures](https://github.com/khoih-prog/BlynkEthernet_STM32_WM) +7. [WiFiManager_NINA_Lite library for Arduino, Teensy, SAM, SAMD, STM32, etc. architectures](https://github.com/khoih-prog/WiFiManager_NINA_Lite) +8. [WiFiWebServer library for Arduino, Teensy, SAM, SAMD, STM32, etc. architectures](https://github.com/khoih-prog/WiFiWebServer) + +and many more to come. + +--- +--- + +### How to use in your sketch + +Just include in your sketch and modify as follows + +```cpp +// For this functional-vlpp library +#include + +// Modify from +//typedef std::function THandlerFunction; +// or +//typedef void (*THandlerFunction)(void); +// to this +typedef vl::Func THandlerFunction; +// That's it + +// Keep these the same +void on(const String &uri, THandlerFunction handler); +void on(const String &uri, HTTPMethod method, THandlerFunction fn); +void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn); +void addHandler(RequestHandler* handler); +void onNotFound(THandlerFunction fn); //called when handler is not assigned +void onFileUpload(THandlerFunction fn); //handle file uploads + +``` +--- +--- + +## Releases + +### Release v1.0.2 + +1. Clear compiler warnings. +2. Add Version String +3. Add Table of Contents + +### Release v1.0.1 + +1. Add support to and tested working **OK** in other architectures such as **Teensy, SAM, SAMD, stm32, eps8266, esp32** besides AVR. + +### Release v1.0.0 + +1. Based on and modified from [Marcus Rugger's functional-vlpp library](https://github.com/marcusrugger/functional-vlpp). + + +--- +--- + +### Issues + +Submit issues to: [WiFiManager_NINA_Lite issues](https://github.com/khoih-prog/Functional-Vlpp/issues) + +--- +--- + +### Contributions and thanks + +1. Based on and modified from [vczh-libraries/Vlpp](https://github.com/vczh-libraries/Vlpp) and [Marcus Rugger functional-vlpp library](https://github.com/marcusrugger/functional-vlpp) + + + + + +
marcusrugger
⭐️ Marcus Rugger

+ +--- + +### Contributing + +If you want to contribute to this project: +- Report bugs and errors +- Ask for enhancements +- Create issues and pull requests +- Tell other people about this library + +--- + +### License + +- The library is licensed under [MIT](https://github.com/khoih-prog/Functional-Vlpp/blob/master/LICENSE) + +--- + +### Copyright + +Copyright 2020- Khoi Hoang diff --git a/software/firmware/source/libraries/functional-vlpp/keywords.txt b/software/firmware/source/libraries/functional-vlpp/keywords.txt new file mode 100644 index 000000000..ef2def378 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/keywords.txt @@ -0,0 +1,81 @@ +####################################### +# Data types (KEYWORD1) +####################################### +NotCopyable KEYWORD1 +RemoveReference KEYWORD1 +RemoveConst KEYWORD1 +RemoveVolatile KEYWORD1 +RemoveCVR KEYWORD1 +ForwardValue KEYWORD1 +TypeTuple KEYWORD1 +Object KEYWORD1 +ObjectBox KEYWORD1 +Nullable KEYWORD1 +BinaryRetriver KEYWORD1 +KeyType KEYWORD1 +POD KEYWORD1 +Interface KEYWORD1 +YesType KEYWORD1 +NoType KEYWORD1 +AcceptType KEYWORD1 +YesNoAnd KEYWORD1 +YesNoOr KEYWORD1 +AcceptValue KEYWORD1 +PointerConvertable KEYWORD1 +ReturnConvertable KEYWORD1 +AcceptAlways KEYWORD1 +RequiresConvertable KEYWORD1 +ReferenceCounterOperator KEYWORD1 +Ptr KEYWORD1 +ComPtr KEYWORD1 +Func KEYWORD1 +Invoker KEYWORD1 +StaticInvoker KEYWORD1 +MemberInvoker KEYWORD1 +ObjectInvoker KEYWORD1 +LambdaRetriveType KEYWORD1 +FunctionObjectRetriveType KEYWORD1 +Binding KEYWORD1 +CR KEYWORD1 +Binder KEYWORD1 +Currier KEYWORD1 +Combining KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +Unbox KEYWORD2 +Equals KEYWORD2 +Equals KEYWORD2 +Value KEYWORD2 +GetKeyValue KEYWORD2 +CreateCounter KEYWORD2 +DeleteReference KEYWORD2 +Inc KEYWORD2 +Dec KEYWORD2 +Counter KEYWORD2 +Cast KEYWORD2 +Obj KEYWORD2 +MakePtr KEYWORD2 +KeyType KEYWORD2 +Invoke KEYWORD2 +Lambda KEYWORD2 +Curry KEYWORD2 + +####################################### +# Literals (LITERAL1) +####################################### + +vint8_t LITERAL1 +vuint8_t LITERAL1 +vint16_t LITERAL1 +vuint16_t LITERAL1 +vint32_t LITERAL1 +vuint32_t LITERAL1 +vint64_t LITERAL1 +vuint64_t LITERAL1 +vint LITERAL1 +vsint LITERAL1 +vuint LITERAL1 +pos_t LITERAL1 diff --git a/software/firmware/source/libraries/functional-vlpp/library.json b/software/firmware/source/libraries/functional-vlpp/library.json new file mode 100644 index 000000000..159e69bda --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/library.json @@ -0,0 +1,22 @@ +{ + "name": "Functional-Vlpp", + "version": "1.0.2", + "keywords": "C++, Function, functional-vlpp, lambda-function, Lambda, Class, AVR, Teensy, SAM, SAMD, stm32, eps8266, esp32, nRF52", + "description": "Provides common C++ construction, including string operation / generic container / linq, function templates to better support C++ functional programming across platforms", + "repository": + { + "type": "git", + "url": "https://github.com/khoih-prog/functional-vlpp" + }, + "homepage": "https://github.com/khoih-prog/functional-vlpp", + "export": { + "exclude": [ + "linux", + "extras", + "tests" + ] + }, + "frameworks": "*", + "platforms": "*", + "examples": "examples/*/*/*.ino" +} diff --git a/software/firmware/source/libraries/functional-vlpp/library.properties b/software/firmware/source/libraries/functional-vlpp/library.properties new file mode 100644 index 000000000..fc221b253 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/library.properties @@ -0,0 +1,9 @@ +name=Functional-Vlpp +version=1.0.2 +author=Khoi Hoang +maintainer=Khoi Hoang +sentence=Provides function templates to better support C++ functional programming across platforms. +paragraph=Provides common C++ construction, including string operation / generic container / linq, function templates to better support C++ functional programming across platforms +category=Other +url=https://github.com/khoih-prog/functional-vlpp +architectures=* diff --git a/software/firmware/source/libraries/functional-vlpp/platformio/platformio.ini b/software/firmware/source/libraries/functional-vlpp/platformio/platformio.ini new file mode 100644 index 000000000..f48cca6c4 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/platformio/platformio.ini @@ -0,0 +1,335 @@ +;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] +; ============================================================ +; chose environment: +; ESP8266 +; ESP32 +; SAMD +; NRF52 +; STM32 +; ============================================================ +;default_envs = ESP8266 +;default_envs = ESP32 +default_envs = SAMD +;default_envs = NRF52 +;default_envs = STM32 + +[env] +; ============================================================ +; Serial configuration +; choose upload speed, serial-monitor speed +; ============================================================ +upload_speed = 921600 +;upload_port = COM11 +;monitor_speed = 9600 +;monitor_port = COM11 + +lib_deps = + + +build_flags = +; set your debug output (default=Serial) +; -D DEBUG_ESP_PORT=Serial +; comment the folowing line to enable WiFi debugging +; -D NDEBUG + +[env:ESP8266] +platform = espressif8266 +framework = arduino +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = gen4iod +;board = huzzah +;board = oak +;board = esp_wroom_02 +;board = espduino +;board = espectro +;board = espino +;board = espresso_lite_v1 +;board = espresso_lite_v2 +;board = esp12e +;board = esp01_1m +;board = esp01 +;board = esp07 +;board = esp8285 +;board = heltec_wifi_kit_8 +;board = inventone +;board = nodemcu +board = nodemcuv2 +;board = modwifi +;board = phoenix_v1 +;board = phoenix_v2 +;board = sparkfunBlynk +;board = thing +;board = thingdev +;board = esp210 +;board = espinotee +;board = d1 +;board = d1_mini +;board = d1_mini_lite +;board = d1_mini_pro +;board = wifi_slot +;board = wifiduino +;board = wifinfo +;board = wio_link +;board = wio_node +;board = xinabox_cw01 +;board = esp32doit-devkit-v1 + +[env:ESP32] +platform = espressif32 +framework = arduino, espidf +; ============================================================ +; Board configuration +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = esp32cam +;board = alksesp32 +;board = featheresp32 +;board = espea32 +;board = bpi-bit +;board = d-duino-32 +board = esp32doit-devkit-v1 +;board = pocket_32 +;board = fm-devkit +;board = pico32 +;board = esp32-evb +;board = esp32-gateway +;board = esp32-pro +;board = esp32-poe +;board = oroca_edubot +;board = onehorse32dev +;board = lopy +;board = lopy4 +;board = wesp32 +;board = esp32thing +;board = sparkfun_lora_gateway_1-channel +;board = ttgo-lora32-v1 +;board = ttgo-t-beam +;board = turta_iot_node +;board = lolin_d32 +;board = lolin_d32_pro +;board = lolin32 +;board = wemosbat +;board = widora-air +;board = xinabox_cw02 +;board = iotbusio +;board = iotbusproteus +;board = nina_w10 + +[env:SAMD] +platform = atmelsam +framework = arduino +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ +; ============================================================ +; Board configuration Adafruit SAMD +; ============================================================ + +;board = adafruit_feather_m0 +;board = adafruit_feather_m0_express +;board = adafruit_metro_m0 +;board = adafruit_circuitplayground_m0 +;board = adafruit_gemma_m0 +;board = adafruit_trinket_m0 +;board = adafruit_itsybitsy_m0 +;board = adafruit_pirkey +;board = adafruit_hallowing +;board = adafruit_crickit_m0 +;board = adafruit_metro_m4 +;board = adafruit_grandcentral_m4 +board = adafruit_itsybitsy_m4 +;board = adafruit_feather_m4 +;board = adafruit_trellis_m4 +;board = adafruit_pyportal_m4 +;board = adafruit_pyportal_m4_titano +;board = adafruit_pybadge_m4 +;board = adafruit_metro_m4_airliftlite +;board = adafruit_pygamer_m4 +;board = adafruit_pygamer_advance_m4 +;board = adafruit_pybadge_airlift_m4 +;board = adafruit_monster_m4sk +;board = adafruit_hallowing_m4 + +; ============================================================ +; Board configuration Arduino SAMD and SAM +; ============================================================ + +;board = arduino_zero_edbg +;board = arduino_zero_native +;board = mkr1000 +;board = mkrzero +;board = mkrwifi1010 +;board = nano_33_iot +;board = mkrfox1200 +;board = mkrwan1300 +;board = mkrwan1310 +;board = mkrgsm1400 +;board = mkrnb1500 +;board = mkrvidor4000 +;board = adafruit_circuitplayground_m0 +;board = mzero_pro_bl_dbg +;board = mzero_pro_bl +;board = mzero_bl +;board = tian +;board = tian_cons +;board = arduino_due_x_dbg +;board = arduino_due_x + +; ============================================================ +; Board configuration Seeeduino SAMD +; ============================================================ + +;board = seeed_wio_terminal +;board = Seeed_femto_m0 +;board = seeed_XIAO_m0 +;board = Wio_Lite_MG126 +;board = WioGPS +;board = zero +;board = rolawan +;board = seeed_grove_ui_wireless + + +[env:NRF52] +platform = nordicnrf52 +framework = arduino +; ============================================================ +; Board configuration Adafruit nRF52 +; choose your board by uncommenting one of the following lines +; ============================================================ +;board = feather52832 +board = feather52840 +;board = feather52840sense +;board = itsybitsy52840 +;board = cplaynrf52840 +;board = cluenrf52840 +;board = metro52840 +;board = pca10056 +;board = particle_xenon +;board = mdbt50qrx +;board = ninab302 +;board = ninab112 + +[env:STM32] +platform = ststm32 +framework = arduino + +; ============================================================ +; Choose your board by uncommenting one of the following lines +; ============================================================ + +; ============================================================ +; Board configuration Nucleo-144 +; ============================================================ + +;board = nucleo_f207zg +;board = nucleo_f429zi +;board = nucleo_f746zg +;board = nucleo_f756zg +;board = nucleo_f767zi +;board = nucleo_h743zi +;board = nucleo_l496zg +;board = nucleo_l496zg-p +;board = nucleo_l4r5zi +;board = nucleo_l4r5zi-p + +; ============================================================ +; Board configuration Nucleo-64 +; ============================================================ + +;board = nucleo_f030r8 +;board = nucleo_f072rb + +;board = nucleo_f091rc +;board = nucleo_f103rb +;board = nucleo_f302r8 +;board = nucleo_f303re +;board = nucleo_f401re +;board = nucleo_f411re +;board = nucleo_f446re +;board = nucleo_g071rb +;board = nucleo_g431rb +;board = nucleo_g474re +;board = nucleo_l053r8 +;board = nucleo_l073rz +;board = nucleo_l152re +;board = nucleo_l433rc_p +;board = nucleo_l452re +;board = nucleo_l452re-p +;board = nucleo_l476rg +;board = pnucleo_wb55rg + +; ============================================================ +; Board configuration Nucleo-32 +; ============================================================ + +;board = nucleo_f031k6 +;board = nucleo_l031k6 +;board = nucleo_l412kb +;board = nucleo_l432lc +;board = nucleo_f303k8 +;board = nucleo_g431kb + +; ============================================================ +; Board configuration Discovery Boards +; ============================================================ + +;board = disco_f030r8 +;board = disco_f072rb +;board = disco_f030r8 +;board = disco_f100rb +;board = disco_f407vg +;board = disco_f413zh +;board = disco_f746ng +;board = disco_g0316 +;board = disco_l475vg_iot +;board = disco_f072cz-lrwan1 + +; ============================================================ +; Board configuration STM32MP1 Boards +; ============================================================ + +;board = stm32mp157a-dk1 +;board = stm32mp157c-dk2 + +; ============================================================ +; Board configuration Generic Boards +; ============================================================ + +;board = bluepill_f103c6 +;board = bluepill_f103c8 +;board = blackpill_f103c8 +;board = stm32f103cx +;board = stm32f103rx +;board = stm32f103tx +;board = stm32f103vx +;board = stm32f103zx +;board = stm32f103zet6 +;board = maplemini_f103cb +;board = blackpill_f303cc +;board = black_f407ve +;board = black_f407vg +;board = black_f407ze +;board = black_f407zg +;board = blue_f407ve_mini +;board = blackpill_f401cc +;board = blackpill_f411ce +;board = coreboard_f401rc +;board = feather_f405 + +; ============================================================ +; Board configuration Many more Boards to be filled +; ============================================================ + diff --git a/software/firmware/source/libraries/functional-vlpp/src/Basic.h b/software/firmware/source/libraries/functional-vlpp/src/Basic.h new file mode 100644 index 000000000..250750f82 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/src/Basic.h @@ -0,0 +1,743 @@ +/**************************************************************************************************************************** + Basic.h + + This library provides function templates to better support C++ functional programming across platforms. + Based on Vlpp library (https://github.com/vczh-libraries/Vlpp) + and Marcus Rugger functional-vlpp library (https://github.com/marcusrugger/functional-vlpp) + Built by Khoi Hoang (https://github.com/khoih-prog/functional-vlpp) + Licensed under MIT license + + Original author + Vczh Library++ 3.0 + Developer: Zihan Chen(vczh) + Framework::Basic + + Classes: + NotCopyable : Object inherits from this type cannot be copied + Error : Error, unlike exception, is not encouraged to catch + Object : Base class of all classes + + Macros: + CHECK_ERROR(CONDITION,DESCRIPTION) : Assert, throws an Error if failed + CHECK_FAIL(DESCRIPTION) : Force an assert failure + SCOPE_VARIABLE(TYPE,VARIABLE,VALUE){ ... } : Scoped variable + + Version: 1.0.2 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2019 Initial coding, testing and supporting AVR architecture + 1.0.1 K Hoang 01/03/2020 Add support for STM32 and all other architectures. + 1.0.2 K Hoang 21/02/2021 Clear compiler warnings + *****************************************************************************************************************************/ + +#pragma once + +#ifndef VCZH_BASIC +#define VCZH_BASIC + +#ifdef VCZH_CHECK_MEMORY_LEAKS + #define _CRTDBG_MAP_ALLOC + #include + #include + #define VCZH_CHECK_MEMORY_LEAKS_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) + #define new VCZH_CHECK_MEMORY_LEAKS_NEW +#endif + +#include +#include +#define abstract +#define __thiscall +#define __forceinline inline + +#define _I8_MIN ((vint8_t)0x80) +#define _I8_MAX ((vint8_t)0x7F) +#define _UI8_MAX ((vuint8_t)0xFF) + +#define _I16_MIN ((vint16_t)0x8000) +#define _I16_MAX ((vint16_t)0x7FFF) +#define _UI16_MAX ((vuint16_t)0xFFFF) + +#define _I32_MIN ((vint32_t)0x80000000) +#define _I32_MAX ((vint32_t)0x7FFFFFFF) +#define _UI32_MAX ((vuint32_t)0xFFFFFFFF) + +#define _I64_MIN ((vint64_t)0x8000000000000000L) +#define _I64_MAX ((vint64_t)0x7FFFFFFFFFFFFFFFL) +#define _UI64_MAX ((vuint64_t)0xFFFFFFFFFFFFFFFFL) + +#define L_(x) L__(x) +#define L__(x) L ## x + +namespace vl +{ + typedef int8_t vint8_t; + typedef uint8_t vuint8_t; + typedef int16_t vint16_t; + typedef uint16_t vuint16_t; + typedef int32_t vint32_t; + typedef uint32_t vuint32_t; + typedef int64_t vint64_t; + typedef uint64_t vuint64_t; + + + /// Signed interface whose size is equal to sizeof(void*). + typedef vint32_t vint; + /// Signed interface whose size is equal to sizeof(void*). + typedef vint32_t vsint; + /// Unsigned interface whose size is equal to sizeof(void*). + typedef vuint32_t vuint; + + /// Signed interger representing position. + typedef vint64_t pos_t; + + #define ITOA_S _itoa_s + #define ITOW_S _itow_s + #define I64TOA_S _i64toa_s + #define I64TOW_S _i64tow_s + #define UITOA_S _ui64toa_s + #define UITOW_S _ui64tow_s + #define UI64TOA_S _ui64toa_s + #define UI64TOW_S _ui64tow_s + + //#define INCRC(x) (__sync_add_and_fetch(x, 1)) + //#define DECRC(x) (__sync_sub_and_fetch(x, 1)) + #define INCRC(x) (++(*x)) + #define DECRC(x) (--(*x)) + + + /*********************************************************************** + NotCopyable Base Class + ***********************************************************************/ + + class NotCopyable + { + private: + NotCopyable(const NotCopyable&) + { + } + NotCopyable& operator=(const NotCopyable&) + { + return *this; + } + public: + NotCopyable() + { + } + }; + + #define SCOPE_VARIABLE(TYPE, VARIABLE, VALUE)\ + if(bool __scope_variable_flag__=true)\ + for(TYPE VARIABLE = VALUE;__scope_variable_flag__;__scope_variable_flag__=false) + + /*********************************************************************** + Type Traits + ***********************************************************************/ + + template + struct RemoveReference + { + typedef T Type; + }; + + template + struct RemoveReference + { + typedef T Type; + }; + + template + struct RemoveReference < T&& > + { + typedef T Type; + }; + + template + struct RemoveConst + { + typedef T Type; + }; + + template + struct RemoveConst + { + typedef T Type; + }; + + template + struct RemoveVolatile + { + typedef T Type; + }; + + template + struct RemoveVolatile + { + typedef T Type; + }; + + template + struct RemoveCVR + { + typedef T Type; + }; + + template + struct RemoveCVR + { + typedef typename RemoveCVR::Type Type; + }; + + template + struct RemoveCVR < T&& > + { + typedef typename RemoveCVR::Type Type; + }; + + template + struct RemoveCVR + { + typedef typename RemoveCVR::Type Type; + }; + + template + struct RemoveCVR + { + typedef typename RemoveCVR::Type Type; + }; + + template + typename RemoveReference::Type&& MoveValue(T&& value) + { + return (typename RemoveReference::Type&&)value; + } + + template + T&& ForwardValue(typename RemoveReference::Type&& value) + { + return (T&&)value; + } + + template + T&& ForwardValue(typename RemoveReference::Type& value) + { + return (T&&)value; + } + + template + struct TypeTuple + { + }; + + /*********************************************************************** + Object Base Class + ***********************************************************************/ + + /// Base type of all classes. + class Object + { + public: + virtual ~Object() + { + } + }; + + /// Type for storing a value to wherever requiring a [T:vl.Ptr`1] to [T:vl.Object]. + /// Type of the value. + template + class ObjectBox : public Object + { + private: + T object; + public: + /// Box a value. + /// The value to box. + ObjectBox(const T& _object) + : object(_object) + { + } + + /// Box a movable value. + /// The value to box. + ObjectBox(T&& _object) + : object(MoveValue(_object)) + { + } + + /// Copy a box. + /// The box. + ObjectBox(const ObjectBox& value) + : object(value.object) + { + } + + /// Move a box. + /// The box. + ObjectBox(ObjectBox&& value) + : object(MoveValue(value.object)) + { + } + + /// Box a value. + /// The boxed value. + /// The value to box. + ObjectBox& operator=(const T& _object) + { + object = _object; + return *this; + } + + /// Copy a box. + /// The boxed value. + /// The box. + ObjectBox& operator=(const ObjectBox& value) + { + object = value.object; + return *this; + } + + /// Move a box. + /// The boxed value. + /// The box. + ObjectBox& operator=(ObjectBox&& value) + { + object = MoveValue(value.object); + return *this; + } + + /// Unbox the value. + /// The original value. + const T& Unbox() + { + return object; + } + }; + + /// Type for optionally storing a value. + /// Type of the value. + template + class Nullable + { + private: + T* object; + public: + /// Create a null value. + Nullable() + : object(0) + { + } + + /// Create a non-null value. + /// The value to copy. + Nullable(const T& value) + : object(new T(value)) + { + } + + /// Create a non-null value. + /// The value to move. + Nullable(T&& value) + : object(new T(MoveValue(value))) + { + } + + /// Copy a nullable value. + /// The nullable value to copy. + Nullable(const Nullable& nullable) + : object(nullable.object ? new T(*nullable.object) : 0) + { + } + + /// Move a nullable value. + /// The nullable value to move. + Nullable(Nullable&& nullable) + : object(nullable.object) + { + nullable.object = 0; + } + + ~Nullable() + { + if (object) + { + delete object; + object = 0; + } + } + + /// Create a non-null value. + /// The created nullable value. + /// The value to copy. + Nullable& operator=(const T& value) + { + if (object) + { + delete object; + object = 0; + } + + object = new T(value); + return *this; + } + + /// Copy a nullable value. + /// The created nullable value. + /// The nullable value to copy. + Nullable& operator=(const Nullable& nullable) + { + if (this != &nullable) + { + if (object) + { + delete object; + object = 0; + } + + if (nullable.object) + { + object = new T(*nullable.object); + } + } + + return *this; + } + + /// Move a nullable value. + /// The created nullable value. + /// The nullable value to move. + Nullable& operator=(Nullable&& nullable) + { + if (this != &nullable) + { + if (object) + { + delete object; + object = 0; + } + + object = nullable.object; + nullable.object = 0; + } + return *this; + } + + static bool Equals(const Nullable& a, const Nullable& b) + { + return + a.object + ? b.object + ? *a.object == *b.object + : false + : b.object + ? false + : true; + } + + static vint Compare(const Nullable& a, const Nullable& b) + { + return + a.object + ? b.object + ? (*a.object == *b.object ? 0 : *a.object < *b.object ? -1 : 1) + : 1 + : b.object + ? -1 + : 0; + } + + bool operator==(const Nullable& nullable)const + { + return Equals(*this, nullable); + } + + bool operator!=(const Nullable& nullable)const + { + return !Equals(*this, nullable); + } + + bool operator<(const Nullable& nullable)const + { + return Compare(*this, nullable) < 0; + } + + bool operator<=(const Nullable& nullable)const + { + return Compare(*this, nullable) <= 0; + } + + bool operator>(const Nullable& nullable)const + { + return Compare(*this, nullable) > 0; + } + + bool operator>=(const Nullable& nullable)const + { + return Compare(*this, nullable) >= 0; + } + + /// Convert the nullable value to a bool value. + /// Returns true if it is not null. + operator bool()const + { + return object != 0; + } + + /// Unbox the value. This operation will cause an access violation of it is null. + /// The original value. + const T& Value()const + { + return *object; + } + }; + + template + union BinaryRetriver + { + T t; + char binary[sizeof(T) > minSize ? sizeof(T) : minSize]; + }; + + /*********************************************************************** + Configuration Type Traits + ***********************************************************************/ + + /// Get the index type of a value for containers. + /// Type of the value. + template + struct KeyType + { + public: + /// The index type of a value for containers. + typedef T Type; + + /// Convert a value to its index type. + /// The corresponding index value. + /// The value. + static T GetKeyValue(const T& value) + { + return value; + } + }; + + /// Test is a type a Plain-Old-Data type for containers. + /// The type to test. + template + struct POD + { + /// Returns true if the type is a Plain-Old-Data type. + static const bool Result = false; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD { + + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + template<>struct POD + { + static const bool Result = true; + }; + + templatestruct POD + { + static const bool Result = true; + }; + + templatestruct POD + { + static const bool Result = true; + }; + + templatestruct POD < T&& > + { + static const bool Result = true; + }; + + templatestruct POD + { + static const bool Result = true; + }; + + templatestruct POD + { + static const bool Result = POD::Result; + }; + + templatestruct POD + { + static const bool Result = POD::Result; + }; + + templatestruct POD + { + static const bool Result = POD::Result; + }; + + templatestruct POD + { + static const bool Result = POD::Result; + }; + + /*********************************************************************** + Interface Class + ***********************************************************************/ + + /// Base type of all interfaces. All interface types are encouraged to be virtual inherited. + class Interface : private NotCopyable + { + public: + virtual ~Interface() + { + } + }; + + /*********************************************************************** + Type Extraction Class + ***********************************************************************/ + + struct YesType {}; + struct NoType {}; + + template + struct AcceptType + { + }; + + template + struct AcceptType + { + typedef T Type; + }; + + template + struct YesNoAnd + { + typedef NoType Type; + }; + + template<> + struct YesNoAnd + { + typedef YesType Type; + }; + + template + struct YesNoOr + { + typedef YesType Type; + }; + + template<> + struct YesNoOr + { + typedef NoType Type; + }; + + template + struct AcceptValue + { + static const bool Result = false; + }; + + template<> + struct AcceptValue + { + static const bool Result = true; + }; + + template + T ValueOf(); + + template + struct PointerConvertable + { + static YesType Test(TTo* value); + static NoType Test(void* value); + + typedef decltype(Test(ValueOf())) YesNoType; + }; + + template + struct ReturnConvertable + { + static YesType Test(TTo&& value); + static NoType Test(...); + + typedef decltype(Test(ValueOf < TFrom&& > ())) YesNoType; + }; + + template + struct ReturnConvertable + { + typedef YesType YesNoType; + }; + + template + struct ReturnConvertable + { + typedef NoType YesNoType; + }; + + template<> + struct ReturnConvertable + { + typedef YesType YesNoType; + }; + + template + struct AcceptAlways + { + typedef T Type; + }; + + template + struct RequiresConvertable + { + static YesType Test(TTo* value); + static NoType Test(void* value); + + typedef decltype(Test((TFrom*)0)) YesNoType; + }; +} // namespace vl + +#endif // VCZH_BASIC diff --git a/software/firmware/source/libraries/functional-vlpp/src/Function.h b/software/firmware/source/libraries/functional-vlpp/src/Function.h new file mode 100644 index 000000000..b3952b61d --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/src/Function.h @@ -0,0 +1,478 @@ +/**************************************************************************************************************************** + Function.h + + This library provides function templates to better support C++ functional programming across platforms. + Based on Vlpp library (https://github.com/vczh-libraries/Vlpp) + and Marcus Rugger functional-vlpp library (https://github.com/marcusrugger/functional-vlpp) + Built by Khoi Hoang (https://github.com/khoih-prog/functional-vlpp) + Licensed under MIT license + + Original author + Vczh Library++ 3.0 + Developer: Zihan Chen(vczh) + Framework::Basic + + Classes: + Func :Function object + + Functions: + Curry :: (A->B) -> A -> B :Currying + Combine :: (A->B) -> (A->C) -> (B->C->D) -> (A->D) :Combine multiple functors using an operator + + Version: 1.0.2 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2019 Initial coding, testing and supporting AVR architecture + 1.0.1 K Hoang 01/03/2020 Add support for STM32 and all other architectures. + 1.0.2 K Hoang 21/02/2021 Clear compiler warnings + *****************************************************************************************************************************/ + +#pragma once + +#ifndef VCZH_FUNCTION +#define VCZH_FUNCTION + +#include +#include "Basic.h" +#include "Pointer.h" + +namespace vl +{ + + /*********************************************************************** + vl::Func + ***********************************************************************/ + + template + class Func + { + }; + + namespace internal_invokers + { + template + class Invoker : public Object + { + public: + virtual R Invoke(TArgs&& ...args) = 0; + }; + + //------------------------------------------------------ + + template + class StaticInvoker : public Invoker + { + protected: + R(*function)(TArgs ...args); + + public: + StaticInvoker(R(*_function)(TArgs...)) + : function(_function) + { + } + + R Invoke(TArgs&& ...args)override + { + return function(ForwardValue(args)...); + } + }; + + //------------------------------------------------------ + + template + class MemberInvoker : public Invoker + { + protected: + C* sender; + R(C::*function)(TArgs ...args); + + public: + MemberInvoker(C* _sender, R(C::*_function)(TArgs ...args)) + : sender(_sender) + , function(_function) + { + } + + R Invoke(TArgs&& ...args)override + { + return (sender->*function)(ForwardValue(args)...); + } + }; + + //------------------------------------------------------ + + template + class ObjectInvoker : public Invoker + { + protected: + C function; + + public: + ObjectInvoker(const C& _function) + : function(_function) + { + } + + R Invoke(TArgs&& ...args)override + { + return function(ForwardValue(args)...); + } + }; + + //------------------------------------------------------ + + template + class ObjectInvoker : public Invoker + { + protected: + C function; + + public: + ObjectInvoker(const C& _function) + : function(_function) + { + } + + void Invoke(TArgs&& ...args)override + { + function(ForwardValue(args)...); + } + }; + } + + /// A type representing a function reference. + /// The return type. + /// Types of parameters. + template + class Func : public Object + { + protected: + Ptr> invoker; + public: + typedef R FunctionType(TArgs...); + typedef R ResultType; + + /// Create a null function reference. + Func() + { + } + + /// Copy a function reference. + /// The function reference to copy. + Func(const Func& function) + : invoker(function.invoker) + { + } + + /// Create a reference using a function pointer. + /// The function pointer. + Func(R(*function)(TArgs...)) + { + invoker = new internal_invokers::StaticInvoker(function); + } + + /// Create a reference using a method. + /// Type of the class that has the method. + /// The object that has the method. + /// The function pointer. + template + Func(C* sender, R(C::*function)(TArgs...)) + { + invoker = new internal_invokers::MemberInvoker(sender, function); + } + + /// Create a reference using a function object. + /// Type of the function object. + /// The function object. It could be a lambda expression. + template + Func(const C& function) + { + invoker = new internal_invokers::ObjectInvoker(function); + } + + /// Invoke the function. + /// Returns the function result. + /// Arguments to invoke the function. + R operator()(TArgs ...args)const + { + return invoker->Invoke(ForwardValue(args)...); + } + + Func& operator=(const Func& function) + { + invoker = function.invoker; + return *this; + } + + Func& operator=(const Func&& function) + { + invoker = MoveValue(function.invoker); + return *this; + } + + bool operator==(const Func& function)const + { + return invoker == function.invoker; + } + + bool operator!=(const Func& function)const + { + return invoker != function.invoker; + } + + /// Test is the reference a null reference. + /// Returns true if it is not a null reference. + operator bool()const + { + return invoker; + } + }; + + /*********************************************************************** + vl::function_lambda::LambdaRetriveType + ***********************************************************************/ + + namespace function_lambda + { + template + struct LambdaRetriveType + { + typedef vint Type; + typedef vint FunctionType; + typedef vint ResultType; + }; + + template + struct FunctionObjectRetriveType + { + typedef typename LambdaRetriveType::Type Type; + typedef typename LambdaRetriveType::FunctionType FunctionType; + typedef typename LambdaRetriveType::ResultType ResultType; + typedef typename LambdaRetriveType::ParameterTypes ParameterTypes; + }; + + template + struct LambdaRetriveType + { + typedef Func Type; + typedef R(FunctionType)(TArgs...); + typedef R ResultType; + }; + + template + struct LambdaRetriveType + { + typedef Func Type; + typedef R(FunctionType)(TArgs...); + typedef R ResultType; + }; + + template + struct FunctionObjectRetriveType + { + typedef Func Type; + typedef R(FunctionType)(TArgs...); + typedef R ResultType; + }; + + /// Create a function reference to a function object or a lambda expression, with all type information + /// automatically inferred. You can use the macro called "LAMBDA" to refer to this function. + /// Type of the function object or the lambda expression. + /// The function reference. + /// The function object or the lambda expression. + template + typename LambdaRetriveType::Type Lambda(T functionObject) + { + return functionObject; + } + + /// Create a function reference to a function pointer, with all type information + /// automatically inferred. You can use the macro called "FUNCTION" to refer to this function. + /// Type of the function pointer. + /// The function reference. + /// The function pointer. + template + typename FunctionObjectRetriveType::Type ConvertToFunction(T functionObject) + { + return functionObject; + } + + #define LAMBDA vl::function_lambda::Lambda + #define FUNCTION vl::function_lambda::ConvertToFunction + #define FUNCTION_TYPE(T) typename vl::function_lambda::FunctionObjectRetriveType::Type + #define FUNCTION_RESULT_TYPE(T) typename vl::function_lambda::FunctionObjectRetriveType::ResultType + } // namespace function_lambda + + /*********************************************************************** + vl::function_binding::Binding + ***********************************************************************/ + + namespace function_binding + { + template + struct Binding + { + }; + + template + struct CR + { + typedef const T& Type; + }; + + template + struct CR + { + typedef T& Type; + }; + + template + struct CR + { + typedef const T& Type; + }; + + template + struct CR + { + typedef const T& Type; + }; + + template + struct Binding + { + typedef R FunctionType(T0, TArgs...); + typedef R CurriedType(TArgs...); + typedef T0 FirstParameterType; + + class Binder : public Object + { + protected: + Func target; + T0 firstArgument; + public: + Binder(const Func& _target, T0 _firstArgument) + : target(_target), firstArgument(ForwardValue(_firstArgument)) + { + } + + R operator()(TArgs ...args)const + { + return target(firstArgument, args...); + } + }; + + class Currier : public Object + { + protected: + Func target; + public: + Currier(const Func& _target) + : target(_target) + { + } + + Func operator()(T0 firstArgument)const + { + return Binder(target, firstArgument); + } + }; + }; + } // namespace function_binding + + /// Currize a function. Currizing means to create a new function whose argument is the first argument + /// of the original function. Calling this function will return another function reference whose arguments is all + /// remain arguments of the original function. Calling the returned function will call the original function. + /// Type of the function. + /// The currized function. + /// The function pointer to currize. + template + Func::CurriedType>(typename function_binding::Binding::FirstParameterType)> + Curry(T* function) + { + return typename function_binding::Binding::Currier(function); + } + + /// Currize a function. Currizing means to create a new function whose argument is the first argument + /// of the original function. Calling this function will return another function reference whose arguments is all + /// remain arguments of the original function. Calling the returned function will call the original function. + /// Type of the function. + /// The currized function. + /// The function reference to currize. + template + Func::CurriedType>(typename function_binding::Binding::FirstParameterType)> + Curry(const Func& function) + { + return typename function_binding::Binding::Currier(function); + } + + /*********************************************************************** + vl::function_combining::Combining + ***********************************************************************/ + + namespace function_combining + { + template + class Combining + { + }; + + template + class Combining : public Object + { + protected: + Func function1; + Func function2; + Func converter; + public: + typedef R1 FirstFunctionType(TArgs...); + typedef R2 SecondFunctionType(TArgs...); + typedef R ConverterFunctionType(R1, R2); + typedef R FinalFunctionType(TArgs...); + + Combining(const Func& _function1, const Func& _function2, const Func& _converter) + : function1(_function1), function2(_function2), converter(_converter) + { + } + + R operator()(TArgs&& ...args)const + { + return converter(function1(ForwardValue(args)...), function2(ForwardValue(args)...)); + } + }; + } // namespace function_combining + + /// Combine two functions with a converter function. The two functions to combine should have the same argument types. + /// The converter function will use the return values of the two function to calculate the final value. + /// Type of the first function. + /// Type of the second function. + /// Type of the converter function. + /// A new function whose argument list are the same of the two functions to provide. Calling this function + /// will call function1, function2 and converter in order to calculate the final value. + /// The converter function. + /// The first function. + /// The second function. + template + Func::FinalFunctionType> + Combine(Func converter, Func function1, Func function2) + { + return function_combining::Combining(function1, function2, converter); + } + + /// Use the converter function to create a combiner, who will receive two function and use to create + /// a combined function. This function assumes the result types of the two provided function in the future are the same, + /// and the converter function will not change the result type. + /// Type of the two functions to combine. + /// The combiner. + /// The converter function. + template + Func(Func, Func)> Combiner(const Func::ResultType(typename Func::ResultType, typename Func::ResultType)>& converter) + { + typedef typename Func::ResultType R; + return Curry(Func, Func, Func)>(Combine)(converter); + } +} // namespace vl + +#endif // VCZH_FUNCTION + diff --git a/software/firmware/source/libraries/functional-vlpp/src/Pointer.h b/software/firmware/source/libraries/functional-vlpp/src/Pointer.h new file mode 100644 index 000000000..d035ec6f7 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/src/Pointer.h @@ -0,0 +1,650 @@ +/**************************************************************************************************************************** + Pointer.h + + This library provides function templates to better support C++ functional programming across platforms. + Based on Vlpp library (https://github.com/vczh-libraries/Vlpp) + and Marcus Rugger functional-vlpp library (https://github.com/marcusrugger/functional-vlpp) + Built by Khoi Hoang (https://github.com/khoih-prog/functional-vlpp) + Licensed under MIT license + + Original author + Vczh Library++ 3.0 + Developer: Zihan Chen(vczh) + Framework::Basic + + Classes: + Ptr :Smart pointer + + Version: 1.0.2 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2019 Initial coding, testing and supporting AVR architecture + 1.0.1 K Hoang 01/03/2020 Add support for STM32 and all other architectures. + 1.0.2 K Hoang 21/02/2021 Clear compiler warnings + *****************************************************************************************************************************/ + +#pragma once + +#ifndef VCZH_POINTER +#define VCZH_POINTER + +#include "Basic.h" + +namespace vl +{ + + /*********************************************************************** + ReferenceCounterOperator + ***********************************************************************/ + + /// The strategy to get the pointer to the reference counter from an object. If you get the same pointer multiple times + /// from the same object by calling [M:vl.ReferenceCounterOperator`2.CreateCounter], than it is safe to convert a object pointer + /// to a [T:vl.Ptr`1]. Currently for reflectable C++ types which inherit from [T:vl.reflection.DescriptableObject] it is yet. + /// For others it is no. + /// The type of the object. + /// [T:vl.Ptr`1] will always use [T:vl.YesType] as the second type parameter. This parameter is useful + /// when you want to do partial specialization in the SFINAE way. + template + struct ReferenceCounterOperator + { + /// Create a pointer to the reference counter from an object. + /// The pointer to the reference counter. + /// The object. + static __forceinline volatile vint* CreateCounter(T* reference) + { + (void) reference; + return new vint(0); + } + + /// Destroy a pointer to the reference counter from an object. + /// The pointer to the reference counter. + /// The object. + static __forceinline void DeleteReference(volatile vint* counter, void* reference) + { + delete counter; + delete (T*)reference; + } + }; + + /*********************************************************************** + Smart Ptr Class + ***********************************************************************/ + + /// A smart pointer. It is always safe to convert a pointer to an object to a smart pointer once. If you do it multiple times, + /// it may be wrong due to different implementation of [T:vl.ReferenceCounterOperator`2]. In case of wrong, disposing the smart pointer + /// will cause an access violation. + /// The type of the object. + template + class Ptr + { + template + friend class Ptr; + + protected: + typedef void (*Destructor)(volatile vint*, void*); + + volatile vint* counter; + T* reference; + void* originalReference; + Destructor originalDestructor; + + void Inc() + { + if (counter) + { + INCRC(counter); + } + } + + void Dec() + { + if (counter) + { + if (DECRC(counter) == 0) + { + originalDestructor(counter, originalReference); + counter = 0; + reference = 0; + originalReference = 0; + originalDestructor = 0; + } + } + } + + volatile vint* Counter()const + { + return counter; + } + + Ptr(volatile vint* _counter, T* _reference, void* _originalReference, Destructor _originalDestructor) + : counter(_counter) + , reference(_reference) + , originalReference(_originalReference) + , originalDestructor(_originalDestructor) + { + Inc(); + } + + public: + + /// Create a null pointer. + Ptr() + : counter(0) + , reference(0) + , originalReference(0) + , originalDestructor(0) + { + } + + /// Convert a pointer to an object to a smart pointer. + /// The pointer to the object. + Ptr(T* pointer) + : counter(0) + , reference(0) + , originalReference(0) + , originalDestructor(0) + { + if (pointer) + { + counter = ReferenceCounterOperator::CreateCounter(pointer); + reference = pointer; + originalReference = pointer; + originalDestructor = &ReferenceCounterOperator::DeleteReference; + Inc(); + } + } + + /// Copy a smart pointer. + /// The smart pointer to copy. + Ptr(const Ptr& pointer) + : counter(pointer.counter) + , reference(pointer.reference) + , originalReference(pointer.originalReference) + , originalDestructor(pointer.originalDestructor) + { + Inc(); + } + + /// Move a smart pointer. + /// The smart pointer to Move. + Ptr(Ptr&& pointer) + : counter(pointer.counter) + , reference(pointer.reference) + , originalReference(pointer.originalReference) + , originalDestructor(pointer.originalDestructor) + { + pointer.counter = 0; + pointer.reference = 0; + pointer.originalReference = 0; + pointer.originalDestructor = 0; + } + + /// Cast a smart pointer. + /// The type of the object before casting. + /// The smart pointer to cast. + template + Ptr(const Ptr& pointer) + : counter(0) + , reference(0) + , originalReference(0) + , originalDestructor(0) + { + T* converted = pointer.Obj(); + if (converted) + { + counter = pointer.Counter(); + reference = converted; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; + Inc(); + } + } + + ~Ptr() + { + Dec(); + } + + /// Cast a smart pointer. + /// The type of the object after casting. + /// The casted smart pointer. Returns null if failed. + template + Ptr Cast()const + { + C* converted = dynamic_cast(reference); + return Ptr((converted ? counter : 0), converted, originalReference, originalDestructor); + } + + /// Convert a pointer to an object to a smart pointer. + /// The converted smart pointer. + /// The pointer to the object. + Ptr& operator=(T* pointer) + { + Dec(); + + if (pointer) + { + counter = ReferenceCounterOperator::CreateCounter(pointer); + reference = pointer; + originalReference = pointer; + originalDestructor = &ReferenceCounterOperator::DeleteReference; + Inc(); + } + else + { + counter = 0; + reference = 0; + originalReference = 0; + originalDestructor = 0; + } + + return *this; + } + + /// Copy a smart pointer. + /// The copied smart pointer. + /// The smart pointer to copy. + Ptr& operator=(const Ptr& pointer) + { + if (this != &pointer) + { + Dec(); + counter = pointer.counter; + reference = pointer.reference; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; + Inc(); + } + + return *this; + } + + /// Move a smart pointer. + /// The moved smart pointer. + /// The smart pointer to Move. + Ptr& operator=(Ptr&& pointer) + { + if (this != &pointer) + { + Dec(); + counter = pointer.counter; + reference = pointer.reference; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; + + pointer.counter = 0; + pointer.reference = 0; + pointer.originalReference = 0; + pointer.originalDestructor = 0; + } + + return *this; + } + + /// Cast a smart pointer. + /// The type of the object before casting. + /// The smart pointer after casting. + /// The smart pointer to cast. + template + Ptr& operator=(const Ptr& pointer) + { + T* converted = pointer.Obj(); + Dec(); + + if (converted) + { + counter = pointer.counter; + reference = converted; + originalReference = pointer.originalReference; + originalDestructor = pointer.originalDestructor; + Inc(); + } + else + { + counter = 0; + reference = 0; + originalReference = 0; + originalDestructor = 0; + } + + return *this; + } + + bool operator==(const T* pointer)const + { + return reference == pointer; + } + + bool operator!=(const T* pointer)const + { + return reference != pointer; + } + + bool operator>(const T* pointer)const + { + return reference > pointer; + } + + bool operator>=(const T* pointer)const + { + return reference >= pointer; + } + + bool operator<(const T* pointer)const + { + return reference < pointer; + } + + bool operator<=(const T* pointer)const + { + return reference <= pointer; + } + + bool operator==(const Ptr& pointer)const + { + return reference == pointer.reference; + } + + bool operator!=(const Ptr& pointer)const + { + return reference != pointer.reference; + } + + bool operator>(const Ptr& pointer)const + { + return reference > pointer.reference; + } + + bool operator>=(const Ptr& pointer)const + { + return reference >= pointer.reference; + } + + bool operator<(const Ptr& pointer)const + { + return reference < pointer.reference; + } + + bool operator<=(const Ptr& pointer)const + { + return reference <= pointer.reference; + } + + /// Test if it is a null pointer. + /// Returns true if it is not null. + operator bool()const + { + return reference != 0; + } + + /// Get the pointer to the object. + /// The pointer to the object. + T* Obj()const + { + return reference; + } + + /// Get the pointer to the object. + /// The pointer to the object. + T* operator->()const + { + return reference; + } + }; + + /*********************************************************************** + ComPtr + ***********************************************************************/ + + template + class ComPtr + { + protected: + volatile vint* counter; + T* reference; + + void Inc() + { + if (counter) + { + INCRC(counter); + } + } + + void Dec() + { + if (counter) + { + if (DECRC(counter) == 0) + { + delete counter; + reference->Release(); + counter = 0; + reference = 0; + } + } + } + + volatile vint* Counter()const + { + return counter; + } + + ComPtr(volatile vint* _counter, T* _reference) + : counter(_counter) + , reference(_reference) + { + Inc(); + } + + public: + + ComPtr() + { + counter = 0; + reference = 0; + } + + ComPtr(T* pointer) + { + if (pointer) + { + counter = new volatile vint(1); + reference = pointer; + } + else + { + counter = 0; + reference = 0; + } + } + + ComPtr(const ComPtr& pointer) + { + counter = pointer.counter; + reference = pointer.reference; + Inc(); + } + + ComPtr(ComPtr&& pointer) + { + counter = pointer.counter; + reference = pointer.reference; + + pointer.counter = 0; + pointer.reference = 0; + } + + ~ComPtr() + { + Dec(); + } + + ComPtr& operator=(T* pointer) + { + Dec(); + + if (pointer) + { + counter = new vint(1); + reference = pointer; + } + else + { + counter = 0; + reference = 0; + } + return *this; + } + + ComPtr& operator=(const ComPtr& pointer) + { + if (this != &pointer) + { + Dec(); + counter = pointer.counter; + reference = pointer.reference; + Inc(); + } + + return *this; + } + + ComPtr& operator=(ComPtr&& pointer) + { + if (this != &pointer) + { + Dec(); + counter = pointer.counter; + reference = pointer.reference; + + pointer.counter = 0; + pointer.reference = 0; + } + + return *this; + } + + bool operator==(const T* pointer)const + { + return reference == pointer; + } + + bool operator!=(const T* pointer)const + { + return reference != pointer; + } + + bool operator>(const T* pointer)const + { + return reference > pointer; + } + + bool operator>=(const T* pointer)const + { + return reference >= pointer; + } + + bool operator<(const T* pointer)const + { + return reference < pointer; + } + + bool operator<=(const T* pointer)const + { + return reference <= pointer; + } + + bool operator==(const ComPtr& pointer)const + { + return reference == pointer.reference; + } + + bool operator!=(const ComPtr& pointer)const + { + return reference != pointer.reference; + } + + bool operator>(const ComPtr& pointer)const + { + return reference > pointer.reference; + } + + bool operator>=(const ComPtr& pointer)const + { + return reference >= pointer.reference; + } + + bool operator<(const ComPtr& pointer)const + { + return reference < pointer.reference; + } + + bool operator<=(const ComPtr& pointer)const + { + return reference <= pointer.reference; + } + + operator bool()const + { + return reference != 0; + } + + T* Obj()const + { + return reference; + } + + T* operator->()const + { + return reference; + } + }; + + template + Ptr MakePtr(TArgs ...args) + { + return new T(args...); + } + + /*********************************************************************** + Traits + ***********************************************************************/ + + template + struct KeyType> + { + typedef T* Type; + + static T* GetKeyValue(const Ptr& key) + { + return key.Obj(); + } + }; + + template + struct POD> + { + static const bool Result = false; + }; + + template + struct KeyType> + { + typedef T* Type; + + static T* GetKeyValue(const ComPtr& key) + { + return key.Obj(); + } + }; + + template + struct POD> + { + static const bool Result = false; + }; +} // namespace vl + +#endif // VCZH_POINTER diff --git a/software/firmware/source/libraries/functional-vlpp/src/functional-vlpp.h b/software/firmware/source/libraries/functional-vlpp/src/functional-vlpp.h new file mode 100644 index 000000000..b34832df9 --- /dev/null +++ b/software/firmware/source/libraries/functional-vlpp/src/functional-vlpp.h @@ -0,0 +1,35 @@ +/**************************************************************************************************************************** + functional-vlpp.h + + Interface for Classes + + This library provides function templates to better support C++ functional programming across platforms. + Based on Vlpp library (https://github.com/vczh-libraries/Vlpp) + and Marcus Rugger functional-vlpp library (https://github.com/marcusrugger/functional-vlpp) + Built by Khoi Hoang (https://github.com/khoih-prog/functional-vlpp) + Licensed under MIT license + + Original author + Vczh Library++ 3.0 + Developer: Zihan Chen(vczh) + Framework::Basic + + Version: 1.0.2 + + Version Modified By Date Comments + ------- ----------- ---------- ----------- + 1.0.0 K Hoang 13/02/2019 Initial coding, testing and supporting AVR architecture + 1.0.1 K Hoang 01/03/2020 Add support for STM32 and all other architectures. + 1.0.2 K Hoang 21/02/2021 Clear compiler warnings + *****************************************************************************************************************************/ + +#pragma once + +#ifndef FUNCTIONAL_VLPP +#define FUNCTIONAL_VLPP + +#define FUNCTIONAL_VLPP_VERSION "Functional-Vlpp v1.0.2" + +#include "Function.h" + +#endif // FUNCTIONAL_VLPP